diff --git a/README.md b/README.md
index 06adff9b1fa11db47e60243fd8064ce985bc50e8..51718d404b18472e0dcc953ee8bb4abc30e17dd6 100644
--- a/README.md
+++ b/README.md
@@ -4,75 +4,87 @@ Pregmod is a modification of the original [Free Cities](https://freecitiesblog.b
 
 ## Play the game
 
-You can download compiled files and source archives from the [Releases page](https://gitgud.io/pregmodfan/fc-pregmod/-/releases), and the [build](https://gitgud.io/pregmodfan/fc-pregmod/-/jobs/artifacts/pregmod-master/download?job=build) from the latest commit to the master branch.
-
-Alternatively, you can build the game yourself:
-
-First, clone the git repository:
-
-1. [Install Git for terminal](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) or a Git GUI of your choice.
-2. Clone the repo
-    * Via terminal: `git clone --single-branch https://gitgud.io/pregmodfan/fc-pregmod.git`
-3. Get updates
-    * Via terminal: `git pull`
-
-Compile the game:
-
-* Windows
-    * Run compile.bat
-    * Second run of compile.bat will overwrite without prompt
-
-* Linux/Mac
-    1. Ensure executable permission on file `devTools/tweeGo/tweego` (not tweego.exe!)
-    2. Ensure executable permission on file `compile.sh`
-    3. In the root dir of sources (where you see src, devTools, bin...) run command `./compile.sh` from console.
-       Alternatively, if you have make installed, run `make all` in the root directory.
-
-To play open FC_pregmod.html in bin/ (Recommendation: Drag it into incognito mode)
+1. Download the game
+   * [Current release](https://gitgud.io/pregmodfan/fc-pregmod/-/releases)
+   * [Latest build](https://gitgud.io/pregmodfan/fc-pregmod/-/jobs/artifacts/pregmod-master/download?job=build)
+2. Open the game in your preferred browser
+   * On PC, we recommend either Firefox or [FCHost](FCHost/documentation_FCHost.md).
+   * Recommendation: Drag it into incognito mode
+3. Have fun!
+
+### Compile the game yourself
+
+If you want to tweak the game a bit, you can easily download the files and compile it yourself.
+
+1. Clone the git repository:
+   1. [Install Git for terminal](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) or a Git GUI of your
+      choice.
+   2. Clone the repo
+       * Via terminal: `git clone --single-branch https://gitgud.io/pregmodfan/fc-pregmod.git`
+   3. Get updates
+       * Via terminal: `git pull`
+
+2. Compile the game:
+   * Windows
+     * Run compile.bat
+     * Second run of compile.bat will overwrite without prompt
+
+   * Linux/Mac
+     1. Ensure executable permission on file `devTools/tweeGo/tweego` (not tweego.exe!)
+     2. Ensure executable permission on file `compile.sh`
+     3. In the root dir of sources (where you see src, devTools, bin...) run command `./compile.sh` from console.
+        Alternatively, if you have make installed, run `make all` in the root directory.
+
+3. To play open FC_pregmod.html in bin/
 
 ## Common problems
 
 * If compiling takes a while or causes a noticeable increase in system resource utilisation.
-	- It might be worth checking your main Antivirus (AV) settings.
-	- If it is Windows Defender (currently tested with Windows 10): Start menu -> Windows Security -> Virus & threat protection -> Virus & threat protection settings -> Manage settings -> Exclusions (near the bottom) -> Add or remove exclusions -> Add an exclusion -> path to bin/.
+  - It might be worth checking your main Antivirus (AV) settings.
+  - If it is Windows Defender (currently tested with Windows 10):
+    * `Start menu` -> `Windows Security` -> `Virus & threat protection` -> `Virus & threat protection settings` ->
+      `Manage settings` -> `Exclusions (near the bottom)` -> `Add or remove exclusions` -> `Add an exclusion` ->
+      `path to bin/.`
 
 * `sessionStorage quota exceeded` / `localStorage quota exceeded` or something similar
-    - Your saves stored inside the browser are getting too large. There are multiple ways to solve this:
-        1. Delete saves stored in the browser. If you want to keep them, save them to disk first.
-        2. Disable autosave and delete the current one. Due to technical reasons autosaves are larger than normal saves,
-           so this may help more than expected.
-        3. If on Firefox, raise the storage limit: Type `about:config` in the address bar and search for
-           `dom.storage.default_quota`. Increase this value as needed. Default value is 5120 kilobytes / 5 MB.
-        4. Switch to a different browser. Recommended is either Firefox or FCHost, a custom HTML renderer specifically
-           for Pregmod. Further reading can be found [here](FCHost/documentation_FCHost.md).
-        5. If you absolutely need to use Google Chrome:
-            1. download and unzip [NW.js SDK](https://nwjs.io/downloads/) for your operative system.
-            2. copy the game file (FC_pregmod.html) into the `nwjs-sdk-v0.XX.Y-YOUR_OS` folder
-            3. in the same folder, create a text file with the following content:
-               ```
-               {
-                   "name": "Free Cities pregmod edition",
-                   "main": "FC_pregmod.html",
-                   "dom_storage_quota":30
-               }
-               ```
-               and save it as package.json. In this example, 30 is the limit (in MB) that is set for the storage quota,
-               but you can replace it with any number. Google Chrome has the same default value as Firefox.
-            4. Double click nw.exe to launch the game.
+  - Your saves stored inside the browser are getting too large. There are multiple ways to solve this:
+    1. Delete saves stored in the browser. If you want to keep them, save them to disk first.
+    2. Disable autosave and delete the current one. Due to technical reasons autosaves are larger than normal saves,
+       so this may help more than expected.
+    3. If on Firefox, raise the storage limit: Type `about:config` in the address bar and search for
+       `dom.storage.default_quota`. Increase this value as needed. Default value is 5120 kilobytes / 5 MB.
+    4. Switch to a different browser. Recommended is either Firefox or [FCHost](FCHost/documentation_FCHost.md), a
+       custom HTML renderer specifically for Pregmod.
+    5. If you absolutely need to use Google Chrome:
+       1. download and unzip [NW.js SDK](https://nwjs.io/downloads/) for your operative system.
+       2. copy the game file (FC_pregmod.html) into the `nwjs-sdk-v0.XX.Y-YOUR_OS` folder
+       3. in the same folder, create a text file with the following content:
+          ```
+          {
+              "name": "Free Cities pregmod edition",
+              "main": "FC_pregmod.html",
+              "dom_storage_quota":30
+          }
+          ```
+          and save it as package.json. In this example, 30 is the limit (in MB) that is set for the storage quota,
+          but you can replace it with any number. Google Chrome has the same default value as Firefox.
+       4. Double click nw.exe to launch the game.
 
 * Everything is broken!
-    - **Do not copy over your existing download** as it may leave old files behind, replace it entirely
+  - **Do not copy over your existing download** as it may leave old files behind, replace it entirely
 
 * I can't save more than once or twice.
-    - Known issue caused by SugarCube level changes. Save to file doesn't have this problem and will likely avoid the first problem as well.
-    - It is possible to increase the memory utilized by your browser to delay this
+  - Known issue caused by SugarCube level changes. Save to file doesn't have this problem and will likely avoid the
+    first problem as well.
+  - It is possible to increase the memory utilized by your browser to delay this
 
 * I wish to report a sanityCheck issue.
-    - Great, however a large majority of the results are false positives. That said, if you found an actual error it could be a great first contribution if you are interested. 
+  - Open an issue or, if you are interested, it could be a great first contribution. Be warned though, a large number
+    are false positives. 
 
 ## Contribute
 
-New Contributors are always welcome. Basic information before you start can be found [here](CONTRIBUTING.md)
+New Contributors are always welcome. Basic information before you start can be found [here](CONTRIBUTING.md).
 
 ## Submodules
 
diff --git a/css/general/layout.css b/css/general/layout.css
index 959c99af5c2e14c4f6fe402cf9adc2429e4764f1..9e7d5b61d4625c3970cee06aefcefb6bc292e44a 100644
--- a/css/general/layout.css
+++ b/css/general/layout.css
@@ -39,15 +39,29 @@ div.double-indent, p.double-indent {
 
 div.grid-2columns-auto {
 	display: grid;
-	grid-template-columns: max-content auto;
+	grid-template-columns: auto auto;
 	grid-column-gap: 1em;
 }
+@media only screen and (min-width: 768px) {
+	div.grid-2columns-auto {
+		grid-template-columns: max-content auto;
+	}
+}
 
 div.grid-3columns-auto {
 	display: grid;
-	grid-template-columns: max-content auto auto;
+	grid-template-columns: auto auto auto;
 	grid-column-gap: 1em;
 }
+@media only screen and (min-width: 768px) {
+	div.grid-3columns-auto {
+		grid-template-columns: max-content max-content auto;
+	}
+}
+
+div.grid-all-columns {
+	grid-column: 1 / -1;
+}
 
 .border-bottom {
 	border-bottom: 1px solid;
diff --git a/css/gui/options.css b/css/gui/options.css
index eb58e8fc6d38b45f2364ceb702c241983c14ca2f..4599529a7dc9e28ed209b18277d7fff954b932eb 100644
--- a/css/gui/options.css
+++ b/css/gui/options.css
@@ -1,9 +1,15 @@
 div.options-group {
 	display: grid;
-	grid-template-columns: max-content auto;
+	grid-template-columns: auto auto;
 	align-items: center;
 }
 
+@media only screen and (min-width: 768px) {
+	div.options-group {
+		grid-template-columns: max-content auto;
+	}
+}
+
 /* left side */
 div.options-group div.description {
 	margin-right: 10px;
diff --git a/css/gui/tooltips/tippy.css b/css/gui/tooltips/tippy.css
index 0025e60e0503ff55ccc7f55dbe171352cc5ddb24..666b85948865439d0447b0270d0322879000a552 100644
--- a/css/gui/tooltips/tippy.css
+++ b/css/gui/tooltips/tippy.css
@@ -3,6 +3,14 @@
 	white-space: nowrap;
 }
 
+/* Fix links */
+a.has-tooltip {
+	text-decoration: none;
+}
+a.has-tooltip:hover {
+	text-decoration: underline;
+}
+
 .tippy-content {
 	text-indent: initial;
 	font-weight: initial;
diff --git a/css/interaction/prosthetics.css b/css/interaction/prosthetics.css
index 0b6a4b4b2dec88df4948f78efe87e67b5327fd0b..810787f6f5e77abead785bf4ec4dfa854ff181e9 100644
--- a/css/interaction/prosthetics.css
+++ b/css/interaction/prosthetics.css
@@ -1,11 +1,11 @@
 div.limb-selector {
 	display: grid;
-	grid-template-columns: 200px 100px 100px 100px 100px;
+	grid-template-columns: 200px 100px 100px 100px 100px 100px;
 }
 
 div.limb-selector div.full {
 	grid-column-start: 1;
-	grid-column-end: 6;
+	grid-column-end: 7;
 	text-align: center;
 }
 
diff --git a/devTools/types/FC/facilities.d.ts b/devTools/types/FC/facilities.d.ts
index 36c3bbd4d028d28fa1659b11fdff2175f13ed95b..0d3b8f87f52618dbd50148a081545a1f487634d9 100644
--- a/devTools/types/FC/facilities.d.ts
+++ b/devTools/types/FC/facilities.d.ts
@@ -182,40 +182,49 @@ declare namespace FC {
 			trainingIDs: number[];
 
 			// Pit section
-			/** The animal fighting a slave if not null. */
-			animal: string | "random";
+			/**
+			 * If there is a fight event at the end of the week.
+			 */
+			active: boolean
 			/** The type of audience the Pit has. */
 			audience: "none" | "free" | "paid";
-			/** Whether or not the bodyguard is fighting this week. */
-			bodyguardFights: boolean;
 			/** The type of decoration the Pit is using. */
 			decoration: FC.FutureSocietyDeco;
-			/**
-			 * Who is fighting this week.
-			 *
-			 * | Value | Description                |
-			 * |------:|:---------------------------|
-			 * | 0     | Two random slaves          |
-			 * | 1     | Random slave and bodyguard |
-			 * | 2     | Random slave and animal    |
-			 * | 3	   | True random				|
-			 * | 4 	   | Two specific slaves		|
-			 */
-			fighters: number;
 			/** An array of the IDs of slaves assigned to the Pit. */
 			fighterIDs: number[];
 			/** Whether or not a fight has taken place during the week. */
 			fought: boolean;
-			/** Whether or not the fights in the Pit are lethal. */
-			lethal: boolean;
-			/** The ID of the slave fighting the bodyguard for their life. */
-			slaveFightingBodyguard: number;
-			/** The ID of the slave fighting one of your beasts for their life. */
-			slaveFightingAnimal: number;
-			/** The IDs of the two slaves chosen to fight this week. */
-			slavesFighting: number[];
-			/** The virginities of the loser not allowed to be taken. */
-			virginities: "neither" | "vaginal" | "anal" | "all"
+			/**
+			 * Base for the max number of fights that can be held each week.
+			 * fightNum = 3 + 2 * fightsBase
+			 */
+			fightsBase: 0 | 1 | 2
+			/**
+			 * How many can watch the fight. Influences rep/cash generation
+			 */
+			seats: 0 | 1 | 2
+			/**
+			 * * 0: no lethal fights allowed
+			 * * 1: lethal and nonlethal fights allowed
+			 * * 2: only lethal fights allowed
+			 */
+			lethal: 0 | 1 | 2
+			/**
+			 * Which virginities will be respected
+			 */
+			virginities: "none" | "vaginal" | "anal" | "all"
+			/**
+			 * Whether slaves fighting must be in somewhat fair health and generally able to do combat.
+			 */
+			minimumHealth: boolean
+			/**
+			 * Schedule a slave to fight the BG
+			 */
+			slaveFightingBodyguard: number
+			/**
+			 * Schedule two slaves to fight each other
+			 */
+			slavesFighting: [number, number]
 		}
 	}
 }
diff --git a/devTools/types/FC/gameState.d.ts b/devTools/types/FC/gameState.d.ts
index 53338f89c27c7ec8801427a3840c66c5e78fc29c..0eeaaed949a2663c1947c0d71f58d33c43171f2a 100644
--- a/devTools/types/FC/gameState.d.ts
+++ b/devTools/types/FC/gameState.d.ts
@@ -151,6 +151,8 @@ declare namespace FC {
 
 		heroSlaves: SlaveTemplate[];
 		endweekFlag?: boolean;
+		limitedCheatStart?: Bool
+		lastCashTransaction?: number;
 	}
 
 	export interface GameVariables extends DefaultGameStateVariables, ResetOnNGPVariables,
diff --git a/devTools/types/FC/human.d.ts b/devTools/types/FC/human.d.ts
index ff2f5865c1fcb331578d36e8b1d6e3f8262f1af4..e82e2ae73bd401a9b31130f5413214751df6de2e 100644
--- a/devTools/types/FC/human.d.ts
+++ b/devTools/types/FC/human.d.ts
@@ -406,6 +406,8 @@ declare global {
 			 *
 			 * **macromastia + gigantomastia** - Breasts never stop growing. Increased growth rate, no shrink rate. */
 			gigantomastia: GeneticQuirk | 3;
+			/** sperm is much more likely to knock someone up */
+			potent: GeneticQuirk;
 			/** is prone to having twins, shorter pregnancy recovery rate */
 			fertility: GeneticQuirk;
 			/** is prone to having multiples, even shorter pregnancy recovery rate
@@ -442,6 +444,9 @@ declare global {
 			mGain: GeneticQuirk;
 			/** constantly loses muscle mass, easier to gain muscle. mGain + mLoss - muscle gain/loss amplified, passively lose muscle unless building */
 			mLoss: GeneticQuirk;
+			/** ova will split if room is available
+			 *  only affects fetuses */
+			twinning: GeneticQuirk;
 			/** slave can only ever birth girls */
 			girlsOnly: GeneticQuirk;
 			/** abnormal production of amniotic fluid
@@ -483,6 +488,8 @@ declare global {
 			fetish: Fetish;
 			spermY: number;
 			inbreedingCoeff?: number;
+			adultHeight: number;
+			artSeed: number;
 		}
 		//#endregion
 
diff --git a/js/002-config/fc-js-init.js b/js/002-config/fc-js-init.js
index bd683646b919f39d86776a6b1b84f46c2012c15a..f5bb39f1186c8e06fbc8a25c533b19ce7425af5f 100644
--- a/js/002-config/fc-js-init.js
+++ b/js/002-config/fc-js-init.js
@@ -52,6 +52,7 @@ App.Facilities.Incubator = {};
 App.Facilities.MasterSuite = {};
 App.Facilities.Nursery = {};
 App.Facilities.Pit = {};
+App.Facilities.Pit.Fights = {};
 App.Facilities.Schoolroom = {};
 App.Facilities.ServantsQuarters = {};
 App.Facilities.Spa = {};
diff --git a/js/003-data/clothes/001-slaveWearData.js b/js/003-data/clothes/001-slaveWearData.js
index fe1e9ad9e183d15161e2da69f4e96e4066581085..0b21ff16ac858e157820210da09083dc9a5f4b21 100644
--- a/js/003-data/clothes/001-slaveWearData.js
+++ b/js/003-data/clothes/001-slaveWearData.js
@@ -27,9 +27,9 @@
 /**
  * @typedef {object} clothes
  * @property {string} name
+ * @property {0|1|2|3|4} exposure 0: Modest, 1: Acceptable, 2: Slutty, 3: Humiliating (exposes genitals), 4: Might as well be nude
  * @property {itemFS} [fs]
  * @property {boolean} [requirements]
- * @property {0|1|2|3|4} [exposure] 0: Modest, 1: Acceptable, 2: Slutty, 3: Humiliating (exposes genitals), 4: Might as well be nude
  * @property {boolean} [harsh]
  * @property {boolean} [topless]
  * @property {boolean} [fuckdoll]
@@ -1173,13 +1173,22 @@ App.Data.slaveWear = {
 
 	dickAccessory: new Map([
 		["none", {name: "None"}],
-		["bullet vibrator", {name: "Bullet vibrator"}],
+		["bullet vibrator",
+			{
+				name: "Bullet vibrator",
+				get requirements() {
+					return V.boughtItem.toys.dildos === 1;
+				},
+				vibrates: 1,
+			}
+		],
 		["smart bullet vibrator",
 			{
 				name: "Smart bullet vibrator",
 				get requirements() {
 					return V.boughtItem.toys.smartVibes === 1;
-				}
+				},
+				vibrates: 2,
 			}
 		]
 	]),
diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js
index 7dbf4a069435711b0fac5f1fc397ca27b103df40..ec0043c213afa4fb70bf9eead2207456ac5c913b 100644
--- a/js/003-data/gameVariableData.js
+++ b/js/003-data/gameVariableData.js
@@ -1326,6 +1326,15 @@ App.Data.resetOnNGPlus = {
 		cost: 0, // How much you have to spend until she forgives you
 	},
 
+	/* Unethical Doctor */
+	pExoticSurgery: {
+		state: 0, // controls introduction and which halves you've met
+		fakePreg: 0, // is the female half teasing a male player?
+		cooldown: 0, // weeks until usable
+		visits: 0, // how many times you've given them money
+		clones: [], // you're starting to get boring, good thing I can fix that
+	},
+
 	diversePronouns: 0,
 
 	/* Weather effect on economy */
diff --git a/js/random.js b/js/random.js
index 8ab8e1d61ea85182398316e6f9927fec8840c5e2..10569f08e4029693bfd48c510c68be8d573cabc7 100644
--- a/js/random.js
+++ b/js/random.js
@@ -1,8 +1,8 @@
 /**
  * generate two independent Gaussian numbers using Box-Muller transform.
  * mean and deviation specify the desired mean and standard deviation.
- * @param {number} [mean]
- * @param {number} [deviation]
+ * @param {number} [mean=0]
+ * @param {number} [deviation=1]
  * @returns {number[]}
  */
 function gaussianPair(mean = 0, deviation = 1) {
@@ -47,10 +47,10 @@ App.Utils.Math.limitedSkewedGaussian = function(max, min, skew) {
  * Generate a random integer with a normal distribution between min and max (both inclusive).
  * Default parameters result in truncating the standard normal distribution between -3 and +3.
  * Not specifying min/max results in rerolling val approximately 0.3% of the time.
- * @param {number} [mean]
- * @param {number} [deviation]
- * @param {number} [min]
- * @param {number} [max]
+ * @param {number} [mean=0]
+ * @param {number} [deviation=1]
+ * @param {number} [min=mean-3*deviation]
+ * @param {number} [max=mean+3*deviation]
  * @returns {number}
  */
 function normalRandInt(mean = 0, deviation = 1, min = mean - 3 * deviation, max = mean + 3 * deviation) {
@@ -66,7 +66,7 @@ function normalRandInt(mean = 0, deviation = 1, min = mean - 3 * deviation, max
  * If count is defined, chooses that many random numbers between min and max and returns the average. This is an approximation of a normal distribution.
  * @param {number} min
  * @param {number} max
- * @param {number} [count]
+ * @param {number} [count=1]
  * @returns {number}
  */
 function jsRandom(min, max, count = 1) {
diff --git a/js/rulesAssistant/conditionEditorSimple.js b/js/rulesAssistant/conditionEditorSimple.js
index 64a557a95a6c1a5711122843a60841f5700dc6b5..fd73f571066193ae803acbd91107f39fc0b99f96 100644
--- a/js/rulesAssistant/conditionEditorSimple.js
+++ b/js/rulesAssistant/conditionEditorSimple.js
@@ -201,7 +201,7 @@ App.RA.Activation.SimpleEditor = (function() {
 		} else if (currentRule.activeRuleType === "custom") {
 			const options = new App.UI.OptionsGroup();
 			options.addOption("Mode", "customMode", currentRule)
-				.addValueList([["Boolean", "b"], ["Number", "n"], ["String", "s"]]).addCallbackToEach(refreshEditor);
+				.addValueList([["Boolean", "b"], ["Number", "n"], ["String", "s"]]).addGlobalCallback(refreshEditor);
 			outerDiv.append(options.render());
 			const textArea = document.createElement("textarea");
 			textArea.classList.add("condition-custom");
@@ -253,7 +253,7 @@ App.RA.Activation.SimpleEditor = (function() {
 	function deserializeRule(rule) {
 		// About the TS errors in this function: we can assume a lot about the rule composition because we know it's in
 		// the simple format. The rule itself is still a normal FC.RA.PostFixRule which would allow a lot more.
-		// Therefore, TS is not happy even though we now everything's fine.
+		// Therefore, TS is not happy even though we know everything's fine.
 		/**
 		 * @type {RuleState}
 		 */
diff --git a/js/rulesAssistant/conditionEditorTree.js b/js/rulesAssistant/conditionEditorTree.js
index 84862bc625ff722dcc2e007f94226540f7ac4558..73013e1d588e348639f5b73eace43668653159b9 100644
--- a/js/rulesAssistant/conditionEditorTree.js
+++ b/js/rulesAssistant/conditionEditorTree.js
@@ -73,7 +73,6 @@ App.RA.Activation.TreeEditor = (function() {
 		} else {
 			ruleDiv.append("Condition saved.");
 		}
-		ruleDiv.append(" ", App.Encyclopedia.link("Help", "RA Condition Editor"));
 		ruleDiv.append(currentRule.render());
 		outerDiv.append(ruleDiv);
 
diff --git a/js/rulesAssistant/z1-conditionEditorController.js b/js/rulesAssistant/z1-conditionEditorController.js
index a45aa13f4624221969686df21c0af27483cf14bb..275da0fce67044ea6ef1ba40ddfa7c9a0f276cf9 100644
--- a/js/rulesAssistant/z1-conditionEditorController.js
+++ b/js/rulesAssistant/z1-conditionEditorController.js
@@ -26,8 +26,10 @@ App.RA.Activation.Editor = (function() {
 	function fillOuterNode(args) {
 		advanced = args.advancedMode;
 		let editorNode = document.createElement("div");
+		let switchNode = document.createElement("div");
+		outerNode.append(switchNode);
 		if (advanced) {
-			outerNode.append(App.UI.DOM.link("Reset to simple mode", () => {
+			switchNode.append(App.UI.DOM.link("Reset to simple mode", () => {
 				if (SugarCube.Dialog.isOpen()) {
 					SugarCube.Dialog.close();
 				}
@@ -48,13 +50,14 @@ App.RA.Activation.Editor = (function() {
 			}));
 			App.RA.Activation.TreeEditor.build(args.activation, editorNode);
 		} else {
-			outerNode.append(App.UI.DOM.link("Switch to advanced mode", () => {
+			switchNode.append(App.UI.DOM.link("Switch to advanced mode", () => {
 				args.advancedMode = true;
 				$(outerNode).empty();
 				fillOuterNode(args);
 			}));
 			App.RA.Activation.SimpleEditor.build(args.activation, editorNode);
 		}
+		switchNode.append(" / ", App.Encyclopedia.link("Help", "RA Condition Editor"));
 		outerNode.append(editorNode);
 	}
 
diff --git a/src/002-config/fc-version.js b/src/002-config/fc-version.js
index 86917d4b34807cea99329f3261a336f25142af07..13d2f133c4e74f941a4893b1e9ad54253cdd245a 100644
--- a/src/002-config/fc-version.js
+++ b/src/002-config/fc-version.js
@@ -2,5 +2,5 @@ App.Version = {
 	base: "0.10.7.1", // The vanilla version the mod is based off of, this should never be changed.
 	pmod: "4.0.0-alpha.23",
 	commitHash: null,
-	release: 1187, // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js.
+	release: 1189, // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js.
 };
diff --git a/src/004-base/basePitFight.js b/src/004-base/basePitFight.js
new file mode 100644
index 0000000000000000000000000000000000000000..19a44d5ba2a8aa3be812900e7e7c0ca99a65561e
--- /dev/null
+++ b/src/004-base/basePitFight.js
@@ -0,0 +1,206 @@
+App.Facilities.Pit.Fights.BaseFight = class BaseFight {
+	/**
+	 * build a new fight
+	 */
+	constructor() {
+		/** @member {Array<number>} actors - a list of IDs for the actors participating in this fight. */
+		this.actors = [];
+		/** @member {object} params - a set of parameters to pass to the fight. */
+		this.params = {};
+	}
+
+	/** A unique key, so we can queue the fight.
+	 * @returns {string}
+	 */
+	get key() {
+		return "base fight";
+	}
+
+	/**
+	 * Whether slaves training at the arena are allowed in this fight. If yes, they will be preferred.
+	 * @returns {boolean}
+	 */
+	get allowTrainees() {
+		return false;
+	}
+
+	/**
+	 * At least one slave is expected to die.
+	 * @returns {boolean}
+	 */
+	get lethal() {
+		return false;
+	}
+
+	/**
+	 * How high the impact of this fight on the total event is. A flat multiplier. Used in descriptions.
+	 * 1 is a nonlethal 1-vs-1 fight. May not be negative
+	 * @returns {number}
+	 */
+	get impact() {
+		return 1;
+	}
+
+	/** Get a short description to show when selecting the fight during the event.
+	 * Assumes fight can be run and actors have been cast already
+	 * @returns {DocumentFragment}
+	 */
+	fightDescription() {
+		return new DocumentFragment();
+	}
+
+	/** Fight predicates determine whether the fight can be shown/executed
+	 * @callback pitFightPredicate
+	 * @returns {boolean}
+	 */
+	/** generate an array of zero or more predicates which must all return true in order for the fight to be valid.
+	 * lambda predicates may add properties to {@link App.Facilities.Pit.Fights.BaseFight#params the params member} in order to pass information on to the fight.
+	 * child classes should implement this.
+	 * @returns {Array<pitFightPredicate>}
+	 */
+	fightPrerequisites() {
+		return [
+			() =>
+				(V.pit.lethal === 0 && !this.lethal) ||
+				(V.pit.lethal === 1) ||
+				(V.pit.lethal === 2 && this.lethal)
+		];
+	}
+
+	/**
+	 * Actors that are forced to be a specific slave
+	 * @returns {Array<number>}
+	 */
+	forcedActors() {
+		return [];
+	}
+
+	/** generate an array of zero or more arrays, each corresponding to an actor in the fight, which contain zero or more predicates which must be satisfied by the actor.
+	 * child classes should implement this, unless they are overriding castActors.
+	 * @returns {Array<Array<actorPredicate>>}
+	 */
+	actorPrerequisites() {
+		return [];
+	}
+
+	/** run the fight and attach DOM output to the pit fight passage.
+	 * child classes must implement this.
+	 * @param {ParentNode} node - Document fragment which fight output should be attached to
+	 * @param {App.Facilities.Pit.Fights.FighterMap} fighterMap
+	 * @returns {number} - How successful the fight was for prestige/cash.
+	 *          The expected value should be between -1 and 1 inclusive. May go more extreme for unexpected outcomes.
+	 *          At least one maximum/minimum value should be used, and then scaled to other events with the
+	 *          {@link App.Facilities.Pit.Fights.BaseFight#impact impact property}.
+	 */
+	execute(node, fighterMap) {
+		return 0;
+	}
+
+	/** build the actual list of actors that will be involved in this fight.
+	 * default implementation should suffice for child classes with a fixed number of actors; may be overridden for fights with variable actor count.
+	 * @returns {boolean} - return false if sufficient qualified actors could not be found (cancel the fight)
+	 */
+	castActors() {
+		const prereqs = this.actorPrerequisites();
+
+		this.actors = [...this.forcedActors()];
+
+		for (let i = 0; i < prereqs.length; ++i) {
+			if (this.allowTrainees) {
+				if (this._selectActor(prereqs[i], ...App.Entity.facilities.pit.job("trainee").employeesIDs())) {
+					continue;
+				}
+			}
+			if (!this._selectActor(prereqs[i], ...App.Entity.facilities.pit.job("fighter").employeesIDs())) {
+				return false;
+			}
+		}
+
+		return true; // all actors cast
+	}
+
+	/**
+	 * @param {Array<actorPredicate>} prereqs
+	 * @param {...number} ids
+	 * @returns {boolean} False, if no actor could be selected
+	 * @private
+	 */
+	_selectActor(prereqs, ...ids) {
+		const qualified = ids
+			.filter(si => !this.actors.includes(si) && prereqs.every(p => p(getSlave(si))) && this._validActor(si));
+		if (qualified.length === 0) {
+			return false; // a required actor was not found
+		}
+		this.actors.push(qualified.pluck());
+		return true;
+	}
+
+	/**
+	 * @param {number} si - Slave ID
+	 * @returns {boolean} True, if the slave is allowed to fight
+	 * @private
+	 */
+	_validActor(si) {
+		if (!V.pit.minimumHealth) {
+			return true;
+		}
+		const slave = getSlave(si);
+		return canWalk(slave) && slave.health.condition >= -20;
+	}
+};
+
+/** This is a trivial fight for use as an example. */
+App.Facilities.Pit.Fights.TestFight = class extends App.Facilities.Pit.Fights.BaseFight {
+	get key() {
+		return "test";
+	}
+
+	actorPrerequisites() {
+		return [
+			[], // actor one, no requirements
+			[] // actor two, no requirements
+		];
+	}
+
+	execute(node) {
+		let [slave1, slave2] = this.actors.map(a => getSlave(a)); // mapped deconstruction of actors into local slave variables
+		node.appendChild(document.createTextNode(`This test fight for ${slave1.slaveName} and ${slave2.slaveName} was successful.`));
+		return 0;
+	}
+};
+
+App.Facilities.Pit.Fights.FighterMap = class {
+	constructor() {
+		/**
+		 * @type {Map<number, number>}
+		 */
+		this.map = new Map();
+	}
+
+	fightCount(slaveId) {
+		const count = this.map.get(slaveId);
+		if (count === undefined) {
+			return 0;
+		} else {
+			return count;
+		}
+	}
+
+	addFight(slaveId) {
+		const oldCount = this.fightCount(slaveId);
+		this.map.set(slaveId, oldCount + 1);
+	}
+
+	fighterCount() {
+		return this.map.size;
+	}
+
+	fightsCount() {
+		let count = 0;
+		this.map.forEach((v, k) => {
+			count += k;
+		});
+		return count;
+	}
+};
+
diff --git a/src/004-base/facilityFramework.js b/src/004-base/facilityFramework.js
index eef52a7dfbadcaac6b5a0496b8c455205110e59f..7d77a8d07f7a2ef54f2394c35432a9d20de7ab17 100644
--- a/src/004-base/facilityFramework.js
+++ b/src/004-base/facilityFramework.js
@@ -169,16 +169,21 @@ App.Facilities.Facility = class Facility {
 						// sum of n terms of an arithmetic series is computed as Sn = (n/2)(2a+(n-1)d), where a is the first term being considered and d is the common difference
 						const level = expand / 5;
 						const exCost = Math.trunc((level / 2) * (2 * cost + (level - 1) * 5 * baseCost));
-						options.push(
-							App.UI.DOM.link(`x${expand}`, () => { expandFacility(expand, exCost); }, [], '', `An additional ${num(expand)} slots will cost ${cashFormat(exCost)}.`)
-						);
+						const f = new DocumentFragment();
+						f.append(App.UI.DOM.link(`x${expand}`, () => {
+							expandFacility(expand, exCost);
+						}));
+						App.Events.addNode(f, [` (${cashFormatColor(exCost)})`]);
+						options.push(f);
 					}
 					link.append(App.UI.DOM.generateLinksStrip(options));
 
 					const linkArray = [];
 					App.UI.DOM.appendNewElement("div", div);
-					div.append(`Expanding ${this.facility.name} by ${num(5)} slots will cost ${cashFormat(Math.trunc(cost))}: `);
-					linkArray.push(App.UI.DOM.link(`x5`, () => { expandFacility(5, Math.trunc(cost)); }));
+					App.Events.addNode(div, [`Expanding ${this.facility.name} by ${num(5)} slots will cost ${cashFormatColor(Math.trunc(cost))}: `]);
+					linkArray.push(App.UI.DOM.link(`x5`, () => {
+						expandFacility(5, Math.trunc(cost));
+					}));
 					if (options.length > 0) {
 						linkArray.push(App.UI.DOM.linkReplace(`Additional options`, link));
 					}
@@ -255,7 +260,7 @@ App.Facilities.Facility = class Facility {
 							}
 
 							if ((rule.object && _.isEqual(rule.object[rule.property], o.value)) ||
-							_.isEqual(V[rule.property], o.value)) {
+								_.isEqual(V[rule.property], o.value)) {
 								App.UI.DOM.appendNewElement("div", div, o.text);
 							}
 						}
@@ -383,7 +388,7 @@ App.Facilities.Facility = class Facility {
 	 *
 	 * @returns {string}
 	 */
-	 get intro() {
+	get intro() {
 		return null;
 	}
 
@@ -392,7 +397,7 @@ App.Facilities.Facility = class Facility {
 	 *
 	 * @returns {string}
 	 */
-	 get decorations() {
+	get decorations() {
 		return null;
 	}
 
@@ -468,7 +473,7 @@ App.Facilities.Facility = class Facility {
 	 *
 	 * @returns {Array<HTMLDivElement|DocumentFragment>}
 	 */
-	 get customNodes() {
+	get customNodes() {
 		return [];
 	}
 };
diff --git a/src/005-passages/interactPassages.js b/src/005-passages/interactPassages.js
index 3861c266e58c02a64ffc9a6671ba57d6677f94b3..794728b07e33c50723fb34c5db909920b682f8cc 100644
--- a/src/005-passages/interactPassages.js
+++ b/src/005-passages/interactPassages.js
@@ -351,7 +351,7 @@ new App.DomPassage("Surrogacy Workaround",
 
 new App.DomPassage("Pit Workaround",
 	() => {
-		V.nextButton = V.pit.slavesFighting.length > 1 ? "Finish" : "Cancel";
+		V.nextButton = V.pit.slavesFighting === null || V.pit.slavesFighting.length !== 2 ? "Cancel" : "Finish";
 		V.nextLink = "Pit";
 		return App.Facilities.Pit.workaround();
 	}
diff --git a/src/Mods/Catmod/generateCatgirl.js b/src/Mods/Catmod/generateCatgirl.js
index 2bd8936d82b0b793efde344dbc5fec3d48a5d917..5724ff6500e8967a6ce6356437a18f54e3d0b9ce 100644
--- a/src/Mods/Catmod/generateCatgirl.js
+++ b/src/Mods/Catmod/generateCatgirl.js
@@ -41,9 +41,11 @@ globalThis.growCatgirl = function(sex, {
 	// they're genetically engineered and very expensive, so go ahead and make their genes conform a bit better to local expectations...
 	const arc = V.arcologies[0];
 	if (arc.FSStatuesqueGlorification !== "unset") {
-		slave.height = Math.min(slave.height + 10, 274);
+		slave.natural.height = Math.min(slave.natural.height + 10, 274);
+		slave.height = Height.forAge(slave.natural.height, slave);
 	} else if (arc.FSPetiteAdmiration !== "unset") {
-		slave.height = Math.max(slave.height - 10, 85);
+		slave.natural.height = Math.max(slave.natural.height - 10, 85);
+		slave.height = Height.forAge(slave.natural.height, slave);
 	}
 	if (arc.FSIntellectualDependency !== "unset") {
 		slave.intelligence = Math.max(slave.intelligence - 15, -100);
diff --git a/src/Mods/SecExp/js/securityReport.js b/src/Mods/SecExp/js/securityReport.js
index 4e4965936c5151e18916bebc87bc04d6129e1514..7d80e67f6acccf8f4116e6d5ce1704f60bf14aad 100644
--- a/src/Mods/SecExp/js/securityReport.js
+++ b/src/Mods/SecExp/js/securityReport.js
@@ -55,13 +55,13 @@ App.Mods.SecExp.securityReport = function(oldACitizens) {
 		r.push(`The extremely high number of residents makes their job a lot harder.`);
 		secGrowth -= 2;
 	}
-	if (V.SecExp.core.security == 3) {
+	if (V.SecExp.edicts.weaponsLaw == 3) {
 		r.push(`The completely free flow of weapons in your arcology makes security quite a bit more challenging.`);
 		secGrowth -= 1,5;
-	} else if (V.SecExp.core.security == 2) {
+	} else if (V.SecExp.edicts.weaponsLaw == 2) {
 		r.push(`The somewhat lax flow of weapons makes securing ${V.arcologies[0].name} moderately harder.`);
 		secGrowth -= 1;
-	} else if (V.SecExp.core.security == 1) {
+	} else if (V.SecExp.edicts.weaponsLaw == 1) {
 		r.push(`The restrictive nature of your weapon laws leaves few instances of violent crime that security has to deal with.`);
 		secGrowth = 0;
 	} else {
diff --git a/src/art/webgl/art.js b/src/art/webgl/art.js
index d1ca2f14c228623d830c03ab233c2f28a7bc0ca6..d3d801ba068f1c2592eca21eb7a5d5e401d72b27 100644
--- a/src/art/webgl/art.js
+++ b/src/art/webgl/art.js
@@ -9,6 +9,11 @@ App.Art.hexToRgb = function(hex) {
 
 App.Art.seed = 0;
 
+App.Art.setSeed = function(slave, offset) {
+	App.Art.seed = slave.natural.artSeed + offset;
+	return App.Art.seed;
+};
+
 App.Art.random = function() {
 	App.Art.seed += 1;
 	let x = Math.sin(App.Art.seed) * 10000;
@@ -82,7 +87,7 @@ App.Art.getArtParams = function(slave) {
 };
 
 App.Art.applyFigures = function(slave, scene, p) {
-	App.Art.seed = slave.ID;
+	App.Art.seed = App.Art.setSeed(slave, 0);
 	let figures = [];
 
 	switch (slave.clothes) {
@@ -1133,7 +1138,7 @@ App.Art.applyFigures = function(slave, scene, p) {
 };
 
 App.Art.applySurfaces = function(slave, scene, p) {
-	App.Art.seed = slave.ID + 1000;
+	App.Art.seed = App.Art.setSeed(slave, 1000);
 
 	let glansFutaliciousShellLayers = [];
 	let shaftFutaliciousShellLayers = [];
@@ -1294,28 +1299,30 @@ App.Art.applySurfaces = function(slave, scene, p) {
 	}
 
 	let pubicStyle = "";
-	switch (slave.pubicHStyle) {
-		case "hairless":
-		case "waxed":
-		case "bald":
-			break;
-		case "neat":
-			pubicStyle = "PubicNeat";
-			break;
-		case "in a strip":
-			pubicStyle = "PubicStrip";
-			break;
-		case "bushy":
-			pubicStyle = "PubicBushy";
-			break;
-		case "very bushy":
-			pubicStyle = "PubicVeryBushy";
-			break;
-		case "bushy in the front and neat in the rear":
-			pubicStyle = "PubicBushyFront";
-			break;
-		default:
-			break;
+	if (slave.physicalAge >= slave.pubertyAge) {
+		switch (slave.pubicHStyle) {
+			case "hairless":
+			case "waxed":
+			case "bald":
+				break;
+			case "neat":
+				pubicStyle = "PubicNeat";
+				break;
+			case "in a strip":
+				pubicStyle = "PubicStrip";
+				break;
+			case "bushy":
+				pubicStyle = "PubicBushy";
+				break;
+			case "very bushy":
+				pubicStyle = "PubicVeryBushy";
+				break;
+			case "bushy in the front and neat in the rear":
+				pubicStyle = "PubicBushyFront";
+				break;
+			default:
+				break;
+		}
 	}
 
 	if (pubicStyle !== "") {
@@ -1637,7 +1644,7 @@ App.Art.applySurfaces = function(slave, scene, p) {
 };
 
 App.Art.applyMaterials = function(slave, scene, p) {
-	App.Art.seed = slave.ID + 2000;
+	App.Art.seed = App.Art.setSeed(slave, 2000);
 
 	let materials = [];
 
@@ -2172,29 +2179,31 @@ App.Art.applyMaterials = function(slave, scene, p) {
 	materials.push(["TemplateGenitalia", "Ni", Ni]);
 	materials.push(["TemplateGenitalia", "map_Ka", "base/skin/" + skin + "Torso.jpg"]);
 
-	let pubicColor = App.Art.hexToRgb(extractColor(slave.pubicHColor));
-	switch (slave.pubicHStyle) {
-		case "hairless":
-		case "waxed":
-		case "bald":
-			break;
-		case "neat":
-			materials.push(["PubicNeat", "Ka", pubicColor]);
-			break;
-		case "in a strip":
-			materials.push(["PubicStrip", "Ka", pubicColor]);
-			break;
-		case "bushy":
-			materials.push(["PubicBushy", "Ka", pubicColor]);
-			break;
-		case "very bushy":
-			materials.push(["PubicVeryBushy", "Ka", pubicColor]);
-			break;
-		case "bushy in the front and neat in the rear":
-			materials.push(["PubicBushyFront", "Ka", pubicColor]);
-			break;
-		default:
-			break;
+	if (slave.physicalAge >= slave.pubertyAge) {
+		const pubicColor = App.Art.hexToRgb(extractColor(slave.pubicHColor));
+		switch (slave.pubicHStyle) {
+			case "hairless":
+			case "waxed":
+			case "bald":
+				break;
+			case "neat":
+				materials.push(["PubicNeat", "Ka", pubicColor]);
+				break;
+			case "in a strip":
+				materials.push(["PubicStrip", "Ka", pubicColor]);
+				break;
+			case "bushy":
+				materials.push(["PubicBushy", "Ka", pubicColor]);
+				break;
+			case "very bushy":
+				materials.push(["PubicVeryBushy", "Ka", pubicColor]);
+				break;
+			case "bushy in the front and neat in the rear":
+				materials.push(["PubicBushyFront", "Ka", pubicColor]);
+				break;
+			default:
+				break;
+		}
 	}
 
 	switch (slave.vaginaLube) {
@@ -2596,7 +2605,7 @@ App.Art.getAnimState = function(slave, scene, p, morphs, isAnimTick) {
 };
 
 App.Art.applyMorphs = function(slave, scene, p, isAnimating) {
-	App.Art.seed = slave.ID + 3000;
+	App.Art.seed = App.Art.setSeed(slave, 3000);
 
 	let morphs = [];
 
diff --git a/src/budget/loans.js b/src/budget/loans.js
index 855278661f8a2fb0ae63c7d6d694ead5b0f1d60d..8c0e1cf421432ec3c0eb411adeb05af29bdbfb89 100644
--- a/src/budget/loans.js
+++ b/src/budget/loans.js
@@ -78,45 +78,37 @@ App.Budget.loans = function() {
 		const values = [10000, 100000, 1000000];
 		const disabledReasons = [];
 		const links = [];
-		const text = [];
-
-		let allowed = true;
 
-		text.push(`You can take out a loan from one of the credit unions in the Free City, if you have the reputation for them to trust you.`);
+		div.append(`You can take out a loan from one of the credit unions in the Free City, if you have the reputation for them to trust you.`);
+		App.UI.DOM.appendNewElement("div", div,
+			`If for any reason you lack the credits, sectors of ${V.arcologies[0].name} will be used in lieu of payment.`,
+			["note", "indent"]);
 
 		if (V.rep < 10000) {
 			disabledReasons.push(`You need at least ${num(10000)} reputation to take a loan from this lender.`);
-			allowed = false;
 		}
 		if (loan('bank')) {
 			disabledReasons.push(`You have already taken out a loan from this lender.`);
-			allowed = false;
 		}
 
-		if (allowed) {
-			values.map(val => links.push(App.UI.DOM.link(cashFormat(val), () => {
-				const term = Math.max(val / 50000, 4);
-				const apr = Math.max(Math.abs((V.rep - 20000) / 500), 5);
-				const interest = val * (term / 52) * (apr / 100);
-				const full = val + interest;
-				V.loans.push({
-					name: 'bank',
-					principal: val,
-					deadline: V.week + term,
-					installments: term,
-					apr,
-					interest,
-					full,
-				});
-				cashX(val, "loan");
-
-				App.UI.reload();
-			}, [], '', terms('bank', val))));
+		if (disabledReasons.length === 0) {
+			for (const amount of values) {
+				const loan = createLoan("bank", amount);
+				const f = new DocumentFragment();
+				f.append(App.UI.DOM.link(cashFormat(amount), () => {
+					V.loans.push(loan);
+					cashX(amount, "loan");
+					App.UI.reload();
+				}));
+				const info = new DocumentFragment();
+				App.Events.addNode(info, [`${cashFormatColor(loan.full)} over ${num(loan.deadline - V.week)} weeks`]);
+				f.append(" – ", App.UI.DOM.spanWithTooltip(info, terms("bank", loan)));
+				links.push(f);
+			}
 		} else {
 			values.map(val => links.push(App.UI.DOM.disabledLink(cashFormat(val), disabledReasons)));
 		}
 
-		div.append(text.join(' '));
 		App.UI.DOM.appendNewElement("div", div, App.UI.DOM.generateLinksStrip(links), ['indent']);
 
 		return div;
@@ -127,67 +119,82 @@ App.Budget.loans = function() {
 		const values = [10000, 100000, 1000000];
 		const disabledReasons = [];
 		const links = [];
-		const text = [];
-
-		let allowed = true;
 
-		text.push(`If you're not quite reputable enough, you can also borrow money from one of the local loansharks in the area.`);
+		div.append(`If you're not quite reputable enough, you can also borrow money from one of the local loan-sharks in the area.`);
+		App.UI.DOM.appendNewElement("div", div,
+			`If for any reason you miss a payment the lender will send his men to collect – forcibly, if necessary.`,
+			["note", "indent"]);
 
 		if (V.rep < 2000) {
 			disabledReasons.push(`You need at least ${num(2000)} reputation to take a loan from this lender.`);
-			allowed = false;
 		}
 		if (loan('shark')) {
 			disabledReasons.push(`You have already taken out a loan from this lender.`);
-			allowed = false;
 		}
 
-		if (allowed) {
-			values.map(val => links.push(App.UI.DOM.link(cashFormat(val), () => {
-				const term = Math.max(val / 50000, 4);
-				const apr = Math.max(Math.abs((V.rep - 20000) / 500), 5);
-				const interest = (val * (term / 52) * (apr / 100)) * 3;
-				const full = val + interest;
-				V.loans.push({
-					name: 'shark',
-					principal: val,
-					deadline: V.week + (Math.max(val / 50000, 4)),
-					installments: 1,
-					apr,
-					interest,
-					full,
-				});
-				cashX(val, "loan");
-
-				App.UI.reload();
-			}, [], '', terms('shark', val))));
+		if (disabledReasons.length === 0) {
+			for (const amount of values) {
+				const loan = createLoan("shark", amount);
+				const f = new DocumentFragment();
+				f.append(App.UI.DOM.link(cashFormat(amount), () => {
+					V.loans.push(loan);
+					cashX(amount, "loan");
+
+					App.UI.reload();
+				}));
+				const info = new DocumentFragment();
+				App.Events.addNode(info, [`${cashFormatColor(loan.full)} after ${num(loan.deadline - V.week)} weeks`]);
+				f.append(" – ", App.UI.DOM.spanWithTooltip(info, terms("shark", loan)));
+				links.push(f);
+			}
 		} else {
 			values.map(val => links.push(App.UI.DOM.disabledLink(cashFormat(val), disabledReasons)));
 		}
 
-		div.append(text.join(' '));
 		App.UI.DOM.appendNewElement("div", div, App.UI.DOM.generateLinksStrip(links), ['indent']);
 
 		return div;
 	}
 
 	/**
-	 * @param {Lender} lender
+	 * @param {"bank"|"shark"}lender
 	 * @param {number} amount
+	 * @returns {FC.Loan}
 	 */
-	function terms(lender, amount) {
+	function createLoan(lender, amount) {
 		const term = Math.max(amount / 50000, 4);
 		const apr = Math.max(Math.abs((V.rep - 20000) / 500), 5);
-		const interest = amount * (term / 52) * (apr / 100);
+		let interest;
+		let installments;
+		if (lender === "shark") {
+			interest = (amount * (term / 52) * (apr / 100)) * 3;
+			installments = 1;
+		} else {
+			interest = amount * (term / 52) * (apr / 100);
+			installments = term;
+		}
 		const full = amount + interest;
-		const text = [];
 
+		return {
+			name: 'shark',
+			principal: amount,
+			deadline: V.week + term,
+			installments,
+			apr,
+			interest,
+			full: Math.trunc(full),
+		};
+	}
+
+	/**
+	 * @param {Lender} lender
+	 * @param {FC.Loan} loan
+	 */
+	function terms(lender, loan) {
 		if (lender === 'bank') {
-			text.push(`You will pay about ${cashFormat(Math.trunc(full / term))} per week for ${num(term)} weeks until you have paid off the entire balance. If for any reason you lack the credits, sectors of ${V.arcologies[0].name} will be used in lieu of payment. You will end up paying back about ${cashFormat(Math.trunc(full))} after interest.`);
+			return `You will pay about ${cashFormat(Math.trunc(loan.full / loan.deadline - V.week))} per week for ${num(loan.deadline - V.week)} weeks until you have paid off the entire balance. You will end up paying back about ${cashFormat(Math.trunc(loan.full))} after interest.`;
 		} else {
-			text.push(`You will have ${num(term)} weeks to pay off the full amount, after which the lender will send his men to collect – forcibly, if necessary. You will end up paying back about ${cashFormat(Math.trunc(amount + (interest * 3)))} after interest.`);
+			return `You will have ${num(loan.deadline - V.week)} weeks to pay off the full amount. You will end up paying back about ${cashFormat(Math.trunc(loan.full))} after interest.`;
 		}
-
-		return text.join(' ');
 	}
 };
diff --git a/src/data/backwardsCompatibility/backwardsCompatibility.js b/src/data/backwardsCompatibility/backwardsCompatibility.js
index 1ef521d24d94d73e2919081272e7956463705cee..d13e4f1c23e937404d43a3ba573c1022da730504 100644
--- a/src/data/backwardsCompatibility/backwardsCompatibility.js
+++ b/src/data/backwardsCompatibility/backwardsCompatibility.js
@@ -1563,6 +1563,16 @@ App.Update.slaveRecords = function(node) {
 				if (child.spermY === undefined) {
 					child.spermY = normalRandInt(50, 5);
 				}
+				if (!child.natural) {
+					child.natural = new App.Entity.GeneticState();
+					if (child.geneticQuirks.dwarfism === 2 && child.geneticQuirks.gigantism !== 2) {
+						child.natural.height = Height.randomAdult(child, {limitMult: [-4, -1], spread: 0.15});
+					} else if (child.geneticQuirks.gigantism === 2) {
+						child.natural.height = Height.randomAdult(child, {limitMult: [3, 10], spread: 0.15});
+					} else {
+						child.natural.height = Height.randomAdult(child);
+					}
+				}
 				App.Facilities.Nursery.InfantDatatypeCleanup(child);
 				child.inbreedingCoeff = ibc.coeff(child);
 			} else {
@@ -2408,8 +2418,6 @@ App.Update.oldVersions = function(node) {
 			}
 		}
 
-		WombInit(newPC);
-
 		V.PC = clone(newPC);
 
 		if (typeof V.PC.name === "undefined") {
@@ -2462,6 +2470,22 @@ App.Update.oldVersions = function(node) {
 			V.PC.skill.combat = 10;
 		}
 	}
+	if (!V.PC.natural) {
+		V.PC.natural = new App.Entity.GeneticState();
+		if (V.PC.physicalAge >= 20) {
+			V.PC.natural.height = V.PC.height - V.PC.heightImplant * 10;
+		} else {
+			// find and set a reasonable natural height for this immature player
+			if (V.PC.geneticQuirks.dwarfism === 2 && V.PC.geneticQuirks.gigantism !== 2) {
+				V.PC.natural.height = Height.randomAdult(V.PC, {limitMult: [-4, -1], spread: 0.15});
+			} else if (V.PC.geneticQuirks.gigantism === 2) {
+				V.PC.natural.height = Height.randomAdult(V.PC, {limitMult: [3, 10], spread: 0.15});
+			} else {
+				V.PC.natural.height = Height.randomAdult(V.PC);
+			}
+		}
+	}
+	WombInit(V.PC);
 
 	if (V.releaseID < 1185) {
 		if (V.nurseryNannies > 0) {
diff --git a/src/data/backwardsCompatibility/datatypeCleanup.js b/src/data/backwardsCompatibility/datatypeCleanup.js
index eb155928a0f0d97565feabf185eb828255034371..6c457b108f7164fc74e520e0aad5818af3171049 100644
--- a/src/data/backwardsCompatibility/datatypeCleanup.js
+++ b/src/data/backwardsCompatibility/datatypeCleanup.js
@@ -249,6 +249,10 @@ App.Entity.Utils.SlaveDataSchemeCleanup = (function() {
 				hairVector: "customHairVector"
 			});
 		}
+
+		if (!slave.custom.hasOwnProperty("name")) {
+			slave.custom.name = "";
+		}
 	}
 
 	/**
diff --git a/src/data/backwardsCompatibility/pitBC.js b/src/data/backwardsCompatibility/pitBC.js
index 877af4c22c58c2c02ba5e4ea194acf3dfc35b5b4..c6303e044a4b96987a78935695d36c7a2079e7c9 100644
--- a/src/data/backwardsCompatibility/pitBC.js
+++ b/src/data/backwardsCompatibility/pitBC.js
@@ -6,39 +6,63 @@ App.Facilities.Pit.BC = function() {
 	}
 
 	if (V.pit) {
-		V.pit.name = V.pit.name || V.pitName || "the Pit";
-		V.pit.virginities = V.pit.virginities || V.pitVirginities || "neither";
+		if (V.releaseID < 1186) {
+			V.pit.name = V.pit.name || V.pitName || "the Pit";
+			V.pit.virginities = V.pit.virginities || V.pitVirginities || "neither";
 
-		if (typeof V.pit.virginities !== "string") {
-			const virginities = ["neither", "vaginal", "anal", "all"];
+			if (typeof V.pit.virginities !== "string") {
+				const virginities = ["neither", "vaginal", "anal", "all"];
 
-			V.pit.virginities = virginities[V.pit.virginities];
-		}
+				V.pit.virginities = virginities[V.pit.virginities];
+			}
 
-		V.pit.bodyguardFights = V.pit.bodyguardFights || V.pitBG || false;
-		V.pit.fighterIDs = V.pit.fighterIDs || V.fighterIDs || [];
-		V.pit.fighters = V.pit.fighters || 0;
+			V.pit.bodyguardFights = V.pit.bodyguardFights || V.pitBG || false;
+			V.pit.fighterIDs = V.pit.fighterIDs || V.fighterIDs || [];
+			V.pit.fighters = V.pit.fighters || 0;
 
-		if (V.pit.bodyguardFights && V.pit.fighterIDs.includes(V.BodyguardID)) {
-			V.pit.fighterIDs.delete(V.BodyguardID);
-		}
+			if (V.pit.bodyguardFights && V.pit.fighterIDs.includes(V.BodyguardID)) {
+				V.pit.fighterIDs.delete(V.BodyguardID);
+			}
+
+			if (V.farmyard) {
+				V.pit.animal = V.pit.animal || V.pitAnimalType || null;
+			}
+
+			V.pit.trainingIDs = V.pit.trainingIDs || [];
+
+			V.pit.audience = V.pit.audience || V.pitAudience || "none";
+			V.pit.lethal = V.pit.lethal || V.pitLethal || false;
+			V.pit.fought = V.pit.fought || V.pitFought || false;
+
+			V.pit.slavesFighting = V.pit.slavesFighting || [];
+			V.pit.decoration = V.pit.decoration || "standard";
 
-		if (V.farmyard) {
-			V.pit.animal = V.pit.animal || V.pitAnimalType || null;
+			if (V.slaveFightingBG) {
+				V.pit.slaveFightingBodyguard = V.slaveFightingBG;
+			}
 		}
 
-		V.pit.trainingIDs = V.pit.trainingIDs || [];
+		V.pit.activeFights = V.pit.activeFights || [];
 
-		V.pit.audience = V.pit.audience || V.pitAudience || "none";
-		V.pit.lethal = V.pit.lethal || V.pitLethal || false;
-		V.pit.fought = V.pit.fought || V.pitFought || false;
+		V.pit.lethal = V.pit.lethal === true ? 1 : V.pit.lethal === false ? 0 : V.pit.lethal;
 
-		V.pit.slavesFighting = V.pit.slavesFighting || [];
-		V.pit.decoration = V.pit.decoration || "standard";
-	}
+		delete V.pit.animal;
+		delete V.pit.bodyguardFights;
+		delete V.pit.slaveFightingAnimal;
+
+		if (V.pit.virginities === "neither") {
+			V.pit.virginities = "none";
+		}
 
-	if (V.slaveFightingBG && V.pit) {
-		V.pit.slaveFightingBodyguard = V.slaveFightingBG;
+		V.pit.active = V.pit.active || false;
+		V.pit.fightsBase = V.pit.fightsBase || 0;
+		V.pit.seats = V.pit.seats || 0;
+		if (V.pit.minimumHealth !== true && V.pit.minimumHealth !== false) {
+			V.pit.minimumHealth = true;
+		}
+		if (V.pit.slavesFighting !== null && V.pit.slavesFighting.length !== 2) {
+			V.pit.slavesFighting = null;
+		}
 	}
 
 	if (V.pit && V.pit.trainingIDs) {
diff --git a/src/data/backwardsCompatibility/updateSlaveObject.js b/src/data/backwardsCompatibility/updateSlaveObject.js
index 23cfd18dde559a74cb2e38f67e768b5ae82c8b04..862d8e041712ea59dac07705fdf4f22ab720c037 100644
--- a/src/data/backwardsCompatibility/updateSlaveObject.js
+++ b/src/data/backwardsCompatibility/updateSlaveObject.js
@@ -1319,12 +1319,12 @@ App.Update.Slave = function(slave, genepool = false) {
 						}
 						break;
 					}
-					case "mother":
+					case "daughter":
 						// we know your mother. that's easy.
 						slave.mother = slave.relationTarget;
 						V.relationLinks[slave.ID] = {mother: slave.mother, father: 0};
 						break;
-					case "daughter":
+					case "mother":
 						// we know you are your daughter's mother. keep track of that in case she's forgotten somehow.
 						if (!V.relationLinks[slave.relationTarget]) {
 							V.relationLinks[slave.relationTarget] = {mother: slave.ID, father: 0};
@@ -1433,8 +1433,25 @@ App.Update.Slave = function(slave, genepool = false) {
 	}
 
 	if (V.releaseID < 1182) {
-		if (slave.skill.combat === 1) {
+		if (slave.skill?.combat === 1) {
 			slave.skill.combat = 70;
 		}
 	}
+
+	if (!slave.natural) {
+		slave.natural = new App.Entity.GeneticState();
+		slave.natural.artSeed = slave.ID; // used to use the ID as the seed; copy it on old slaves so they don't suddenly change appearance
+		if (slave.physicalAge >= 20) {
+			slave.natural.height = slave.height - slave.heightImplant * 10;
+		} else {
+			// find and set a reasonable natural height for this immature slave
+			if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2) {
+				slave.natural.height = Height.randomAdult(slave, {limitMult: [-4, -1], spread: 0.15});
+			} else if (slave.geneticQuirks.gigantism === 2) {
+				slave.natural.height = Height.randomAdult(slave, {limitMult: [3, 10], spread: 0.15});
+			} else {
+				slave.natural.height = Height.randomAdult(slave);
+			}
+		}
+	}
 };
diff --git a/src/endWeek/events/expire.js b/src/endWeek/events/expire.js
index cc8d0c61f5c53a08d97f3d0a8f1b1832179e9c94..e49b9b62f53b9b7ccae2ae0154da91cdc04fffeb 100644
--- a/src/endWeek/events/expire.js
+++ b/src/endWeek/events/expire.js
@@ -79,16 +79,13 @@ App.Events.SEExpiration = class SEExpiration extends App.Events.BaseEvent {
 				r.push(`${He} ${hasAnyLegs(slave) ? 'stands' : 'sits'} before you dumbly, betraying no reaction to the prospect of becoming free from sexual slavery. In situations like this, it is perfectly acceptable to subject ${him} to another indenture for ${his} own good.`);
 
 				if (V.cash > 1000) {
-					App.UI.DOM.appendNewElement("div", result, App.UI.DOM.link(
-						`Plead necessity and reactivate ${his} indenture`,
-						() => {
-							keepSlave(-1000);
-							jQuery(result).empty().append(`You plead necessity and place ${him} under another indenture, paying the trivial fees left over once ${he} has been charged for ${his} own forecasted upkeep. Naturally, ${he} offers no response at all to any of this.`);
-						},
-						[],
-						"",
-						`This costs ${cashFormat(1000)}`
-					));
+					const div = document.createElement("div");
+					div.append(App.UI.DOM.link(`Plead necessity and reactivate ${his} indenture`, () => {
+						keepSlave(-1000);
+						jQuery(result).empty().append(`You plead necessity and place ${him} under another indenture, paying the trivial fees left over once ${he} has been charged for ${his} own forecasted upkeep. Naturally, ${he} offers no response at all to any of this.`);
+					}));
+					App.UI.DOM.appendNewElement("span", div, ` This costs ${cashFormat(1000)}`, ["note"]);
+					result.append(div);
 				} else {
 					App.UI.DOM.appendNewElement("div", result, `You cannot afford to do this`, ["note"]);
 				}
@@ -109,33 +106,30 @@ App.Events.SEExpiration = class SEExpiration extends App.Events.BaseEvent {
 				}
 
 				if (V.cash > 1000) {
-					App.UI.DOM.appendNewElement("div", result, App.UI.DOM.link(
-						`Enslave ${him}`,
-						() => {
-							const el = new DocumentFragment();
-							const r = [];
-							r.push(`${He}'s beside ${himself} with joy when you accept ${his} plea and enslave ${him}. ${He}'s given you the finest proof of loyalty a slave possibly can, having tasted a moment of freedom under the law, and thrown it away with utter contempt.`);
-							if (hasAnyEyes(slave)) {
-								r.push(`${His} ${App.Desc.eyesColor(slave)}`);
-								if (canSee(slave)) {
-									r.push(`${hasBothEyes(slave) ? 'watch' : 'watches'} you with`);
-								} else {
-									r.push(`${hasBothEyes(slave) ? 'are' :'is'} wide with`);
-								}
+					const div = document.createElement("div");
+					div.append(App.UI.DOM.link(`Enslave ${him}`, () => {
+						const el = new DocumentFragment();
+						const r = [];
+						r.push(`${He}'s beside ${himself} with joy when you accept ${his} plea and enslave ${him}. ${He}'s given you the finest proof of loyalty a slave possibly can, having tasted a moment of freedom under the law, and thrown it away with utter contempt.`);
+						if (hasAnyEyes(slave)) {
+							r.push(`${His} ${App.Desc.eyesColor(slave)}`);
+							if (canSee(slave)) {
+								r.push(`${hasBothEyes(slave) ? 'watch' : 'watches'} you with`);
 							} else {
-								r.push(`${His} face shows`);
+								r.push(`${hasBothEyes(slave) ? 'are' : 'is'} wide with`);
 							}
-							r.push(`eager anticipation, radiating gladness that the prospect of separation from you has gone.`);
-							App.Events.addNode(el, r);
-							slave.indenture = -1;
-							slave.indentureRestrictions = 0;
-							keepSlave(-1000);
-							jQuery(result).empty().append(el);
-						},
-						[],
-						"",
-						`This costs ${cashFormat(1000)}`
-					));
+						} else {
+							r.push(`${His} face shows`);
+						}
+						r.push(`eager anticipation, radiating gladness that the prospect of separation from you has gone.`);
+						App.Events.addNode(el, r);
+						slave.indenture = -1;
+						slave.indentureRestrictions = 0;
+						keepSlave(-1000);
+						jQuery(result).empty().append(el);
+					}));
+					App.UI.DOM.appendNewElement("span", div, ` This costs ${cashFormat(1000)}`, ["note"]);
+					result.append(div);
 				} else {
 					App.UI.DOM.appendNewElement("div", result, `You cannot afford to do this`, ["note"]);
 				}
@@ -154,16 +148,13 @@ App.Events.SEExpiration = class SEExpiration extends App.Events.BaseEvent {
 				}
 
 				if (V.cash > cost) {
-					App.UI.DOM.appendNewElement("div", result, App.UI.DOM.link(
-						`Offer ${him} a one year supplementary indenture`,
-						() => {
-							keepSlave(cost);
-							jQuery(result).empty().append(`${He} smiles almost shyly when you offer ${him} a one year supplementary indenture. The price is reasonable, but definitely favorable to you. ${He} accepts it anyway, and you transfer the money into an escrow account to be held for ${him} until ${his} new indenture is done. Your sex slave once again, ${he} awaits your pleasure without a hint of fear.`);
-						},
-						[],
-						"",
-						`This costs ${cashFormat(cost)}`
-					));
+					const div = document.createElement("div");
+					div.append(App.UI.DOM.link(`Offer ${him} a one year supplementary indenture`, () => {
+						keepSlave(cost);
+						jQuery(result).empty().append(`${He} smiles almost shyly when you offer ${him} a one year supplementary indenture. The price is reasonable, but definitely favorable to you. ${He} accepts it anyway, and you transfer the money into an escrow account to be held for ${him} until ${his} new indenture is done. Your sex slave once again, ${he} awaits your pleasure without a hint of fear.`);
+					}));
+					App.UI.DOM.appendNewElement("span", div, ` This costs ${cashFormat(cost)}`, ["note"]);
+					result.append(div);
 				} else {
 					App.UI.DOM.appendNewElement("div", result, `You cannot afford to do this`, ["note"]);
 				}
@@ -172,16 +163,13 @@ App.Events.SEExpiration = class SEExpiration extends App.Events.BaseEvent {
 				r.push(`${!hasAnyLegs(slave) ? 'Propped up' : 'Standing before you'} at the moment of ${his} scheduled emancipation, ${he} seems willing to consider a short term continuation of service.`);
 
 				if (V.cash > cost) {
-					App.UI.DOM.appendNewElement("div", result, App.UI.DOM.link(
-						`Offer ${him} a one year supplementary indenture`,
-						() => {
-							keepSlave(cost);
-							jQuery(result).empty().append(`${He} looks pensive when you offer ${him} a one year supplementary indenture. The price reflects the market, and is a reasonable compensation for a year of sexual slavery. ${He} accepts it after some consideration, and you transfer the money into an escrow account to be held for ${him} until ${his} new indenture is done. Your sex slave once again, ${he} awaits orders with complacency.`);
-						},
-						[],
-						"",
-						`This costs ${cashFormat(cost)}`
-					));
+					const div = document.createElement("div");
+					div.append(App.UI.DOM.link(`Offer ${him} a one year supplementary indenture`, () => {
+						keepSlave(cost);
+						jQuery(result).empty().append(`${He} looks pensive when you offer ${him} a one year supplementary indenture. The price reflects the market, and is a reasonable compensation for a year of sexual slavery. ${He} accepts it after some consideration, and you transfer the money into an escrow account to be held for ${him} until ${his} new indenture is done. Your sex slave once again, ${he} awaits orders with complacency.`);
+					}));
+					App.UI.DOM.appendNewElement("span", div, ` This costs ${cashFormat(cost)}`, ["note"]);
+					result.append(div);
 				} else {
 					App.UI.DOM.appendNewElement("div", result, `You cannot afford to do this`, ["note"]);
 				}
diff --git a/src/endWeek/nextWeek/nextWeek.js b/src/endWeek/nextWeek/nextWeek.js
index f4d433d5478147dc3868e7261e0fe92a1724c891..7fee81272282a2bff1ebe5a4877e67cda1f66707 100644
--- a/src/endWeek/nextWeek/nextWeek.js
+++ b/src/endWeek/nextWeek/nextWeek.js
@@ -39,7 +39,7 @@ App.EndWeek.nextWeek = function() {
 					V.PC.visualAge++;
 					V.PC.ovaryAge += either(0.8, 0.9, 0.9, 1.0, 1.0, 1.0, 1.1);
 				}
-				if (V.PC.physicalAge <= 18 && V.loliGrow > 0) {
+				if (V.PC.physicalAge <= 20 && V.loliGrow > 0) {
 					App.EndWeek.Shared.physicalDevelopment(V.PC, true);
 				}
 				agePCEffects();
diff --git a/src/endWeek/player/prDrugs.js b/src/endWeek/player/prDrugs.js
index 7385a8de254f83be27803563bd2f424f539750e4..eb3188b48b8b8672994018e1b371b9ac2765f5f5 100644
--- a/src/endWeek/player/prDrugs.js
+++ b/src/endWeek/player/prDrugs.js
@@ -879,9 +879,9 @@ App.EndWeek.Player.drugs = function(PC = V.PC) {
 					// evaluate against expected height, with neoteny comparing against expected height for 12 year olds...
 					let heightDiff;
 					if (PC.geneticQuirks.neoteny === 2 && PC.physicalAge > 12) {
-						heightDiff = (PC.height - PC.heightImplant * 10) / Height.mean(PC.nationality, PC.race, PC.genes, 12);
+						heightDiff = (PC.height - PC.heightImplant * 10) / Height.forAge(PC.natural.height, 12, PC.genes);
 					} else {
-						heightDiff = (PC.height - PC.heightImplant * 10) / Height.mean(PC);
+						heightDiff = (PC.height - PC.heightImplant * 10) / Height.forAge(PC.natural.height, PC);
 					}
 					// if you are taller than the expected height the growth is reduced, if shorter accelerated proportionally to the distance from the expected height
 					heightDiff = 1 - heightDiff;
diff --git a/src/endWeek/player/prPregnancy.js b/src/endWeek/player/prPregnancy.js
index d64b59e3fccabaaeb7f1e69995c2805c263dbdf7..7e8ac6f35a90f60c627e2be970a17d7729b6f332 100644
--- a/src/endWeek/player/prPregnancy.js
+++ b/src/endWeek/player/prPregnancy.js
@@ -471,10 +471,10 @@ App.EndWeek.Player.pregnancy = function(PC = V.PC) {
 	function impregnation() {
 		if (PC.vagina === 0 || (PC.anus === 0 && PC.mpreg > 0)) {
 			// You aren't putting out.
-			if (isVirile(PC) && PC.geneMods.aggressiveSperm === 1 && canFemImpreg(PC, PC)) {
+			if (PC.geneMods.aggressiveSperm === 1) {
 				// But ejaculating with the sperm mod can result in splashback. More sex, more chances.
 				if (random(1, 100) > (99 - (PC.energy / 2))) {
-					knockMeUp(PC, 0, 2, -1); // 0% chance is correct. Gene mod adds 75% in knockMeUp().
+					tryKnockMeUp(PC, 0, 2, PC); // 0% chance is correct. Gene mod adds 75% in tryKnockMeUp().
 				}
 			}
 		} else if (random(1, 100) > (70 - (V.reproductionFormula * 10))) {
@@ -515,29 +515,29 @@ App.EndWeek.Player.pregnancy = function(PC = V.PC) {
 				return weight;
 			};
 
-			let dadHash;
+			let eligibleSlaves;
 			if (V.policies.sexualOpenness === 1) {
-				dadHash = V.slaves.filter(s => canImpreg(V.PC, s) && App.Utils.sexAllowed(V.PC, s) && isSlaveAvailable(s) && canAchieveErection(s) && s.devotion > 20 && raceIsAcceptable);
+				eligibleSlaves = V.slaves.filter(s => canImpreg(V.PC, s) && App.Utils.sexAllowed(V.PC, s) && isSlaveAvailable(s) && canAchieveErection(s) && s.devotion > 20 && raceIsAcceptable);
 			} else {
-				dadHash = V.slaves.filter(s => canImpreg(V.PC, s) && isSlaveAvailable(s) && s.toyHole === "dick");
+				eligibleSlaves = V.slaves.filter(s => canImpreg(V.PC, s) && isSlaveAvailable(s) && s.toyHole === "dick");
 			}
-			dadHash.reduce((acc, cur) => Object.assign(acc, {[cur.ID]: score(cur)}), {});
-			const chosenDadID = hashChoice(dadHash);
-			if (chosenDadID) {
-				knockMeUp(PC, 100, 2, chosenDadID);
+			const dadHash = eligibleSlaves.reduce((acc, cur, i) => Object.assign(acc, {[i]: score(cur)}), {});
+			const chosenDadIndex = hashChoice(dadHash);
+			if (chosenDadIndex) {
+				tryKnockMeUp(PC, 100, 2, eligibleSlaves[chosenDadIndex]);
 			}
 		}
 		if (canGetPregnant(PC) && !onBedRest(PC, true) && !isPCCareerInCategory("servant")) {
 			// Sperm mod leavings around the penthouse. Gives servants more of a point too.
-			let slobs = V.slaves.filter(s => canFemImpreg(PC, s) && isSlaveAvailable(s) && s.geneMods.aggressiveSperm === 1 && (s.fetish === "mindbroken" || s.energy > 95 || (s.devotion < -20 && s.trust > 20) || (s.intelligence + s.intelligenceImplant < -10)));
+			let slobs = V.slaves.filter(s => isSlaveAvailable(s) && s.geneMods.aggressiveSperm === 1 && (s.fetish === "mindbroken" || s.energy > 95 || (s.devotion < -20 && s.trust > 20) || (s.intelligence + s.intelligenceImplant < -10)));
 			if (slobs.length > (totalServantCapacity() / 5)) {
-				knockMeUp(PC, -50, 2, slobs.random());
+				tryKnockMeUp(PC, -50, 2, slobs.random());
 			}
 		}
 	}
 
 	function autoImpregnation() {
-		knockMeUp(PC, 100, 2, PC.ID);
+		tryKnockMeUp(PC, 100, 2, PC);
 		if (PC.geneticQuirks.superfetation === 2 && PC.pregKnown === 1) {
 			if (V.geneticMappingUpgrade === 0 && PC.counter.birthsTotal === 0) {
 				r.push(`You are wracked with frequent spontaneous orgasms from your asexual reproduction modifications despite already being pregnant.`);
diff --git a/src/endWeek/reports/incubatorReport.js b/src/endWeek/reports/incubatorReport.js
index ac5dc09d1fc551356cea0e6c5c5451797cc7f6b7..a3f138fee6a7cd656f86d76022ac9c5339471aaa 100644
--- a/src/endWeek/reports/incubatorReport.js
+++ b/src/endWeek/reports/incubatorReport.js
@@ -156,23 +156,23 @@ App.EndWeek.incubatorReport = function() {
 
 		r = [];
 		if (V.incubator.upgrade.growthStims === 1 && V.incubator.setting.growthStims !== 0) {
-			let heightLimit = Math.clamp((Height.mean(tank) * 1.25), 0, 274);
-			let heightLimitAge = Height.mean(tank);
+			let heightLimit = Math.clamp((Height.forAge(tank.natural.height, tank) * 1.25), 0, 274);
+			let heightLimitAge = Height.forAge(tank.natural.height, tank);
 			if (tank.geneticQuirks.dwarfism === 2 && tank.geneticQuirks.gigantism !== 2) {
-				heightLimit = Math.clamp((Height.mean(tank) * 0.95), 0, 160);
+				heightLimit = Math.clamp((Height.forAge(tank.natural.height, tank) * 0.95), 0, 160);
 			} else if (tank.geneticQuirks.gigantism === 2 && tank.geneticQuirks.dwarfism !== 2) {
-				heightLimit = Math.clamp((Height.mean(tank) * 1.75), 0, 274);
+				heightLimit = Math.clamp((Height.forAge(tank.natural.height, tank) * 1.75), 0, 274);
 			}
 			if (tank.geneMods.NCS === 1) {
 				/* NCS should block physical growth beyond that of a toddler, but some players might like
 				 * a little more or less. So using V.minimumSlaveAge or 8, whichever is lesser.	*/
 				const limitAge = Math.min(8, V.minimumSlaveAge);
-				/* Generate new average height for slave of age limitAge */
-				heightLimitAge = Height.mean(tank.nationality, tank.race, tank.genes, limitAge);
-				heightLimit = heightLimitAge; /* TODO: Add some variation, right now all NCS slaves will be the exact same height */
+				/* scale height to age 8 */
+				heightLimitAge = Height.forAge(tank.natural.height, limitAge);
+				heightLimit = heightLimitAge;
 			} else if (tank.geneticQuirks.neoteny === 2 && tank.physicalAge > 12) {
-				/* Generate new average height for slave of age 12 */
-				heightLimitAge = Height.mean(tank.nationality, tank.race, tank.genes, 12);
+				/* scale height to age 12 */
+				heightLimitAge = Height.forAge(tank.natural.height, 12);
 				heightLimit = Math.clamp((heightLimitAge * 1.25), 0, 274);
 			}
 			if (tank.height >= heightLimit) {
diff --git a/src/endWeek/reports/spaReport.js b/src/endWeek/reports/spaReport.js
index 804768e12af2eb22c834d054b5a6fed9c0b26a53..89d0ce00b63451843bf1c4d1b9152919d1c9813a 100644
--- a/src/endWeek/reports/spaReport.js
+++ b/src/endWeek/reports/spaReport.js
@@ -305,7 +305,7 @@ App.EndWeek.spaReport = function() {
 	if (S.Attendant) {
 		const slave = App.SlaveAssignment.reportSlave(S.Attendant);
 		tired(slave);
-		if (isFertile(slave) && slave.preg !== -1 && App.EndWeek.saVars.poolJizz > (canSee(S.Attendant) ? 5000 : 1000)) { // Free swimming sperm do not respect chastity and the Attendant can not avoid going in the pool.
+		if (isFertile(slave) && slave.preg !== -1 && App.EndWeek.saVars.poolJizz > (canSee(S.Attendant) ? 5000 : 1000)) { // Free swimming sperm do not respect chastity and the Attendant cannot avoid going in the pool.
 			const spermAtt = weightedRandom(App.EndWeek.saVars.poolJizzers);
 			if (canBreed(slave, getSlave(spermAtt.ID))) {
 				knockMeUp(slave, 25, 2, spermAtt.ID);
diff --git a/src/endWeek/saDrugs.js b/src/endWeek/saDrugs.js
index c03bba400e049622c79ae92511f68bb56005c652..13c74177ab9f3151ec12e3eedbd5d05e743ebe5c 100644
--- a/src/endWeek/saDrugs.js
+++ b/src/endWeek/saDrugs.js
@@ -930,9 +930,9 @@ App.SlaveAssignment.drugs = function saDrugs(slave) {
 					// evaluate against slave expected height, with neoteny slaves comparing against expected height for 12 year olds...
 					let heightDiff;
 					if (slave.geneticQuirks.neoteny === 2 && slave.physicalAge > 12) {
-						heightDiff = (slave.height - slave.heightImplant * 10) / Height.mean(slave.nationality, slave.race, slave.genes, 12);
+						heightDiff = (slave.height - slave.heightImplant * 10) / Height.forAge(slave.natural.height, 12, slave.genes);
 					} else {
-						heightDiff = (slave.height - slave.heightImplant * 10) / Height.mean(slave);
+						heightDiff = (slave.height - slave.heightImplant * 10) / Height.forAge(slave.natural.height, slave);
 					}
 					// if ${he} is taller than the expected height the growth is reduced, if shorter accelerated proportionally to the distance from the expected height
 					heightDiff = 1 - heightDiff;
diff --git a/src/endWeek/saPregnancy.js b/src/endWeek/saPregnancy.js
index 20a2c114ea03a67e04ef1b8dd7fef860973d5479..02e08dc3c95cd56643ef2f2f5bd83636706f5b93 100644
--- a/src/endWeek/saPregnancy.js
+++ b/src/endWeek/saPregnancy.js
@@ -1767,7 +1767,7 @@ App.SlaveAssignment.pregnancy = function saPregnancy(slave) {
 						// Sperm mod leavings around the penthouse. Gives servants more of a point too.
 						let slobs = V.slaves.filter(s => canFemImpreg(slave, s) && isSlaveAvailable(s) && s.geneMods.aggressiveSperm === 1 && (s.fetish === "mindbroken" || s.energy > 95 || (s.devotion < -20 && s.trust > 20) || (s.intelligence + s.intelligenceImplant < -10)));
 						if (slobs.length > (totalServantCapacity() / 5)) {
-							knockMeUp(slave, -50, 2, slobs.random());
+							tryKnockMeUp(slave, -50, 2, slobs.random());
 						}
 					}
 			} /* closes assignment checks */
diff --git a/src/endWeek/saSharedVariables.js b/src/endWeek/saSharedVariables.js
index 79c9462c8fac022ad9f7dd50355bbfcd99d3fe78..c982d402d25aa50cec20994927942fbb1a55d995 100644
--- a/src/endWeek/saSharedVariables.js
+++ b/src/endWeek/saSharedVariables.js
@@ -22,9 +22,9 @@ App.EndWeek.SASharedVariables = class {
 		this.whorePriceAdjustment = {};
 		/** How many slaves can the designated stud still impregnate? */
 		this.StudCum = 0;
-		/** Are slaves with the agressive sperm gene mod jacking off or having sex in the spa pool? */
+		/** Are slaves with the aggressive sperm gene mod jacking off or having sex in the spa pool? */
 		this.poolJizz = 0;
-		/** Which agressive sperm slaves are knocking up the spa bathers? */
+		/** Which aggressive sperm slaves are knocking up the spa bathers? */
 		this.poolJizzers = [];
 		/** How much energy does the player have left to fuck slaves who need it? */
 		this.freeSexualEnergy = 0;
diff --git a/src/endWeek/shared/physicalDevelopment.js b/src/endWeek/shared/physicalDevelopment.js
index 6b7e98562c4d8c389e9b934b090f55923bc91a94..3765d58dfe0aa2c4b1a09ef33d9f7d7a69b97db0 100644
--- a/src/endWeek/shared/physicalDevelopment.js
+++ b/src/endWeek/shared/physicalDevelopment.js
@@ -5,7 +5,6 @@ App.EndWeek.Shared.physicalDevelopment = function(actor, player = false) {
 	const rearQuirkDivider = rearQuirk === 0 ? 1 : rearQuirk;
 	const dickMod = (actor.geneticQuirks.wellHung === 2 ? 2 : 1);
 	let physicalAgeSwap;
-	const tallerPC = (player && actor.height >= Height.mean(actor) + 5 && actor.bodySwap === 0);
 
 	if (actor.geneticQuirks.progeria === 2) {
 		// since progeria increases .physicalAge, we need to work around it.
@@ -15,1557 +14,109 @@ App.EndWeek.Shared.physicalDevelopment = function(actor, player = false) {
 		physicalAgeSwap = actor.physicalAge;
 	}
 	if (actor.geneMods.NCS !== 1) {
-		/* NCS completely blocks all natural physical growth: no height increases. It also blocks all hormonal secondary sexual * characteristics. So, on the female side: no boobs, no butt, no hips, and no labia. And on the male side: no dick, no clit, no balls, no scrotum, no shoulders. */
+		/* NCS completely blocks all natural physical growth: no height increases. It also blocks all hormonal secondary sexual
+		 * characteristics. So, on the female side: no boobs, no butt, no hips, and no labia. And on the male side: no dick, no clit, no balls, no scrotum, no shoulders. */
 		/* so this is a big old NO-OP to skip the physical development. */
-		if (actor.geneticQuirks.androgyny === 2) { /* takes a mix of both to create a very androgynous slave */
-			if (actor.geneticQuirks.dwarfism === 2 && actor.geneticQuirks.gigantism !== 2) {
-				increaseHeightDwarf(actor);
-			} else if (actor.geneticQuirks.gigantism === 2) {
-				increaseHeightGiant(actor);
-			} else if (actor.geneticQuirks.neoteny === 2) {
-				increaseHeightNeoteny(actor);
-			} else {
-				increaseHeightXX(actor);
-			}
-			if (actor.geneticQuirks.neoteny !== 2) {
-				if (actor.boobs - actor.boobsImplant <= 300) {
-					increaseBoobsXX(actor);
-				}
-				if (actor.dick.isBetween(0, 3) || actor.geneticQuirks.wellHung === 2) {
-					increaseDick(actor);
-				}
-				if (actor.balls.isBetween(0, 3)) {
-					increaseBalls(actor);
-				}
-				if (actor.vagina > 0 && actor.ovaries > 0 && physicalAgeSwap > actor.pubertyAgeXX) {
-					increaseWetness(actor);
-				}
-				if (actor.waist < 10) {
-					increaseWaistXY(actor);
-				}
-				if (actor.hips - actor.hipsImplant < 0) {
-					increaseHipsXX(actor);
-				}
-				if (actor.butt - actor.buttImplant < 3) {
-					increaseButtXX(actor);
-				}
-			}
-			increasePregAdaptationXX(actor);
-		} else if (actor.genes === "XX") { /* loli becoming a woman */
-			if (actor.geneticQuirks.dwarfism === 2 && actor.geneticQuirks.gigantism !== 2) {
-				increaseHeightDwarf(actor);
-			} else if (actor.geneticQuirks.gigantism === 2) {
-				increaseHeightGiant(actor);
-			} else if (actor.geneticQuirks.neoteny === 2) {
-				increaseHeightNeoteny(actor);
-			} else {
-				increaseHeightXX(actor);
-			}
-			if (physicalAgeSwap === 13 || (physicalAgeSwap > 13 && (actor.hormoneBalance >= 100 || actor.hormoneBalance <= -100))) {
-				increaseFaceXX(actor);
-				if (actor.voice > 1) {
-					increaseVoiceXX(actor);
-				}
-			}
-			if (actor.geneticQuirks.neoteny !== 2) {
-				increaseBoobsXX(actor);
-				if (actor.clit > 0) {
-					increaseClit(actor);
-				}
-				if (actor.vagina > 0 && actor.ovaries > 0 && physicalAgeSwap > actor.pubertyAgeXX) {
-					increaseWetness(actor);
-				}
-				increaseWaistXX(actor);
-				increaseHipsXX(actor);
-				increaseButtXX(actor);
-			}
-			increasePregAdaptationXX(actor);
-		} else {
-			/* shota becoming a man */
-			if (actor.geneticQuirks.dwarfism === 2 && actor.geneticQuirks.gigantism !== 2) {
-				increaseHeightDwarf(actor);
-			} else if (actor.geneticQuirks.gigantism === 2) {
-				increaseHeightGiant(actor);
-			} else if (actor.geneticQuirks.neoteny === 2) {
-				increaseHeightNeoteny(actor);
-			} else {
-				increaseHeightXY(actor);
-			}
-			if (physicalAgeSwap === 13 || (physicalAgeSwap > 13 && (actor.hormoneBalance >= 100 || actor.hormoneBalance <= -100))) {
-				increaseFaceXY(actor);
-				if (actor.voice > 1) {
-					increaseVoiceXY(actor);
-				}
-			}
-			if (actor.geneticQuirks.neoteny !== 2) {
-				increaseBoobsXY(actor);
-				if (actor.dick > 0) {
-					increaseDick(actor);
-				}
-				if (actor.balls > 0) {
-					increaseBalls(actor);
-				}
-				increaseWaistXY(actor);
-				increaseHipsXY(actor);
-				increaseButtXY(actor);
-			}
-			increasePregAdaptationXY(actor);
-		}
-	}
-
-	/**
-	 * @param {FC.HumanState} actor
-	 */
-	function increaseHeightXX(actor) {
-		if (actor.hormoneBalance >= 200) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 91) {
-					actor.height += jsEither([8, 8, 9, 9]);
-				} else if (actor.height <= 101) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 101) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 109) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 109) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 116) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 116) {
-					actor.height += jsEither([5, 5, 6, 6]);
-				} else if (actor.height <= 124) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 124) {
-					actor.height += jsEither([7, 7, 8, 8]);
-				} else if (actor.height <= 131) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 131) {
-					actor.height += jsEither([5, 5, 6, 6]);
-				} else if (actor.height <= 137) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 137) {
-					actor.height += jsEither([4, 4, 5, 5]);
-				} else if (actor.height <= 144) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 144) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 156) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 156) {
-					actor.height += jsEither([5, 5, 6, 6]);
-				} else if (actor.height <= 163) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 163) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 168) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 168) {
-					actor.height += jsEither([5, 5, 6, 6]);
-				} else if (actor.height <= 171) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 171) {
-					actor.height += jsEither([4, 4, 5, 5]);
-				} else if (actor.height <= 173) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1]);
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1]);
-				}
-			}
-		} else if (actor.hormoneBalance >= 100) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 91) {
-					actor.height += jsEither([8, 8, 9, 9, 9]);
-				} else if (actor.height <= 101) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 101) {
-					actor.height += jsEither([6, 6, 7, 7, 7]);
-				} else if (actor.height <= 109) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 109) {
-					actor.height += jsEither([6, 6, 7, 7, 7]);
-				} else if (actor.height <= 116) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 116) {
-					actor.height += jsEither([5, 5, 6, 6, 6]);
-				} else if (actor.height <= 124) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 124) {
-					actor.height += jsEither([7, 7, 8, 8, 8]);
-				} else if (actor.height <= 131) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 131) {
-					actor.height += jsEither([5, 5, 6, 6, 6]);
-				} else if (actor.height <= 137) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 137) {
-					actor.height += jsEither([4, 4, 5, 5, 5]);
-				} else if (actor.height <= 144) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 144) {
-					actor.height += jsEither([6, 6, 7, 7, 7]);
-				} else if (actor.height <= 156) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 156) {
-					actor.height += jsEither([5, 5, 6, 6, 6]);
-				} else if (actor.height <= 163) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 163) {
-					actor.height += jsEither([6, 6, 7, 7, 7]);
-				} else if (actor.height <= 168) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 168) {
-					actor.height += jsEither([5, 5, 6, 6, 6]);
-				} else if (actor.height <= 171) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 171) {
-					actor.height += jsEither([4, 4, 5, 5, 5]);
-				} else if (actor.height <= 173) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1, 1]);
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1, 1]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1, 1]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1, 1]);
-				}
-			}
-		} else if (actor.hormoneBalance <= -200) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 91) {
-					actor.height += jsEither([9, 9, 9, 10, 10]);
-				} else if (actor.height <= 101) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 101) {
-					actor.height += jsEither([7, 7, 7, 8, 8]);
-				} else if (actor.height <= 109) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 109) {
-					actor.height += jsEither([7, 7, 7, 8, 8]);
-				} else if (actor.height <= 116) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 116) {
-					actor.height += jsEither([6, 6, 6, 7, 7]);
-				} else if (actor.height <= 124) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 124) {
-					actor.height += jsEither([8, 8, 8, 9, 9]);
-				} else if (actor.height <= 131) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 131) {
-					actor.height += jsEither([6, 6, 6, 7, 7]);
-				} else if (actor.height <= 137) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 137) {
-					actor.height += jsEither([5, 5, 5, 6, 6]);
-				} else if (actor.height <= 144) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 144) {
-					actor.height += jsEither([7, 7, 7, 8, 8]);
-				} else if (actor.height <= 156) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 156) {
-					actor.height += jsEither([6, 6, 6, 7, 7]);
-				} else if (actor.height <= 163) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 163) {
-					actor.height += jsEither([7, 7, 7, 8, 8]);
-				} else if (actor.height <= 168) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 168) {
-					actor.height += jsEither([6, 6, 6, 7, 7]);
-				} else if (actor.height <= 171) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 171) {
-					actor.height += jsEither([5, 5, 5, 6, 6]);
-				} else if (actor.height <= 173) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([1, 1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([1, 1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([1, 1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([1, 1, 1, 2, 2]);
-				}
-			}
-		} else if (actor.hormoneBalance <= -100) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 91) {
-					actor.height += jsEither([8, 9, 9, 10, 10]);
-				} else if (actor.height <= 101) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 101) {
-					actor.height += jsEither([6, 7, 7, 8, 8]);
-				} else if (actor.height <= 109) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 109) {
-					actor.height += jsEither([6, 7, 7, 8, 8]);
-				} else if (actor.height <= 116) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 116) {
-					actor.height += jsEither([5, 6, 6, 7, 7]);
-				} else if (actor.height <= 124) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 124) {
-					actor.height += jsEither([7, 8, 8, 9, 9]);
-				} else if (actor.height <= 131) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 131) {
-					actor.height += jsEither([5, 6, 6, 7, 7]);
-				} else if (actor.height <= 137) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 137) {
-					actor.height += jsEither([4, 5, 5, 6, 6]);
-				} else if (actor.height <= 144) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 144) {
-					actor.height += jsEither([6, 7, 7, 8, 8]);
-				} else if (actor.height <= 156) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 156) {
-					actor.height += jsEither([5, 6, 6, 7, 7]);
-				} else if (actor.height <= 163) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 163) {
-					actor.height += jsEither([6, 7, 7, 8, 8]);
-				} else if (actor.height <= 168) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 168) {
-					actor.height += jsEither([5, 6, 6, 7, 7]);
-				} else if (actor.height <= 171) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 171) {
-					actor.height += jsEither([4, 5, 5, 6, 6]);
-				} else if (actor.height <= 173) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 1, 1, 2, 2]);
-				}
-			}
+		if (actor.geneticQuirks.neoteny === 2) {
+			// special case for neoteny (genetic target height does not take it into account)
+			increaseHeightNeoteny(actor);
 		} else {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 91) {
-					actor.height += jsEither([8, 8, 9, 9, 9, 10]);
-				} else if (actor.height <= 101) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 101) {
-					actor.height += jsEither([6, 6, 7, 7, 8, 8]);
-				} else if (actor.height <= 109) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 109) {
-					actor.height += jsEither([6, 6, 7, 7, 7, 8]);
-				} else if (actor.height <= 116) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 116) {
-					actor.height += jsEither([5, 5, 6, 6, 6, 7]);
-				} else if (actor.height <= 124) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 124) {
-					actor.height += jsEither([7, 7, 8, 8, 8, 9]);
-				} else if (actor.height <= 131) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 131) {
-					actor.height += jsEither([5, 5, 6, 6, 6, 7]);
-				} else if (actor.height <= 137) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 137) {
-					actor.height += jsEither([4, 4, 5, 5, 5, 6]);
-				} else if (actor.height <= 144) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 144) {
-					actor.height += jsEither([6, 6, 7, 7, 7, 8]);
-				} else if (actor.height <= 156) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 156) {
-					actor.height += jsEither([5, 5, 6, 6, 6, 7]);
-				} else if (actor.height <= 163) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 163) {
-					actor.height += jsEither([6, 6, 7, 7, 7, 8]);
-				} else if (actor.height <= 168) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 168) {
-					actor.height += jsEither([5, 5, 6, 6, 6, 7]);
-				} else if (actor.height <= 171) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 171) {
-					actor.height += jsEither([4, 4, 5, 5, 5, 6]);
-				} else if (actor.height <= 173) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1, 1, 2]);
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1, 1, 2]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1, 1, 2]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 174) {
-					actor.height += jsEither([0, 0, 1, 1, 1, 2]);
-				}
-			}
+			// giant/dwarf/sex/race/etc is already taken into account by the target height. just need to take one step towards it.
+			increaseHeight(actor);
 		}
-		// experiment - Let's see if this keeps players on average above average height or if it makes them too tall in the long run.
-		if (tallerPC) {
-			actor.height += random(0, 3);
-		}
-	}
-
-	/**
-	 * @param {FC.HumanState} actor
-	 */
-	function increaseHeightXY(actor) {
-		if (actor.hormoneBalance >= 200) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 93) {
-					actor.height += jsEither([9, 9, 10, 10]);
-				} else if (actor.height <= 103) {
-					actor.height += 6;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 103) {
-					actor.height += jsEither([7, 7, 8, 8]);
-				} else if (actor.height <= 110) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 110) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 117) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 117) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 124) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 124) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 131) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 131) {
-					actor.height += jsEither([5, 5, 6, 6]);
-				} else if (actor.height <= 137) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 137) {
-					actor.height += jsEither([4, 4, 5, 5]);
-				} else if (actor.height <= 144) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 144) {
-					actor.height += jsEither([5, 5, 6, 6]);
-				} else if (actor.height <= 150) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 150) {
-					actor.height += jsEither([5, 5, 6, 6]);
-				} else if (actor.height <= 156) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 156) {
-					actor.height += jsEither([5, 5, 6, 6]);
-				} else if (actor.height <= 162) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 162) {
-					actor.height += jsEither([7, 7, 8, 8]);
-				} else if (actor.height <= 170) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 170) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 177) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 177) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 184) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 184) {
-					actor.height += jsEither([2, 2, 3, 3]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 185) {
-					actor.height += jsEither([1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 186) {
-					actor.height += jsEither([0, 0, 1, 1]);
-				}
-			}
-		} else if (actor.hormoneBalance >= 100) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 93) {
-					actor.height += jsEither([9, 9, 9, 10, 10]);
-				} else if (actor.height <= 103) {
-					actor.height += 6;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 103) {
-					actor.height += jsEither([7, 7, 8, 8, 8]);
-				} else if (actor.height <= 110) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 110) {
-					actor.height += jsEither([6, 6, 7, 7, 7]);
-				} else if (actor.height <= 117) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 117) {
-					actor.height += jsEither([6, 6, 7, 7, 7]);
-				} else if (actor.height <= 124) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 124) {
-					actor.height += jsEither([6, 6, 7, 7, 7]);
-				} else if (actor.height <= 131) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 131) {
-					actor.height += jsEither([5, 5, 6, 6, 6]);
-				} else if (actor.height <= 137) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 137) {
-					actor.height += jsEither([4, 4, 5, 5, 5]);
-				} else if (actor.height <= 144) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 144) {
-					actor.height += jsEither([5, 5, 6, 6, 6]);
-				} else if (actor.height <= 150) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 150) {
-					actor.height += jsEither([5, 5, 6, 6, 6]);
-				} else if (actor.height <= 156) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 156) {
-					actor.height += jsEither([5, 5, 6, 6, 6]);
-				} else if (actor.height <= 162) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 162) {
-					actor.height += jsEither([7, 7, 8, 8, 8]);
-				} else if (actor.height <= 170) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 170) {
-					actor.height += jsEither([6, 6, 7, 7, 7]);
-				} else if (actor.height <= 177) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 177) {
-					actor.height += jsEither([6, 6, 7, 7, 7]);
-				} else if (actor.height <= 184) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 184) {
-					actor.height += jsEither([2, 2, 3, 3, 3]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 185) {
-					actor.height += jsEither([1, 1, 2, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 186) {
-					actor.height += jsEither([0, 0, 1, 1, 1]);
-				}
-			}
-		} else if (actor.hormoneBalance <= -200) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 93) {
-					actor.height += jsEither([10, 10, 11, 11]);
-				} else if (actor.height <= 103) {
-					actor.height += 6;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 103) {
-					actor.height += jsEither([8, 8, 9, 9]);
-				} else if (actor.height <= 110) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 110) {
-					actor.height += jsEither([7, 7, 8, 8]);
-				} else if (actor.height <= 117) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 117) {
-					actor.height += jsEither([7, 7, 8, 8]);
-				} else if (actor.height <= 124) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 124) {
-					actor.height += jsEither([7, 7, 8, 8]);
-				} else if (actor.height <= 131) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 131) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 137) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 137) {
-					actor.height += jsEither([5, 5, 6, 6]);
-				} else if (actor.height <= 144) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 144) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 150) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 150) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 156) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 156) {
-					actor.height += jsEither([6, 6, 7, 7]);
-				} else if (actor.height <= 162) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 162) {
-					actor.height += jsEither([8, 8, 9, 9]);
-				} else if (actor.height <= 170) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 170) {
-					actor.height += jsEither([7, 7, 8, 8]);
-				} else if (actor.height <= 177) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 177) {
-					actor.height += jsEither([7, 7, 8, 8]);
-				} else if (actor.height <= 184) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 184) {
-					actor.height += jsEither([3, 3, 4, 4]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 185) {
-					actor.height += jsEither([2, 2, 3, 3]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 186) {
-					actor.height += jsEither([1, 1, 2, 2]);
-				}
-			}
-		} else if (actor.hormoneBalance <= -100) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 93) {
-					actor.height += jsEither([10, 10, 10, 11, 11]);
-				} else if (actor.height <= 103) {
-					actor.height += 6;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 103) {
-					actor.height += jsEither([8, 8, 8, 9, 9]);
-				} else if (actor.height <= 110) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 110) {
-					actor.height += jsEither([7, 7, 7, 8, 8]);
-				} else if (actor.height <= 117) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 117) {
-					actor.height += jsEither([7, 7, 7, 8, 8]);
-				} else if (actor.height <= 124) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 124) {
-					actor.height += jsEither([7, 7, 7, 8, 8]);
-				} else if (actor.height <= 131) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 131) {
-					actor.height += jsEither([6, 6, 6, 7, 7]);
-				} else if (actor.height <= 137) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 137) {
-					actor.height += jsEither([5, 5, 5, 6, 6]);
-				} else if (actor.height <= 144) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 144) {
-					actor.height += jsEither([6, 6, 6, 7, 7]);
-				} else if (actor.height <= 150) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 150) {
-					actor.height += jsEither([6, 6, 6, 7, 7]);
-				} else if (actor.height <= 156) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 156) {
-					actor.height += jsEither([6, 6, 6, 7, 7]);
-				} else if (actor.height <= 162) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 162) {
-					actor.height += jsEither([8, 8, 8, 9, 9]);
-				} else if (actor.height <= 170) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 170) {
-					actor.height += jsEither([7, 7, 7, 8, 8]);
-				} else if (actor.height <= 177) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 177) {
-					actor.height += jsEither([7, 7, 7, 8, 8]);
-				} else if (actor.height <= 184) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 184) {
-					actor.height += jsEither([3, 3, 3, 4, 4]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 185) {
-					actor.height += jsEither([2, 2, 2, 3, 3]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 186) {
-					actor.height += jsEither([1, 1, 1, 2, 2]);
-				}
-			}
-		} else {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 93) {
-					actor.height += jsEither([9, 9, 10, 10, 10, 11]);
-				} else if (actor.height <= 103) {
-					actor.height += 6;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 103) {
-					actor.height += jsEither([7, 7, 8, 8, 9, 9]);
-				} else if (actor.height <= 110) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 110) {
-					actor.height += jsEither([6, 6, 7, 7, 8, 8]);
-				} else if (actor.height <= 117) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 117) {
-					actor.height += jsEither([6, 6, 7, 7, 8, 8]);
-				} else if (actor.height <= 124) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 124) {
-					actor.height += jsEither([6, 6, 7, 7, 8, 8]);
-				} else if (actor.height <= 131) {
-					actor.height += 4;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 131) {
-					actor.height += jsEither([5, 5, 6, 6, 7, 7]);
-				} else if (actor.height <= 137) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 137) {
-					actor.height += jsEither([4, 4, 5, 5, 5, 6]);
-				} else if (actor.height <= 144) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 144) {
-					actor.height += jsEither([5, 5, 6, 6, 7, 7]);
-				} else if (actor.height <= 150) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 150) {
-					actor.height += jsEither([5, 5, 6, 6, 6, 7]);
-				} else if (actor.height <= 156) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 156) {
-					actor.height += jsEither([5, 5, 6, 6, 7, 7]);
-				} else if (actor.height <= 162) {
-					actor.height += 3;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 162) {
-					actor.height += jsEither([7, 7, 8, 8, 9, 9]);
-				} else if (actor.height <= 170) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 170) {
-					actor.height += jsEither([6, 6, 7, 7, 8, 8]);
-				} else if (actor.height <= 177) {
-					actor.height += 4;
+		// physical development EXCEPT for height stops at 18; height keeps going until 20.
+		if (physicalAgeSwap <= 18) {
+			if (actor.geneticQuirks.androgyny === 2) { /* takes a mix of both to create a very androgynous slave */
+				if (actor.geneticQuirks.neoteny !== 2) {
+					if (actor.boobs - actor.boobsImplant <= 300) {
+						increaseBoobsXX(actor);
+					}
+					if (actor.dick.isBetween(0, 3) || actor.geneticQuirks.wellHung === 2) {
+						increaseDick(actor);
+					}
+					if (actor.balls.isBetween(0, 3)) {
+						increaseBalls(actor);
+					}
+					if (actor.vagina > 0 && actor.ovaries > 0 && physicalAgeSwap > actor.pubertyAgeXX) {
+						increaseWetness(actor);
+					}
+					if (actor.waist < 10) {
+						increaseWaistXY(actor);
+					}
+					if (actor.hips - actor.hipsImplant < 0) {
+						increaseHipsXX(actor);
+					}
+					if (actor.butt - actor.buttImplant < 3) {
+						increaseButtXX(actor);
+					}
 				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 177) {
-					actor.height += jsEither([6, 6, 7, 7, 8, 8]);
-				} else if (actor.height <= 184) {
-					actor.height += 4;
+				increasePregAdaptationXX(actor);
+			} else if (actor.genes === "XX") { /* loli becoming a woman */
+				if (physicalAgeSwap === 13 || (physicalAgeSwap > 13 && (actor.hormoneBalance >= 100 || actor.hormoneBalance <= -100))) {
+					increaseFaceXX(actor);
+					if (actor.voice > 1) {
+						increaseVoiceXX(actor);
+					}
 				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 184) {
-					actor.height += jsEither([2, 2, 3, 3, 4, 4]);
+				if (actor.geneticQuirks.neoteny !== 2) {
+					increaseBoobsXX(actor);
+					if (actor.clit > 0) {
+						increaseClit(actor);
+					}
+					if (actor.vagina > 0 && actor.ovaries > 0 && physicalAgeSwap > actor.pubertyAgeXX) {
+						increaseWetness(actor);
+					}
+					increaseWaistXX(actor);
+					increaseHipsXX(actor);
+					increaseButtXX(actor);
 				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 185) {
-					actor.height += jsEither([1, 1, 2, 2, 3, 3]);
+				increasePregAdaptationXX(actor);
+			} else { /* shota becoming a man */
+				if (physicalAgeSwap === 13 || (physicalAgeSwap > 13 && (actor.hormoneBalance >= 100 || actor.hormoneBalance <= -100))) {
+					increaseFaceXY(actor);
+					if (actor.voice > 1) {
+						increaseVoiceXY(actor);
+					}
 				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 186) {
-					actor.height += jsEither([0, 0, 1, 1, 2, 2]);
+				if (actor.geneticQuirks.neoteny !== 2) {
+					increaseBoobsXY(actor);
+					if (actor.dick > 0) {
+						increaseDick(actor);
+					}
+					if (actor.balls > 0) {
+						increaseBalls(actor);
+					}
+					increaseWaistXY(actor);
+					increaseHipsXY(actor);
+					increaseButtXY(actor);
 				}
+				increasePregAdaptationXY(actor);
 			}
 		}
-		// experiment - Let's see if this keeps players on average above average height or if it makes them too tall in the long run.
-		if (tallerPC) {
-			actor.height += random(0, 3);
-		}
 	}
 
 	/**
 	 * @param {FC.HumanState} actor
 	 */
-	function increaseHeightDwarf(actor) {
-		if (actor.hormoneBalance >= 200) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 80) {
-					actor.height += jsEither([1, 1, 2, 2]);
-				} else if (actor.height <= 84) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 84) {
-					actor.height += jsEither([4, 4, 5, 5]);
-				} else if (actor.height <= 90) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 90) {
-					actor.height += jsEither([8, 8, 9, 9]);
-				} else if (actor.height <= 100) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 100) {
-					actor.height += jsEither([3, 3, 4, 4]);
-				} else if (actor.height <= 105) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 105) {
-					actor.height += jsEither([2, 2, 3, 3]);
-				} else if (actor.height <= 109) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 109) {
-					actor.height += jsEither([3, 3, 4, 4]);
-				} else if (actor.height <= 114) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 114) {
-					actor.height += jsEither([2, 2, 3, 3]);
-				} else if (actor.height <= 118) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 118) {
-					actor.height += jsEither([2, 2, 3, 3]);
-				} else if (actor.height <= 122) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 122) {
-					actor.height += jsEither([3, 3, 4, 4]);
-				} else if (actor.height <= 127) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 127) {
-					actor.height += jsEither([3, 3, 4, 4]);
-				} else if (actor.height <= 132) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 132) {
-					actor.height += jsEither([1, 1, 2, 2]);
-				} else if (actor.height <= 135) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 135) {
-					actor.height += jsEither([1, 1, 2, 2]);
-				} else if (actor.height <= 138) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 138) {
-					actor.height += jsEither([1, 1, 2, 2]);
-				} else if (actor.height <= 141) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([0, 0, 1, 1]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([0, 0, 1, 1]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([0, 0, 1, 1]);
-				}
-			}
-		} else if (actor.hormoneBalance >= 100) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 80) {
-					actor.height += jsEither([1, 1, 2, 2, 2]);
-				} else if (actor.height <= 84) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 84) {
-					actor.height += jsEither([4, 4, 5, 5, 5]);
-				} else if (actor.height <= 90) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 90) {
-					actor.height += jsEither([8, 8, 9, 9, 9]);
-				} else if (actor.height <= 100) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 100) {
-					actor.height += jsEither([3, 3, 4, 4, 4]);
-				} else if (actor.height <= 105) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 105) {
-					actor.height += jsEither([2, 2, 3, 3, 3]);
-				} else if (actor.height <= 109) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 109) {
-					actor.height += jsEither([3, 3, 4, 4, 4]);
-				} else if (actor.height <= 114) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 114) {
-					actor.height += jsEither([2, 2, 3, 3, 3]);
-				} else if (actor.height <= 118) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 118) {
-					actor.height += jsEither([2, 2, 3, 3, 3]);
-				} else if (actor.height <= 122) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 122) {
-					actor.height += jsEither([3, 3, 4, 4, 4]);
-				} else if (actor.height <= 127) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 127) {
-					actor.height += jsEither([3, 3, 4, 4, 4]);
-				} else if (actor.height <= 132) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 132) {
-					actor.height += jsEither([1, 1, 2, 2, 2]);
-				} else if (actor.height <= 135) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 135) {
-					actor.height += jsEither([1, 1, 2, 2, 2]);
-				} else if (actor.height <= 138) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 138) {
-					actor.height += jsEither([1, 1, 2, 2, 2]);
-				} else if (actor.height <= 141) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([0, 0, 1, 1, 1]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([0, 0, 1, 1, 1]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([0, 0, 1, 1, 1]);
-				}
-			}
-		} else if (actor.hormoneBalance <= -200) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 80) {
-					actor.height += jsEither([2, 2, 3, 3]);
-				} else if (actor.height <= 84) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 84) {
-					actor.height += jsEither([5, 5, 6, 6]);
-				} else if (actor.height <= 90) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 90) {
-					actor.height += jsEither([9, 9, 10, 10]);
-				} else if (actor.height <= 100) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 100) {
-					actor.height += jsEither([4, 4, 5, 5]);
-				} else if (actor.height <= 105) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 105) {
-					actor.height += jsEither([3, 3, 4, 4]);
-				} else if (actor.height <= 109) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 109) {
-					actor.height += jsEither([4, 4, 5, 5]);
-				} else if (actor.height <= 114) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 114) {
-					actor.height += jsEither([3, 3, 4, 4]);
-				} else if (actor.height <= 118) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 118) {
-					actor.height += jsEither([3, 3, 4, 4]);
-				} else if (actor.height <= 122) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 122) {
-					actor.height += jsEither([4, 4, 5, 5]);
-				} else if (actor.height <= 127) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 127) {
-					actor.height += jsEither([4, 4, 5, 5]);
-				} else if (actor.height <= 132) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 132) {
-					actor.height += jsEither([2, 2, 3, 3]);
-				} else if (actor.height <= 135) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 135) {
-					actor.height += jsEither([2, 2, 3, 3]);
-				} else if (actor.height <= 138) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 138) {
-					actor.height += jsEither([2, 2, 3, 3]);
-				} else if (actor.height <= 141) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([1, 1, 2, 2]);
-				}
-			}
-		} else if (actor.hormoneBalance <= -100) {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 80) {
-					actor.height += jsEither([2, 2, 2, 3, 3]);
-				} else if (actor.height <= 84) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 84) {
-					actor.height += jsEither([5, 5, 5, 6, 6]);
-				} else if (actor.height <= 90) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 90) {
-					actor.height += jsEither([9, 9, 9, 10, 10]);
-				} else if (actor.height <= 100) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 100) {
-					actor.height += jsEither([4, 4, 4, 5, 5]);
-				} else if (actor.height <= 105) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 105) {
-					actor.height += jsEither([3, 3, 3, 4, 4]);
-				} else if (actor.height <= 109) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 109) {
-					actor.height += jsEither([4, 4, 4, 5, 5]);
-				} else if (actor.height <= 114) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 114) {
-					actor.height += jsEither([3, 3, 3, 4, 4]);
-				} else if (actor.height <= 118) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 118) {
-					actor.height += jsEither([3, 3, 3, 4, 4]);
-				} else if (actor.height <= 122) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 122) {
-					actor.height += jsEither([4, 4, 4, 5, 5]);
-				} else if (actor.height <= 127) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 127) {
-					actor.height += jsEither([4, 4, 4, 5, 5]);
-				} else if (actor.height <= 132) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 132) {
-					actor.height += jsEither([2, 2, 2, 3, 3]);
-				} else if (actor.height <= 135) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 135) {
-					actor.height += jsEither([2, 2, 2, 3, 3]);
-				} else if (actor.height <= 138) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 138) {
-					actor.height += jsEither([2, 2, 2, 3, 3]);
-				} else if (actor.height <= 141) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([1, 1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([1, 1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([1, 1, 1, 2, 2]);
-				}
-			}
-		} else {
-			if (physicalAgeSwap === 3) {
-				if (actor.height <= 80) {
-					actor.height += jsEither([1, 1, 2, 2, 3, 3]);
-				} else if (actor.height <= 84) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 4) {
-				if (actor.height <= 84) {
-					actor.height += jsEither([4, 4, 5, 5, 6, 6]);
-				} else if (actor.height <= 90) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 5) {
-				if (actor.height <= 90) {
-					actor.height += jsEither([8, 8, 9, 9, 10, 10]);
-				} else if (actor.height <= 100) {
-					actor.height += 5;
-				}
-			} else if (physicalAgeSwap === 6) {
-				if (actor.height <= 100) {
-					actor.height += jsEither([3, 3, 4, 4, 5, 5]);
-				} else if (actor.height <= 105) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 7) {
-				if (actor.height <= 105) {
-					actor.height += jsEither([2, 2, 3, 3, 4, 4]);
-				} else if (actor.height <= 109) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 8) {
-				if (actor.height <= 109) {
-					actor.height += jsEither([3, 3, 4, 4, 5, 5]);
-				} else if (actor.height <= 114) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 9) {
-				if (actor.height <= 114) {
-					actor.height += jsEither([2, 2, 3, 3, 4, 4]);
-				} else if (actor.height <= 118) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 10) {
-				if (actor.height <= 118) {
-					actor.height += jsEither([2, 2, 3, 3, 4, 4]);
-				} else if (actor.height <= 122) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 11) {
-				if (actor.height <= 122) {
-					actor.height += jsEither([3, 3, 4, 4, 5, 5]);
-				} else if (actor.height <= 127) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 12) {
-				if (actor.height <= 127) {
-					actor.height += jsEither([3, 3, 4, 4, 5, 5]);
-				} else if (actor.height <= 132) {
-					actor.height += 2;
-				}
-			} else if (physicalAgeSwap === 13) {
-				if (actor.height <= 132) {
-					actor.height += jsEither([1, 1, 2, 2, 3, 3]);
-				} else if (actor.height <= 135) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 14) {
-				if (actor.height <= 135) {
-					actor.height += jsEither([1, 1, 2, 2, 3, 3]);
-				} else if (actor.height <= 138) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 15) {
-				if (actor.height <= 138) {
-					actor.height += jsEither([1, 1, 2, 2, 3, 3]);
-				} else if (actor.height <= 141) {
-					actor.height += 1;
-				}
-			} else if (physicalAgeSwap === 16) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([0, 0, 1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 17) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([0, 0, 1, 1, 2, 2]);
-				}
-			} else if (physicalAgeSwap === 18) {
-				if (actor.height <= 143) {
-					actor.height += jsEither([0, 0, 1, 1, 2, 2]);
-				}
-			}
+	function increaseHeight(actor) {
+		const unalteredHeight = actor.height - actor.heightImplant * 10;
+		const lastYearsTarget = Height.forAge(actor.natural.height, physicalAgeSwap - 1, actor.genes);
+		const thisYearsTarget = Height.forAge(actor.natural.height, physicalAgeSwap, actor.genes);
+		// by default, grow by the difference in natural height targets, +1/-2 cm
+		// slightly undershooting on average is intentional, since we can't shrink but we CAN have growth spurts
+		let thisYearsGrowth = thisYearsTarget - lastYearsTarget + jsRandom(-2, 1);
+		// if we're way ahead of target or way behind target, adjust towards it a bit harder
+		// if the player doesn't interfere, this mechanism should always end up within 2cm of the target at age 20, with slightly "spurty" growth
+		const deltaFromTarget = thisYearsTarget - (unalteredHeight + thisYearsGrowth);
+		const yearsLeft = Math.min(5, 21 - physicalAgeSwap);
+		if (deltaFromTarget >= yearsLeft) {
+			thisYearsGrowth = Math.max(0, thisYearsGrowth) + 2;
+		} else if (deltaFromTarget <= -yearsLeft) {
+			thisYearsGrowth = Math.min(0, thisYearsGrowth) - 2;
 		}
-	}
-
-	/**
-	 * @param {FC.HumanState} actor
-	 */
-	function increaseHeightGiant(actor) {
-		if (actor.hormoneBalance >= 200) {
-			if (physicalAgeSwap < 16) {
-				if (actor.height <= 270) {
-					actor.height += random(5, 12);
-				}
-			} else {
-				if (actor.height <= 270) {
-					actor.height += random(3, 7);
-				}
-			}
-		} else if (actor.hormoneBalance >= 100) {
-			if (physicalAgeSwap < 16) {
-				if (actor.height <= 270) {
-					actor.height += random(7, 15);
-				}
-			} else {
-				if (actor.height <= 270) {
-					actor.height += random(5, 7);
-				}
-			}
-		} else if (actor.hormoneBalance <= -200) {
-			if (physicalAgeSwap < 16) {
-				if (actor.height <= 270) {
-					actor.height += random(10, 25);
-				}
-			} else {
-				if (actor.height <= 270) {
-					actor.height += random(7, 13);
-				}
-			}
-		} else if (actor.hormoneBalance <= -100) {
-			if (physicalAgeSwap < 16) {
-				if (actor.height <= 270) {
-					actor.height += random(7, 22);
-				}
-			} else {
-				if (actor.height <= 270) {
-					actor.height += random(7, 12);
-				}
-			}
-		} else {
-			if (physicalAgeSwap < 16) {
-				if (actor.height <= 270) {
-					actor.height += random(7, 20);
-				}
-			} else {
-				if (actor.height <= 270) {
-					actor.height += random(5, 10);
-				}
-			}
+		// never shrink
+		if (thisYearsGrowth > 0) {
+			actor.height += Math.round(thisYearsGrowth);
 		}
 	}
 
diff --git a/src/events/PE/pePitFightInvite.js b/src/events/PE/pePitFightInvite.js
index bb87accef41e052dd06cf78f1a9f4d2a3ee794dd..fac0557e5a499a5cc2efd0f044898ae60d156250 100644
--- a/src/events/PE/pePitFightInvite.js
+++ b/src/events/PE/pePitFightInvite.js
@@ -14,7 +14,7 @@ App.Events.PEPitFightInvite = class PEPitFightInvite extends App.Events.BaseEven
 		App.Events.addParagraph(node, r);
 		r = [];
 		if (V.pit) {
-			r.push(`Of course, ${capFirstChar(V.pit.name)} in ${V.arcologies[0].name} sees regular fights${(V.pit.lethal) ? " to the death" : ""}, but there's something extra special about attending these outside fights${(V.pit.lethal) ? ", especially with the very real risk of violent death" : ""}.`);
+			r.push(`Of course, ${capFirstChar(V.pit.name)} in ${V.arcologies[0].name} sees regular fights${(V.pit.lethal > 0) ? " to the death" : ""}, but there's something extra special about attending these outside fights${(V.pit.lethal > 0) ? ", especially with the very real risk of violent death" : ""}.`);
 		}
 		App.Events.addParagraph(node, r);
 
diff --git a/src/events/RE/reShippingContainer.js b/src/events/RE/reShippingContainer.js
index 05661da1cce1360648a1a5bc84d48be39fa86094..60e1c5f5e0003565b11b29f9b201bf41fe7561fd 100644
--- a/src/events/RE/reShippingContainer.js
+++ b/src/events/RE/reShippingContainer.js
@@ -17,7 +17,7 @@ App.Events.REShippingContainer = class REShippingContainer extends App.Events.Ba
 
 		const newSlaves = [];
 		for (let reShip = 0; reShip < 5; reShip++) {
-			const slave = GenerateNewSlave("XX");
+			const slave = GenerateNewSlave((V.seeDicks !== 100) ? "XX" : "XY");
 			slave.origin = "$He arrived at your arcology in an undocumented shipping container.";
 			slave.devotion = random(-90, -75);
 			slave.trust = -20;
diff --git a/src/events/RESS/review/birthdaySex.js b/src/events/RESS/review/birthdaySex.js
index 73ffa808b68f8ff1243c05ba6bbc911cb3a7ce0d..02e8e3f521264c1021b09df40650f89495647c18 100644
--- a/src/events/RESS/review/birthdaySex.js
+++ b/src/events/RESS/review/birthdaySex.js
@@ -55,7 +55,9 @@ App.Events.RESSBirthdaySex = class RESSBirthdaySex extends App.Events.BaseEvent
 			);
 
 			seX(eventSlave, vaginal ? "vaginal" : "anal", V.PC);
-			knockMeUp(eventSlave, 1, vaginal ? 0 : 1, -1);
+			if (canImpreg(eventSlave, V.PC)) {
+				knockMeUp(eventSlave, 1, vaginal ? 0 : 1, -1);
+			}
 			eventSlave.devotion += 10;
 
 			App.Events.addParagraph(frag, r);
@@ -80,7 +82,9 @@ App.Events.RESSBirthdaySex = class RESSBirthdaySex extends App.Events.BaseEvent
 			}
 
 			seX(eventSlave, vaginal ? "vaginal" : "anal", V.PC);
-			knockMeUp(eventSlave, 1, vaginal ? 0 : 1, -1);
+			if (canImpreg(eventSlave, V.PC)) {
+				knockMeUp(eventSlave, 1, vaginal ? 0 : 1, -1);
+			}
 			eventSlave.trust -= 10;
 			if (isVirgin) {
 				eventSlave.devotion -= 10;
diff --git a/src/events/assistant/assistantMarket.js b/src/events/assistant/assistantMarket.js
index 735ef655910e0eb5d4be760945fa2cc59a118514..a9ff1ff9a4f0fb215a647fd735e29e1c7a44b949 100644
--- a/src/events/assistant/assistantMarket.js
+++ b/src/events/assistant/assistantMarket.js
@@ -109,9 +109,8 @@ App.Events.assistantMarket = class assistantMarket extends App.Events.BaseEvent
 			r.push(`${HisA} avatar bounces towards the ¤ symbol. "This avatar indicates the automated trading systems. If you wish to activate them, please visit my menu. Consider the options there carefully before offering an automated system access to your finances."`);
 		}
 
-		r.push(App.UI.DOM.makeElement("h3", "Personal Assistant and Market Assistant relationship styles"));
 		App.Events.addParagraph(node, r);
-
+		App.UI.DOM.appendNewElement("h3", node, "Personal Assistant and Market Assistant relationship styles");
 
 		if (V.assistant.personality !== 0 && V.assistant.appearance !== "normal") {
 			const responses = [
diff --git a/src/events/assistant/assistantName.js b/src/events/assistant/assistantName.js
index 075b64e9eb22e87e4070ed16b61d9e7c5cfb7e98..f38c7a24ad648985caa232176f8cd08fa0ddee3a 100644
--- a/src/events/assistant/assistantName.js
+++ b/src/events/assistant/assistantName.js
@@ -12,6 +12,7 @@ App.Events.assistantName = class assistantName extends App.Events.BaseEvent {
 	}
 
 	execute(node) {
+		V.assistant.announcedName = 1;
 		const {
 			HeA, HisA,
 			heA, hisA, himA, himselfA,
@@ -158,7 +159,6 @@ App.Events.assistantName = class assistantName extends App.Events.BaseEvent {
 				V.assistant.name = v;
 				const el = new DocumentFragment();
 				const r = [];
-				V.assistant.announcedName = 1;
 				if (V.assistant.name !== "your personal assistant") {
 					r.push(`"${V.assistant.name}," ${heA} says. "${V.assistant.name}. My name is ${V.assistant.name}."`);
 					switch (V.assistant.appearance) {
diff --git a/src/events/intro/acquisition.js b/src/events/intro/acquisition.js
index f2a8c7998bea90a956413883e03808c4c11f5a85..a3a00a0561275f4d20bed3dfac568b5bae51985a 100644
--- a/src/events/intro/acquisition.js
+++ b/src/events/intro/acquisition.js
@@ -25,6 +25,8 @@ App.Intro.acquisition = function() {
 	V.targetAgeNursery = V.minimumSlaveAge;
 	resetFamilyCounters();
 
+	delete V.limitedCheatStart;
+
 	App.UI.DOM.appendNewElement("p", el, "You've done it.");
 	App.UI.DOM.appendNewElement("p", el, `You arrive at your new arcology, ${V.arcologies[0].name}, and head straight to the penthouse to enter the access codes that will tell the ${V.arcologies[0].name} systems to recognize you as their owner. The penthouse office is ready to receive the codes, and they authenticate. A voice activates in your earpiece.`);
 	App.UI.DOM.appendNewElement("p", el, `Congratulations. I am a personal assistant program, and it is my pleasure to assist you, ${PlayerName()} the new owner of ${V.arcologies[0].name}. I will offer useful information whenever possible in italics. Your new arcology has some unusual equipment. The previous owner kept a small stable of sex slaves. The penthouse therefore has a body modification studio for tattooing, bleaching and piercing, and an auto salon for more prosaic things like hair care. It also has a remote surgery, a small surgical theater that can be operated remotely by a qualified surgeon if you can pay the fee. Finally, it has a slave nutrition system connected to the arcology's hydroponics bays. This system produces a tasty protein-rich drink that provides the physically active female body all its necessary nutrients while leaving the lower digestive tract extremely clean. It even causes a mild increase in sex drive.`, ["note"]);
@@ -373,9 +375,13 @@ App.Intro.acquisition = function() {
 		} else {
 			V.PC.trueVirgin = 1;
 		}
+		if (V.PC.geneticQuirks.albinism === 2) {
+			V.PC.skin = getGeneticSkinColor(V.PC);
+			V.PC.hColor = getGeneticHairColor(V.PC);
+			resetEyeColor(V.PC, "both");
+		}
 	}
 
-
 	function parentSetup() {
 		/** @type {Map<number, number>} */
 		const missingMap = new Map();
@@ -1031,6 +1037,7 @@ App.Intro.acquisition = function() {
 							slave.geneticQuirks.dwarfism = 2;
 						}
 					}
+					slave.natural.height = slave.height;
 				}
 				slave.skill.oral = random(35, 65);
 				slave.skill.anal = random(15, 35);
@@ -1063,6 +1070,7 @@ App.Intro.acquisition = function() {
 							slave.geneticQuirks.gigantism = 2;
 						}
 					}
+					slave.natural.height = slave.height;
 				}
 				slave.skill.oral = random(15, 35);
 				slave.skill.anal = random(15, 35);
diff --git a/src/events/intro/introSummary.js b/src/events/intro/introSummary.js
index 6b2623414ee599a963a25aeed0f087a7c342626a..5baa94df043d8b12de14a8b660184dff5644ad0a 100644
--- a/src/events/intro/introSummary.js
+++ b/src/events/intro/introSummary.js
@@ -5,6 +5,7 @@ App.Intro.summary = function() {
 	V.FSCreditCount = variableAsNumber(V.FSCreditCount, 4, 7, 5);
 	V.PC.actualAge = variableAsNumber(V.PC.actualAge, 10, 80, 35);
 	V.PC.height = variableAsNumber(V.PC.height, 85, 305, 185);
+	V.PC.natural.height = variableAsNumber(V.PC.natural.height, 85, 305, 185);
 	V.PC.boobs = variableAsNumber(V.PC.boobs, 100, 50000, 200);
 	V.PC.pubertyAgeXX = variableAsNumber(V.PC.pubertyAgeXX, 8, 13, 13);
 	V.PC.pubertyAgeXY = variableAsNumber(V.PC.pubertyAgeXY, 8, 13, 13);
@@ -57,468 +58,7 @@ App.Intro.summary = function() {
 			App.UI.DOM.link(
 				"Continue",
 				() => {
-					if (V.freshPC === 1 || V.saveImported === 0) {
-						switch (V.PC.career) {
-							case "arcology owner":
-								V.PC.skill.trading = 100;
-								V.PC.skill.warfare = 100;
-								V.PC.skill.hacking = 100;
-								V.PC.skill.slaving = 100;
-								V.PC.skill.engineering = 100;
-								V.PC.skill.medicine = 100;
-								V.PC.skill.combat = 100;
-								break;
-							case "wealth":
-								if (V.PC.vagina === 1) {
-									V.PC.vagina = 2;
-								}
-								V.PC.weight = 60;
-								V.PC.muscles = 0;
-								break;
-							case "trust fund":
-								V.PC.intelligenceImplant = 15;
-								V.PC.skill.warfare = -50;
-								V.PC.skill.slaving = -50;
-								V.PC.skill.engineering = -50;
-								V.PC.skill.medicine = -50;
-								V.PC.weight = 60;
-								V.PC.muscles = 0;
-								break;
-							case "rich kid":
-								V.PC.intelligenceImplant = 5;
-								V.PC.skill.trading = -25;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -25;
-								V.PC.weight = 60;
-								V.PC.muscles = 0;
-								break;
-							case "capitalist":
-								V.PC.skill.trading = 100;
-								V.PC.muscles = 0;
-								break;
-							case "entrepreneur":
-								V.PC.intelligenceImplant = 15;
-								V.PC.skill.trading = 50;
-								V.PC.skill.warfare = -25;
-								V.PC.skill.slaving = -25;
-								V.PC.skill.engineering = -25;
-								V.PC.skill.medicine = -25;
-								V.PC.muscles = 0;
-								break;
-							case "business kid":
-								V.PC.intelligenceImplant = 5;
-								V.PC.skill.warfare = -80;
-								V.PC.skill.slaving = -80;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -20;
-								V.PC.muscles = 0;
-								break;
-							case "mercenary":
-								V.PC.skill.warfare = 100;
-								V.PC.skill.combat = 70;
-								V.PC.muscles = 50;
-								break;
-							case "recruit":
-								V.PC.intelligenceImplant = 15;
-								V.PC.skill.trading = -25;
-								V.PC.skill.warfare = 50;
-								V.PC.skill.slaving = -25;
-								V.PC.skill.engineering = -25;
-								V.PC.skill.medicine = -25;
-								V.PC.skill.combat = 50;
-								V.PC.muscles = 40;
-								break;
-							case "child soldier":
-								V.PC.intelligenceImplant = 0;
-								V.PC.skill.trading = -100;
-								V.PC.skill.slaving = -80;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -80;
-								V.PC.skill.combat = 30;
-								break;
-							case "slaver":
-								V.PC.skill.slaving = 100;
-								V.PC.skill.combat = 50;
-								V.PC.muscles = 50;
-								break;
-							case "slave overseer":
-								V.PC.intelligenceImplant = 15;
-								V.PC.skill.trading = -20;
-								V.PC.skill.warfare = -20;
-								V.PC.skill.slaving = 50;
-								V.PC.skill.engineering = -25;
-								V.PC.skill.medicine = -20;
-								V.PC.skill.combat = 30;
-								V.PC.muscles = 50;
-								break;
-							case "slave tender":
-								V.PC.intelligenceImplant = 0;
-								V.PC.skill.trading = -100;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -60;
-								V.PC.skill.hacking = -100;
-								V.PC.muscles = 10;
-								break;
-							case "engineer":
-								V.PC.skill.engineering = 100;
-								break;
-							case "construction":
-								V.PC.intelligenceImplant = 15;
-								V.PC.skill.trading = -25;
-								V.PC.skill.warfare = -50;
-								V.PC.skill.slaving = -25;
-								V.PC.skill.engineering = 50;
-								V.PC.skill.medicine = -25;
-								V.PC.skill.hacking = -20;
-								V.PC.muscles = 50;
-								break;
-							case "worksite helper":
-								V.PC.intelligenceImplant = 0;
-								V.PC.skill.trading = -80;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = 0;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -100;
-								break;
-							case "medicine":
-								V.PC.skill.medicine = 100;
-								V.PC.muscles = 0;
-								V.consumerDrugs = 1;
-								break;
-							case "medical assistant":
-								V.PC.intelligenceImplant = 15;
-								V.PC.skill.trading = -25;
-								V.PC.skill.warfare = -50;
-								V.PC.skill.slaving = -25;
-								V.PC.skill.engineering = -25;
-								V.PC.skill.medicine = 50;
-								V.PC.skill.hacking = -20;
-								V.PC.muscles = 0;
-								break;
-							case "nurse":
-								V.PC.intelligenceImplant = 5;
-								V.PC.skill.trading = -100;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.hacking = -20;
-								V.PC.muscles = 0;
-								break;
-							case "celebrity":
-								if (V.PC.vagina === 1) {
-									V.PC.vagina = 2;
-								}
-								V.PC.muscles = -20;
-								break;
-							case "rising star":
-								V.PC.intelligenceImplant = 15;
-								V.PC.skill.trading = -50;
-								V.PC.skill.warfare = -50;
-								V.PC.skill.slaving = -50;
-								V.PC.skill.engineering = -50;
-								V.PC.skill.medicine = -50;
-								V.PC.muscles = -20;
-								break;
-							case "child star":
-								V.PC.intelligenceImplant = 0;
-								V.PC.skill.trading = -100;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -20;
-								V.PC.muscles = 0;
-								break;
-							case "BlackHat":
-								V.PC.skill.hacking = 100;
-								V.PC.muscles = -20;
-								break;
-							case "hacker":
-								V.PC.intelligenceImplant = 15;
-								V.PC.skill.trading = -50;
-								V.PC.skill.warfare = -50;
-								V.PC.skill.slaving = -50;
-								V.PC.skill.engineering = -50;
-								V.PC.skill.medicine = -50;
-								V.PC.skill.hacking = 50;
-								V.PC.muscles = -20;
-								break;
-							case "script kiddy":
-								V.PC.intelligenceImplant = 5;
-								V.PC.skill.trading = -80;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -80;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = 20;
-								V.PC.muscles = -20;
-								break;
-							case "escort":
-								if (V.PC.vagina >= 0) {
-									V.PC.vagina = 4;
-								}
-								V.PC.anus = 1;
-								V.PC.clothes = "a slutty outfit";
-								V.PC.intelligenceImplant = 15;
-								V.PC.skill.trading = 50;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = 10;
-								V.PC.skill.hacking = 10;
-								V.PC.muscles = 0;
-								break;
-							case "prostitute":
-								if (V.PC.vagina >= 0) {
-									V.PC.vagina = 3;
-								}
-								V.PC.anus = 1;
-								V.PC.clothes = "a slutty outfit";
-								V.PC.intelligenceImplant = 0;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -50;
-								V.PC.skill.hacking = -20;
-								V.PC.muscles = 0;
-								break;
-							case "child prostitute":
-								if (V.PC.vagina >= 0) {
-									V.PC.vagina = 2;
-								}
-								V.PC.anus = 1;
-								V.PC.clothes = "a slutty outfit";
-								V.PC.intelligenceImplant = 0;
-								V.PC.skill.trading = -50;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -80;
-								V.PC.muscles = -20;
-								break;
-							case "servant":
-								V.PC.clothes = "a nice maid outfit";
-								V.PC.intelligenceImplant = 0;
-								if (V.PC.vagina >= 1) {
-									V.PC.vagina = 3;
-								}
-								if (V.PC.vagina >= 0) {
-									V.PC.geneticQuirks.fertility = 2;
-								} else {
-									V.PC.geneticQuirks.fertility = 1;
-								}
-								V.PC.skill.trading = -100;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -100;
-								V.PC.muscles = 0;
-								V.PC.digestiveSystem = "atrophied";
-								break;
-							case "handmaiden":
-								V.PC.clothes = "a nice maid outfit";
-								V.PC.intelligenceImplant = 0;
-								if (V.PC.vagina >= 1) {
-									V.PC.vagina = 3;
-								}
-								if (V.PC.vagina >= 0) {
-									V.PC.geneticQuirks.fertility = 2;
-								} else {
-									V.PC.geneticQuirks.fertility = 1;
-								}
-								V.PC.skill.trading = -100;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -100;
-								V.PC.muscles = 0;
-								V.PC.geneticQuirks.fertility = 1;
-								V.PC.digestiveSystem = "atrophied";
-								break;
-							case "child servant":
-								V.PC.clothes = "a nice maid outfit";
-								V.PC.intelligenceImplant = 0;
-								if (V.PC.vagina >= 1) {
-									V.PC.vagina = 2;
-								}
-								if (V.PC.vagina >= 0) {
-									V.PC.geneticQuirks.fertility = 2;
-								} else {
-									V.PC.geneticQuirks.fertility = 1;
-								}
-								V.PC.skill.trading = -100;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -100;
-								V.PC.muscles = 0;
-								V.PC.geneticQuirks.fertility = 1;
-								V.PC.digestiveSystem = "atrophied";
-								break;
-							case "gang":
-								if (V.PC.vagina === 1) {
-									V.PC.vagina = 2;
-								}
-								V.PC.intelligenceImplant = 15;
-								V.PC.skill.trading = 50;
-								V.PC.skill.warfare = 50;
-								V.PC.skill.slaving = 50;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.hacking = 50;
-								V.PC.skill.combat = 50;
-								V.PC.muscles = 60;
-								break;
-							case "hoodlum":
-								V.PC.intelligenceImplant = 0;
-								V.PC.skill.warfare = -20;
-								V.PC.skill.slaving = -20;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -50;
-								V.PC.skill.hacking = 0;
-								V.PC.skill.combat = 30;
-								break;
-							case "street urchin":
-								V.PC.intelligenceImplant = 0;
-								V.PC.skill.trading = -20;
-								V.PC.skill.warfare = -40;
-								V.PC.skill.slaving = -80;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -100;
-								V.PC.skill.combat = 10;
-								break;
-							case "test subject":
-								V.PC.intelligenceImplant = 0;
-								V.PC.skill.trading = -100;
-								V.PC.skill.warfare = -100;
-								V.PC.skill.slaving = -100;
-								V.PC.skill.engineering = -100;
-								V.PC.skill.medicine = -100;
-								V.PC.skill.hacking = -100;
-								V.PC.muscles = -100;
-								V.PC.boobs = 50000;
-								V.PC.lactation = 1;
-								V.PC.lactationAdaptation = 100;
-								if (V.PC.pubertyXX === 1) {
-									V.PC.pregType = 100;
-									V.PC.preg = 27;
-								} else {
-									V.PC.bellyImplant = 800000;
-								}
-								V.PC.pregAdaptation = 200;
-								V.PC.hips = 3;
-								V.PC.butt = 20;
-								V.PC.dick = 50;
-								V.PC.balls = 100;
-								V.PC.weight = 200;
-								V.PC.digestiveSystem = "atrophied";
-								break;
-						}
-						if (V.PC.rumor === "diligence") {
-							V.PC.weight = 0;
-							if (V.PC.muscles < 30) {
-								V.PC.muscles += 20;
-							}
-						} else if (V.PC.rumor === "force") {
-							V.PC.muscles += 20;
-						}
-						// I hope this works
-						PCDatatypeCleanup(V.PC);
-
-						if (V.PC.dick >= 3) {
-							V.PC.geneticQuirks.wellHung = 2;
-						}
-						if (V.PC.title === 0) {
-							V.PC.hLength = 15;
-							V.PC.waist = -20;
-							V.PC.voice = 2;
-						}
-						if (V.PC.eye.right.vision === 1 || V.PC.eye.left.vision === 1) {
-							V.PC.eyewear = "corrective glasses";
-						}
-						if (V.PC.physicalAge >= 14) {
-							if (V.PC.balls > 0) {
-								V.PC.pubertyXY = 1;
-							}
-							if (V.PC.ovaries > 0) {
-								V.PC.pubertyXX = 1;
-							}
-						}
-						if (V.PC.pubertyXX === 0 && V.PC.pubertyXY === 0) {
-							if (V.PC.physicalAge < 11) {
-								V.PC.energy = 20;
-							} else if (V.PC.physicalAge < 12) {
-								V.PC.energy = 30;
-							} else if (V.PC.physicalAge < 13) {
-								V.PC.energy = 40;
-							}
-						}
-						if (V.PC.genes === "XX") {
-							if (V.PC.ovaries === 1 && V.PC.pubertyXX > 0) {
-								if (V.PC.balls > 0 && V.PC.pubertyXY > 0) {
-									V.PC.hormoneBalance = 10;
-								} else {
-									V.PC.hormoneBalance = 50;
-								}
-							} else if (V.PC.balls > 0 && V.PC.pubertyXY > 0) {
-								V.PC.hormoneBalance = -30;
-							} else {
-								V.PC.hormoneBalance = 10;
-							}
-						} else if (V.PC.genes === "XY") {
-							if (V.PC.ovaries === 1 && V.PC.pubertyXX > 0) {
-								if (V.PC.balls > 0 && V.PC.pubertyXY > 0) {
-									V.PC.hormoneBalance = -10;
-								} else {
-									V.PC.hormoneBalance = 30;
-								}
-							} else {
-								if (V.PC.balls > 0 && V.PC.pubertyXY > 0) {
-									V.PC.hormoneBalance = -50;
-								} else {
-									V.PC.hormoneBalance = -10;
-								}
-							}
-						}
-						if (V.PC.preg > 0 && V.PC.preg > V.PC.pregData.normalBirth / 2) {
-							V.PC.lactation = 1;
-						}
-						if (V.PC.pubertyXX === 1 && V.PC.physicalAge < V.PC.pubertyAgeXX) {
-							V.PC.pubertyAgeXX = 8;
-						}
-						if (V.PC.pubertyXY === 1 && V.PC.physicalAge < V.PC.pubertyAgeXY) {
-							V.PC.pubertyAgeXY = 8;
-						}
-						V.genePool.push(clone(V.PC));
-					}
-
-					V.PC.birthName = V.PC.slaveName;
-					V.PC.birthSurname = V.PC.slaveSurname;
-
-					if (V.saveImported === 1 && V.freshPC === 0 && V.PC.rules.living !== "luxurious") {
-						if (V.PC.rules.living === "spare") {
-							V.PC.rules.living = "normal";
-						} else {
-							V.PC.rules.living = "luxurious";
-						}
-					} else if (["celebrity", "child star", "rich kid", "rising star", "trust fund", "wealth"].includes(V.PC.career)) {
-						V.PC.rules.living = "normal";
-					} else {
-						V.PC.rules.living = "spare";
-					}
-					App.Intro.initNationalities();
-					SectorCounts(); // Update AProsperityCap
+					continueNormal();
 				},
 				[],
 				"Starting Girls"
@@ -647,6 +187,18 @@ App.Intro.summary = function() {
 				"Intended for debugging: may have unexpected effects"
 			)
 		);
+		linkArray.push(
+			App.UI.DOM.link(
+				"Limited Cheat Start",
+				() => {
+					continueNormal();
+					V.limitedCheatStart = 1;
+				},
+				[],
+				"Starting Girls",
+				"Allow cheating when selecting starting slaves"
+			)
+		);
 		App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(linkArray));
 
 		return el;
@@ -791,6 +343,473 @@ App.Intro.summary = function() {
 
 		return el;
 	}
+
+
+	function continueNormal() {
+
+		if (V.freshPC === 1 || V.saveImported === 0) {
+			switch (V.PC.career) {
+				case "arcology owner":
+					V.PC.skill.trading = 100;
+					V.PC.skill.warfare = 100;
+					V.PC.skill.hacking = 100;
+					V.PC.skill.slaving = 100;
+					V.PC.skill.engineering = 100;
+					V.PC.skill.medicine = 100;
+					V.PC.skill.combat = 100;
+					break;
+				case "wealth":
+					if (V.PC.vagina === 1) {
+						V.PC.vagina = 2;
+					}
+					V.PC.weight = 60;
+					V.PC.muscles = 0;
+					break;
+				case "trust fund":
+					V.PC.intelligenceImplant = 15;
+					V.PC.skill.warfare = -50;
+					V.PC.skill.slaving = -50;
+					V.PC.skill.engineering = -50;
+					V.PC.skill.medicine = -50;
+					V.PC.weight = 60;
+					V.PC.muscles = 0;
+					break;
+				case "rich kid":
+					V.PC.intelligenceImplant = 5;
+					V.PC.skill.trading = -25;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -25;
+					V.PC.weight = 60;
+					V.PC.muscles = 0;
+					break;
+				case "capitalist":
+					V.PC.skill.trading = 100;
+					V.PC.muscles = 0;
+					break;
+				case "entrepreneur":
+					V.PC.intelligenceImplant = 15;
+					V.PC.skill.trading = 50;
+					V.PC.skill.warfare = -25;
+					V.PC.skill.slaving = -25;
+					V.PC.skill.engineering = -25;
+					V.PC.skill.medicine = -25;
+					V.PC.muscles = 0;
+					break;
+				case "business kid":
+					V.PC.intelligenceImplant = 5;
+					V.PC.skill.warfare = -80;
+					V.PC.skill.slaving = -80;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -20;
+					V.PC.muscles = 0;
+					break;
+				case "mercenary":
+					V.PC.skill.warfare = 100;
+					V.PC.skill.combat = 70;
+					V.PC.muscles = 50;
+					break;
+				case "recruit":
+					V.PC.intelligenceImplant = 15;
+					V.PC.skill.trading = -25;
+					V.PC.skill.warfare = 50;
+					V.PC.skill.slaving = -25;
+					V.PC.skill.engineering = -25;
+					V.PC.skill.medicine = -25;
+					V.PC.skill.combat = 50;
+					V.PC.muscles = 40;
+					break;
+				case "child soldier":
+					V.PC.intelligenceImplant = 0;
+					V.PC.skill.trading = -100;
+					V.PC.skill.slaving = -80;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -80;
+					V.PC.skill.combat = 30;
+					break;
+				case "slaver":
+					V.PC.skill.slaving = 100;
+					V.PC.skill.combat = 50;
+					V.PC.muscles = 50;
+					break;
+				case "slave overseer":
+					V.PC.intelligenceImplant = 15;
+					V.PC.skill.trading = -20;
+					V.PC.skill.warfare = -20;
+					V.PC.skill.slaving = 50;
+					V.PC.skill.engineering = -25;
+					V.PC.skill.medicine = -20;
+					V.PC.skill.combat = 30;
+					V.PC.muscles = 50;
+					break;
+				case "slave tender":
+					V.PC.intelligenceImplant = 0;
+					V.PC.skill.trading = -100;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -60;
+					V.PC.skill.hacking = -100;
+					V.PC.muscles = 10;
+					break;
+				case "engineer":
+					V.PC.skill.engineering = 100;
+					break;
+				case "construction":
+					V.PC.intelligenceImplant = 15;
+					V.PC.skill.trading = -25;
+					V.PC.skill.warfare = -50;
+					V.PC.skill.slaving = -25;
+					V.PC.skill.engineering = 50;
+					V.PC.skill.medicine = -25;
+					V.PC.skill.hacking = -20;
+					V.PC.muscles = 50;
+					break;
+				case "worksite helper":
+					V.PC.intelligenceImplant = 0;
+					V.PC.skill.trading = -80;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = 0;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -100;
+					break;
+				case "medicine":
+					V.PC.skill.medicine = 100;
+					V.PC.muscles = 0;
+					V.consumerDrugs = 1;
+					break;
+				case "medical assistant":
+					V.PC.intelligenceImplant = 15;
+					V.PC.skill.trading = -25;
+					V.PC.skill.warfare = -50;
+					V.PC.skill.slaving = -25;
+					V.PC.skill.engineering = -25;
+					V.PC.skill.medicine = 50;
+					V.PC.skill.hacking = -20;
+					V.PC.muscles = 0;
+					break;
+				case "nurse":
+					V.PC.intelligenceImplant = 5;
+					V.PC.skill.trading = -100;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.hacking = -20;
+					V.PC.muscles = 0;
+					break;
+				case "celebrity":
+					if (V.PC.vagina === 1) {
+						V.PC.vagina = 2;
+					}
+					V.PC.muscles = -20;
+					break;
+				case "rising star":
+					V.PC.intelligenceImplant = 15;
+					V.PC.skill.trading = -50;
+					V.PC.skill.warfare = -50;
+					V.PC.skill.slaving = -50;
+					V.PC.skill.engineering = -50;
+					V.PC.skill.medicine = -50;
+					V.PC.muscles = -20;
+					break;
+				case "child star":
+					V.PC.intelligenceImplant = 0;
+					V.PC.skill.trading = -100;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -20;
+					V.PC.muscles = 0;
+					break;
+				case "BlackHat":
+					V.PC.skill.hacking = 100;
+					V.PC.muscles = -20;
+					break;
+				case "hacker":
+					V.PC.intelligenceImplant = 15;
+					V.PC.skill.trading = -50;
+					V.PC.skill.warfare = -50;
+					V.PC.skill.slaving = -50;
+					V.PC.skill.engineering = -50;
+					V.PC.skill.medicine = -50;
+					V.PC.skill.hacking = 50;
+					V.PC.muscles = -20;
+					break;
+				case "script kiddy":
+					V.PC.intelligenceImplant = 5;
+					V.PC.skill.trading = -80;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -80;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = 20;
+					V.PC.muscles = -20;
+					break;
+				case "escort":
+					if (V.PC.vagina >= 0) {
+						V.PC.vagina = 4;
+					}
+					V.PC.anus = 1;
+					V.PC.clothes = "a slutty outfit";
+					V.PC.intelligenceImplant = 15;
+					V.PC.skill.trading = 50;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = 10;
+					V.PC.skill.hacking = 10;
+					V.PC.muscles = 0;
+					break;
+				case "prostitute":
+					if (V.PC.vagina >= 0) {
+						V.PC.vagina = 3;
+					}
+					V.PC.anus = 1;
+					V.PC.clothes = "a slutty outfit";
+					V.PC.intelligenceImplant = 0;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -50;
+					V.PC.skill.hacking = -20;
+					V.PC.muscles = 0;
+					break;
+				case "child prostitute":
+					if (V.PC.vagina >= 0) {
+						V.PC.vagina = 2;
+					}
+					V.PC.anus = 1;
+					V.PC.clothes = "a slutty outfit";
+					V.PC.intelligenceImplant = 0;
+					V.PC.skill.trading = -50;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -80;
+					V.PC.muscles = -20;
+					break;
+				case "servant":
+					V.PC.clothes = "a nice maid outfit";
+					V.PC.intelligenceImplant = 0;
+					if (V.PC.vagina >= 1) {
+						V.PC.vagina = 3;
+					}
+					if (V.PC.vagina >= 0) {
+						V.PC.geneticQuirks.fertility = 2;
+					} else {
+						V.PC.geneticQuirks.fertility = 1;
+					}
+					V.PC.skill.trading = -100;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -100;
+					V.PC.muscles = 0;
+					V.PC.digestiveSystem = "atrophied";
+					break;
+				case "handmaiden":
+					V.PC.clothes = "a nice maid outfit";
+					V.PC.intelligenceImplant = 0;
+					if (V.PC.vagina >= 1) {
+						V.PC.vagina = 3;
+					}
+					if (V.PC.vagina >= 0) {
+						V.PC.geneticQuirks.fertility = 2;
+					} else {
+						V.PC.geneticQuirks.fertility = 1;
+					}
+					V.PC.skill.trading = -100;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -100;
+					V.PC.muscles = 0;
+					V.PC.geneticQuirks.fertility = 1;
+					V.PC.digestiveSystem = "atrophied";
+					break;
+				case "child servant":
+					V.PC.clothes = "a nice maid outfit";
+					V.PC.intelligenceImplant = 0;
+					if (V.PC.vagina >= 1) {
+						V.PC.vagina = 2;
+					}
+					if (V.PC.vagina >= 0) {
+						V.PC.geneticQuirks.fertility = 2;
+					} else {
+						V.PC.geneticQuirks.fertility = 1;
+					}
+					V.PC.skill.trading = -100;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -100;
+					V.PC.muscles = 0;
+					V.PC.geneticQuirks.fertility = 1;
+					V.PC.digestiveSystem = "atrophied";
+					break;
+				case "gang":
+					if (V.PC.vagina === 1) {
+						V.PC.vagina = 2;
+					}
+					V.PC.intelligenceImplant = 15;
+					V.PC.skill.trading = 50;
+					V.PC.skill.warfare = 50;
+					V.PC.skill.slaving = 50;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.hacking = 50;
+					V.PC.skill.combat = 50;
+					V.PC.muscles = 60;
+					break;
+				case "hoodlum":
+					V.PC.intelligenceImplant = 0;
+					V.PC.skill.warfare = -20;
+					V.PC.skill.slaving = -20;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -50;
+					V.PC.skill.hacking = 0;
+					V.PC.skill.combat = 30;
+					break;
+				case "street urchin":
+					V.PC.intelligenceImplant = 0;
+					V.PC.skill.trading = -20;
+					V.PC.skill.warfare = -40;
+					V.PC.skill.slaving = -80;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -100;
+					V.PC.skill.combat = 10;
+					break;
+				case "test subject":
+					V.PC.intelligenceImplant = 0;
+					V.PC.skill.trading = -100;
+					V.PC.skill.warfare = -100;
+					V.PC.skill.slaving = -100;
+					V.PC.skill.engineering = -100;
+					V.PC.skill.medicine = -100;
+					V.PC.skill.hacking = -100;
+					V.PC.muscles = -100;
+					V.PC.boobs = 50000;
+					V.PC.lactation = 1;
+					V.PC.lactationAdaptation = 100;
+					if (V.PC.pubertyXX === 1) {
+						V.PC.pregType = 100;
+						V.PC.preg = 27;
+					} else {
+						V.PC.bellyImplant = 800000;
+					}
+					V.PC.pregAdaptation = 200;
+					V.PC.hips = 3;
+					V.PC.butt = 20;
+					V.PC.dick = 50;
+					V.PC.balls = 100;
+					V.PC.weight = 200;
+					V.PC.digestiveSystem = "atrophied";
+					break;
+			}
+			if (V.PC.rumor === "diligence") {
+				V.PC.weight = 0;
+				if (V.PC.muscles < 30) {
+					V.PC.muscles += 20;
+				}
+			} else if (V.PC.rumor === "force") {
+				V.PC.muscles += 20;
+			}
+			// I hope this works
+			PCDatatypeCleanup(V.PC);
+
+			if (V.PC.dick >= 3) {
+				V.PC.geneticQuirks.wellHung = 2;
+			}
+			if (V.PC.title === 0) {
+				V.PC.hLength = 15;
+				V.PC.waist = -20;
+				V.PC.voice = 2;
+			}
+			if (V.PC.eye.right.vision === 1 || V.PC.eye.left.vision === 1) {
+				V.PC.eyewear = "corrective glasses";
+			}
+			if (V.PC.physicalAge >= 14) {
+				if (V.PC.balls > 0) {
+					V.PC.pubertyXY = 1;
+				}
+				if (V.PC.ovaries > 0) {
+					V.PC.pubertyXX = 1;
+				}
+			}
+			if (V.PC.pubertyXX === 0 && V.PC.pubertyXY === 0) {
+				if (V.PC.physicalAge < 11) {
+					V.PC.energy = 20;
+				} else if (V.PC.physicalAge < 12) {
+					V.PC.energy = 30;
+				} else if (V.PC.physicalAge < 13) {
+					V.PC.energy = 40;
+				}
+			}
+			if (V.PC.genes === "XX") {
+				if (V.PC.ovaries === 1 && V.PC.pubertyXX > 0) {
+					if (V.PC.balls > 0 && V.PC.pubertyXY > 0) {
+						V.PC.hormoneBalance = 10;
+					} else {
+						V.PC.hormoneBalance = 50;
+					}
+				} else if (V.PC.balls > 0 && V.PC.pubertyXY > 0) {
+					V.PC.hormoneBalance = -30;
+				} else {
+					V.PC.hormoneBalance = 10;
+				}
+			} else if (V.PC.genes === "XY") {
+				if (V.PC.ovaries === 1 && V.PC.pubertyXX > 0) {
+					if (V.PC.balls > 0 && V.PC.pubertyXY > 0) {
+						V.PC.hormoneBalance = -10;
+					} else {
+						V.PC.hormoneBalance = 30;
+					}
+				} else {
+					if (V.PC.balls > 0 && V.PC.pubertyXY > 0) {
+						V.PC.hormoneBalance = -50;
+					} else {
+						V.PC.hormoneBalance = -10;
+					}
+				}
+			}
+			if (V.PC.preg > 0 && V.PC.preg > V.PC.pregData.normalBirth / 2) {
+				V.PC.lactation = 1;
+			}
+			if (V.PC.pubertyXX === 1 && V.PC.physicalAge < V.PC.pubertyAgeXX) {
+				V.PC.pubertyAgeXX = 8;
+			}
+			if (V.PC.pubertyXY === 1 && V.PC.physicalAge < V.PC.pubertyAgeXY) {
+				V.PC.pubertyAgeXY = 8;
+			}
+			V.genePool.push(clone(V.PC));
+		}
+
+		V.PC.birthName = V.PC.slaveName;
+		V.PC.birthSurname = V.PC.slaveSurname;
+
+		if (V.saveImported === 1 && V.freshPC === 0 && V.PC.rules.living !== "luxurious") {
+			if (V.PC.rules.living === "spare") {
+				V.PC.rules.living = "normal";
+			} else {
+				V.PC.rules.living = "luxurious";
+			}
+		} else if (["celebrity", "child star", "rich kid", "rising star", "trust fund", "wealth"].includes(V.PC.career)) {
+			V.PC.rules.living = "normal";
+		} else {
+			V.PC.rules.living = "spare";
+		}
+		App.Intro.initNationalities();
+		SectorCounts(); // Update AProsperityCap
+	}
 };
 /**
  * @param {boolean} isIntro
diff --git a/src/events/intro/pcAppearance.js b/src/events/intro/pcAppearance.js
index b144a6abb56430fad323f0f99bbf6bfbd51f6df7..82a7f7df9c1f3b9ec89fddcf5f957f9919196d6c 100644
--- a/src/events/intro/pcAppearance.js
+++ b/src/events/intro/pcAppearance.js
@@ -18,19 +18,44 @@ App.UI.Player.appearance = function(options, summary = false) {
 	options.addOption("You are genetically", "genes", V.PC)
 		.addValue("XY").addValue("XX");
 
-	options.addOption(`You are`, "height", V.PC).showTextBox({unit: "cm"})
-		.addRange(145, 150, "<", "Petite")
-		.addRange(155, 160, "<", "Short")
-		.addRange(165, 170, "<", "Average")
-		.addRange(180, 185, "<", "Tall")
-		.addRange(190, 185, ">=", "Very tall")
-		.addComment(`Average height for a ${V.PC.physicalAge} year old is ${heightToEitherUnit(Height.mean(V.PC))}`);
+	if (V.PC.physicalAge >= 20) {
+		options.addOption(`You are`, "height", V.PC.natural).showTextBox({unit: "cm"})
+			.addRange(145, 150, "<", "Petite")
+			.addRange(155, 160, "<", "Short")
+			.addRange(165, 170, "<", "Average")
+			.addRange(180, 185, "<", "Tall")
+			.addRange(190, 185, ">=", "Very tall")
+			.addComment(`Average height is ${heightToEitherUnit(Height.mean(V.PC))}`)
+			.addCallback(() => V.PC.height = V.PC.natural.height);
+	} else {
+		options.addOption(`When full-grown, you will be`, "height", V.PC.natural).showTextBox({unit: "cm"})
+			.addRange(145, 150, "<", "Petite")
+			.addRange(155, 160, "<", "Short")
+			.addRange(165, 170, "<", "Average")
+			.addRange(180, 185, "<", "Tall")
+			.addRange(190, 185, ">=", "Very tall");
+	}
 	option = options.addCustomOption()
 		.addButton(
 			"Make average",
 			() => resyncSlaveHeight(V.PC),
 			""
 		);
+	if (V.PC.physicalAge < 20) {
+		options.addOption(`But right now, you are`, "height", V.PC).showTextBox({unit: "cm"})
+			.addRange(Height.forAge(145, V.PC), Height.forAge(150, V.PC), "<", "Petite for your age")
+			.addRange(Height.forAge(155, V.PC), Height.forAge(160, V.PC), "<", "Short for your age")
+			.addRange(Height.forAge(165, V.PC), Height.forAge(170, V.PC), "<", "Average for your age")
+			.addRange(Height.forAge(180, V.PC), Height.forAge(185, V.PC), "<", "Tall for your age")
+			.addRange(Height.forAge(190, V.PC), Height.forAge(185, V.PC), ">=", "Very tall for your age")
+			.addComment(`Average height for a ${V.PC.physicalAge} year old is ${heightToEitherUnit(Height.mean(V.PC))}`);
+		option = options.addCustomOption()
+			.addButton(
+				"Scale for age from adult height",
+				() => V.PC.height = Height.forAge(V.PC.natural.height, V.PC),
+				""
+			);
+	}
 
 	options.addOption("Your skin tone is", "skin", V.PC).showTextBox()
 		.addValueList(makeAList(V.PC.race === "catgirl" ? App.Medicine.Modification.catgirlNaturalSkins : App.Medicine.Modification.naturalSkins));
@@ -70,6 +95,16 @@ App.UI.Player.appearance = function(options, summary = false) {
 	options.addOption("Your body", "markings", V.PC)
 		.addValueList([["Is clear of blemishes", "none"], ["Has light freckling", "freckles"], ["Has heavy freckling", "heavily freckled"]]);
 
+	if (V.PC.geneticQuirks.albinism === 2 || V.PC.skin === "pure white" || V.PC.eye.origColor === "red" || V.PC.hColor === "white") {
+		options.addOption("You are", "albinism", V.PC.geneticQuirks)
+			.addValueList([
+				["An albino", 2],
+				["Not an albino", 0],
+			])
+			.addGlobalCallback((val) => induceAlbinism(V.PC, val))
+			.addComment("Once this is set, you may change your hair/eyes/skin without worry. You will generate as an albino.");
+	}
+
 	options.addOption("You have", "lips", V.PC).addValue("Thin lips", 5)
 		.addValueList([
 			["Normal lips", 15],
@@ -289,7 +324,7 @@ App.UI.Player.syncAgeBasedParameters = function() {
 	V.PC.physicalAge = V.PC.actualAge;
 	V.PC.visualAge = V.PC.actualAge;
 	V.PC.ovaryAge = V.PC.actualAge;
-	V.PC.height = Height.random(V.PC, {limitMult: [1, 2]});
+	V.PC.height = Height.forAge(V.PC.natural.height, V.PC);
 	if (V.PC.genes === "XY") {
 		if (V.PC.physicalAge <= 13) {
 			V.PC.hips = -2;
diff --git a/src/events/nonRandom/pAidResult.js b/src/events/nonRandom/pAidResult.js
index 7882f1e68ce43da45bc76975ffed1ae716fe9df0..b845aa3e6354a187ea14b8a770fa61a0a624ba12 100644
--- a/src/events/nonRandom/pAidResult.js
+++ b/src/events/nonRandom/pAidResult.js
@@ -249,7 +249,8 @@ App.Events.pAidResult = class pAidResult extends App.Events.BaseEvent {
 				slave = GenerateNewSlave("XX", {
 					disableDisability: 1, ageOverridesPedoMode: 1, minAge: 18, maxAge: 18
 				});
-				slave.height = Height.random(slave, {skew: 1, limitMult: [0, 2]});
+				slave.natural.height = Height.randomAdult(slave, {skew: 1, limitMult: [0.5, 2.5]});
+				slave.height = Height.forAge(slave.natural.height, slave);
 				slave.origin = "$He was a volleyball player you enslaved when you evacuated $him from a broken down bus.";
 				slave.career = "a student athlete";
 				generateSalonModifications(slave);
diff --git a/src/events/nonRandom/pSchoolSuggestion.js b/src/events/nonRandom/pSchoolSuggestion.js
index ead7004b8f2f95c516aa6ddf45e527627fe461d7..8af37ebfa4d037394ac77c7179c636280ab5870b 100644
--- a/src/events/nonRandom/pSchoolSuggestion.js
+++ b/src/events/nonRandom/pSchoolSuggestion.js
@@ -17,10 +17,11 @@ App.Events.PSchoolSuggestion = class PSchoolSuggestion extends App.Events.BaseEv
 
 		App.Events.addParagraph(node, [`It seems a young, thin woman in a modern business suit was concluding her own argument when you arrived. "In summation, I propose we offer our support for Nueva Universidad de Libertad," says the woman, who you now realize is a very feminine man. "Nullification may seem extreme, but serves to expand the potential market amongst more... traditional slaveowners," says the man, who you <i>now</i> realize is a woman who merely looks like a very feminine man.`]);
 
-		App.Events.addParagraph(node, [`"I believe what you need in a slave is a good base. As such, The Utopian Orphanage is the best. They offer slaves who were raised with careful attention; they're beautiful, smart, well-educated and unspoiled." The young surgeon continues. "No traumas, a happy childhood, obedient and trusting. You can then mold them to your will as you please; I have enough faith in my skills to achieve the results I desire myself."`]);
-
 		if (V.seeDicks !== 100) {
+			App.Events.addParagraph(node, [`"I believe what you need in a slave is a good base. As such, The Utopian Orphanage is the best. They offer girls who were raised with careful attention; they're beautiful, smart, well-educated and unspoiled." The young surgeon continues. "No traumas, a happy childhood, obedient and trusting. You can then mold them to your will as you please; I have enough faith in my skills to achieve the results I desire myself."`]);
+
 			App.Events.addParagraph(node, [`"The Slave School for me," says a portly man with a thriving slave breaking business down in the markets. "Their girls are pretty, skilled, and innocent, without any of that weird crap the other schools go in for. Besides, all that special stuff drives up the prices. TSS girls are cheap for what you get. When you're tired of one, just buy another." He turns to his friend and business partner, a much thinner man. "Though I'm sure you disagree with me."`]);
+
 			App.Events.addParagraph(node, [`"Of course I do, we've been having this debate every day for ten years." The thin man laughs. "Hasn't hurt our company, though. Anyway, I'm a GRI man. It's much harder to change a girl's body than it is to train her mind. The Growth Research Institute might sell their girls with no training and some nasty flaws, but you can fix those faster than you can grow a well-trained skinny girl's tits out to <i>here</i>," and he gestures far out in front of his own chest.`]);
 
 			App.Events.addParagraph(node, [`An older woman standing across from him sniffs. "St. Claver's knows how to do both. They train them right, and if they aren't perfectly made, well, that's what plastic surgery is for." She favors the group with a sharp smile. "The best part is that between the silicone and their, ahem, strict training, they're all the same. Once you get used to their girls, you can always rely on them to give you more of what you like."`]);
diff --git a/src/events/reRecruit/orphanFemboy.js b/src/events/reRecruit/orphanFemboy.js
index 3224281851eb8294fcc23ad08a4f17acf4d60143..c7c8ca064a44c8e8aa2217b112a0e338f2b4f764 100644
--- a/src/events/reRecruit/orphanFemboy.js
+++ b/src/events/reRecruit/orphanFemboy.js
@@ -73,7 +73,8 @@ App.Events.recOrphanFemboy = class recOrphanFemboy extends App.Events.BaseEvent
 			slave.scrotum = slave.balls;
 			slave.pubicHStyle = "waxed";
 			slave.underArmHStyle = "waxed";
-			slave.height = random(140, 170);
+			slave.natural.height = random(140, 170);
+			slave.height = Height.forAge(slave.natural.height, slave);
 			slave.hips = random(-1, 0);
 			slave.butt = 1;
 			slave.anus = 1;
diff --git a/src/events/reRecruit/racerDgChaser.js b/src/events/reRecruit/racerDgChaser.js
index 06347da66a3ad7dc638aee4b96d741a3612ec738..ab40f18f094331484412fb201a8db1d9b8acadb0 100644
--- a/src/events/reRecruit/racerDgChaser.js
+++ b/src/events/reRecruit/racerDgChaser.js
@@ -74,7 +74,8 @@ App.Events.recRacerDgChaser = class recRacerDgChaser extends App.Events.BaseEven
 			slave.dick = random(4, 5);
 			slave.balls = random(3, 4);
 			slave.scrotum = slave.balls;
-			slave.height = Height.forAge(random(180, 200), slave);
+			slave.natural.height = random(180, 200);
+			slave.height = Height.forAge(slave.natural.height, slave);
 			slave.weight = 0;
 			slave.muscles = 50;
 			slave.intelligence = random(-50, 50);
diff --git a/src/events/reRecruit/racerLoser.js b/src/events/reRecruit/racerLoser.js
index dd73371cc025768fe3fad3550d8b152bd2088462..59e9a315772d5990822e467f8257387439b58ea5 100644
--- a/src/events/reRecruit/racerLoser.js
+++ b/src/events/reRecruit/racerLoser.js
@@ -85,7 +85,8 @@ App.Events.recRacerLoser = class recRacerLoser extends App.Events.BaseEvent {
 			WombImpregnate(slave, slave.pregType, slave.pregSource, 0);
 			slave.pubicHStyle = "waxed";
 			slave.underArmHStyle = "waxed";
-			slave.height = Height.forAge(random(180, 200), slave);
+			slave.natural.height = random(180, 200);
+			slave.height = Height.forAge(slave.natural.height, slave);
 			slave.hips = -1;
 			slave.butt = 0;
 			slave.anus = 0;
diff --git a/src/events/reRecruit/racerWinner.js b/src/events/reRecruit/racerWinner.js
index 7f6fce10e2d4e6554fa7265042981ef848ff8529..911dadacc49bd697ca57da1e3dae8661d196231c 100644
--- a/src/events/reRecruit/racerWinner.js
+++ b/src/events/reRecruit/racerWinner.js
@@ -84,7 +84,8 @@ App.Events.recRacerWinner = class recRacerWinner extends App.Events.BaseEvent {
 			slave.preg = -1;
 			slave.pubicHStyle = "waxed";
 			slave.underArmHStyle = "waxed";
-			slave.height = Height.forAge(random(180, 200), slave);
+			slave.natural.height = random(180, 200);
+			slave.height = Height.forAge(slave.natural.height, slave);
 			slave.shoulders = random(-1, 1);
 			slave.hips = -1;
 			slave.butt = 0;
diff --git a/src/events/reRecruit/starvingArtist.js b/src/events/reRecruit/starvingArtist.js
index 4b62ba3121aa7b07f70b12953d96bc938feace7c..372a873f9ed6f09bbb570fd43e890d52c6a047d5 100644
--- a/src/events/reRecruit/starvingArtist.js
+++ b/src/events/reRecruit/starvingArtist.js
@@ -59,7 +59,8 @@ App.Events.recStarvingArtist = class recStarvingArtist extends App.Events.BaseEv
 			slave.origin = "$He offered $himself to you for enslavement out of devotion to $his artistic 'craft'.";
 			slave.boobs = random(4, 6) * 50;
 			slave.weight = -20;
-			slave.height = Height.forAge(random(160, 200), slave);
+			slave.natural.height = random(160, 200);
+			slave.height = Height.forAge(slave.natural.height, slave);
 			slave.face = random(15, 100);
 			slave.butt = random(1, 2);
 			slave.lips = 0;
diff --git a/src/events/recETS/recetsIncestBrotherBrother.js b/src/events/recETS/recetsIncestBrotherBrother.js
index f32c9036ae9b21ea231589f0d2062833c2d5e8a7..3744891a0881ad67a3ce65f364077e351cbb1fcc 100644
--- a/src/events/recETS/recetsIncestBrotherBrother.js
+++ b/src/events/recETS/recetsIncestBrotherBrother.js
@@ -37,7 +37,6 @@ App.Events.recetsIncestBrotherBrother = class recetsIncestBrotherBrother extends
 		brother1.relationship = 3;
 
 		const brother2 = generateRelatedSlave(brother1, "younger brother");
-		brother2.height += random(-5, 5);
 		brother2.pubicHStyle = "shaved";
 		brother2.dick += 2;
 		brother2.balls += 2;
diff --git a/src/events/recETS/recetsIncestTwinBrother.js b/src/events/recETS/recetsIncestTwinBrother.js
index 8ab785f01258588c744138c8b8ef81215b3bfdfa..c7f204555c0cbd59da0fe394edb8462c9e904f42 100644
--- a/src/events/recETS/recetsIncestTwinBrother.js
+++ b/src/events/recETS/recetsIncestTwinBrother.js
@@ -37,7 +37,6 @@ App.Events.recetsIncestTwinBrother = class recetsIncestTwinBrother extends App.E
 		brother1.relationship = 3;
 
 		const brother2 = generateRelatedSlave(brother1, "twin");
-		brother2.height += random(-5, 5);
 		brother2.energy = Math.max(brother2.energy, 40);
 		brother2.attrXY = Math.max(brother2.attrXY, 70);
 		if (brother2.behavioralFlaw === "hates men") {
diff --git a/src/events/recETS/recetsIncestTwinSister.js b/src/events/recETS/recetsIncestTwinSister.js
index 091551daba1c0aa53aff34f6db38158740bd63df..8ee9b5161889c50dd933b4682e5ab9210895b54b 100644
--- a/src/events/recETS/recetsIncestTwinSister.js
+++ b/src/events/recETS/recetsIncestTwinSister.js
@@ -39,7 +39,6 @@ App.Events.recetsIncestTwinSister = class recetsIncestTwinSister extends App.Eve
 
 		const sis2 = generateRelatedSlave(sis1, "twin");
 		sis2.slaveName = sis2.birthName;
-		sis2.height += random(-5, 5);
 		sis2.energy = Math.max(sis2.energy, 40);
 		sis2.attrXX = Math.max(sis2.attrXX, 70);
 		if (sis2.behavioralFlaw === "hates women") {
diff --git a/src/events/recETS/recetsIncestTwinsMixed.js b/src/events/recETS/recetsIncestTwinsMixed.js
index b8f46f391e77f63a4c5b6854ae8a61af278e4013..6bcb38c8bae197ce47d8ff93ba1bca10b396b7ae 100644
--- a/src/events/recETS/recetsIncestTwinsMixed.js
+++ b/src/events/recETS/recetsIncestTwinsMixed.js
@@ -40,7 +40,6 @@ App.Events.recetsIncestTwinsMixed = class recetsIncestTwinsMixed extends App.Eve
 		sis.relationship = 3;
 
 		const bro = generateRelatedSlave(sis, "twin", true);
-		bro.height += random(-5, 5);
 		bro.vagina = -1;
 		bro.dick = 2;
 		bro.foreskin = 2;
diff --git a/src/events/recFS/recfsPetiteAdmiration.js b/src/events/recFS/recfsPetiteAdmiration.js
index c016347525bcdf4ff3badbea79524b455ee4740e..5d7e091ed0c7b3fc874eddb4261f8f59252d7e32 100644
--- a/src/events/recFS/recfsPetiteAdmiration.js
+++ b/src/events/recFS/recfsPetiteAdmiration.js
@@ -11,15 +11,16 @@ App.Events.recFSPetiteAdmiration = class recFSPetiteAdmiration extends App.Event
 		const slave = GenerateNewSlave(null, {minAge: 13, maxAge: 22, disableDisability: 1});
 		generateSalonModifications(slave);
 		slave.origin = "$He offered $himself for voluntary enslavement to avoid being singled out by ruthless slavers.";
-		if (slave.height >= Height.forAge(150, slave)) {
-			slave.height = Height.random(slave, {limitMult: [-2, 0]});
-			if (slave.height >= Height.forAge(150, slave)) {
-				slave.height = Height.random(slave, {limitMult: [-3, -1]});
-				if (slave.height >= Height.forAge(150, slave)) {
-					slave.height = Height.forAge(random(90, 130), slave);
+		if (slave.natural.height >= 150) {
+			slave.natural.height = Height.randomAdult(slave, {limitMult: [-2, 0]});
+			if (slave.natural.height >= 150) {
+				slave.natural.height = Height.randomAdult(slave, {limitMult: [-3, -1]});
+				if (slave.natural.height >= 150) {
+					slave.natural.height = random(90, 130);
 					slave.geneticQuirks.dwarfism = 2;
 				}
 			}
+			slave.height = Height.forAge(slave.natural.height, slave);
 		}
 		setHealth(slave, jsRandom(20, 40), undefined, undefined, 0, 0);
 		slave.face = Math.clamp(slave.face+80, -100, 100);
diff --git a/src/events/recFS/recfsPetiteAdmirationTwo.js b/src/events/recFS/recfsPetiteAdmirationTwo.js
index 4f1bf7ca5f1b82ed6de92bec910e359724b97b21..294e55743373d75de419f2f9d983a8cb55f171e7 100644
--- a/src/events/recFS/recfsPetiteAdmirationTwo.js
+++ b/src/events/recFS/recfsPetiteAdmirationTwo.js
@@ -20,7 +20,8 @@ App.Events.recFSPetiteAdmirationTwo = class recFSPetiteAdmirationTwo extends App
 		slave.career = "a porn star";
 		generateSalonModifications(slave);
 		slave.origin = "$He offered $himself to you for enslavement because $he felt your arcology would be a nice place to retire to.";
-		slave.height = random(90, 100);
+		slave.natural.height = random(90, 100);
+		slave.height = slave.natural.height;
 		slave.geneticQuirks.dwarfism = 2;
 		slave.boobsImplant += random(4, 6)*200;
 		slave.boobs += slave.boobsImplant;
diff --git a/src/events/recFS/recfsSlimnessEnthusiast.js b/src/events/recFS/recfsSlimnessEnthusiast.js
index 64dd26301cde6c9690bacb209ee0b893e2f0c46a..c0a04697fd137ec2c6e9ed2ac641fe61ece3f7c1 100644
--- a/src/events/recFS/recfsSlimnessEnthusiast.js
+++ b/src/events/recFS/recfsSlimnessEnthusiast.js
@@ -22,7 +22,8 @@ App.Events.recFSSlimnessEnthusiast = class recFSSlimnessEnthusiast extends App.E
 		slave.origin = "$He offered $himself to you for enslavement because $he felt your arcology was the best place for a $woman of $his appearance.";
 		slave.boobs = random(4, 6)*50;
 		slave.weight = -20;
-		slave.height = random(160, 200);
+		slave.natural.height = random(160, 200);
+		slave.height = slave.natural.height;
 		slave.face = random(15, 100);
 		slave.butt = random(1, 2);
 		slave.lips = 0;
diff --git a/src/events/recFS/recfsSlimnessEnthusiastTwo.js b/src/events/recFS/recfsSlimnessEnthusiastTwo.js
index 069960a74a3c6b3161e1a9becf47878c717950da..b8660fa09b4136981c7458db1661ad014680c565 100644
--- a/src/events/recFS/recfsSlimnessEnthusiastTwo.js
+++ b/src/events/recFS/recfsSlimnessEnthusiastTwo.js
@@ -13,7 +13,8 @@ App.Events.recFSSlimnessEnthusiastTwo = class recFSSlimnessEnthusiastTwo extends
 		slave.origin = "$He offered $himself to you for enslavement to escape having plastic surgery foisted on $him.";
 		slave.boobs = random(4, 6)*50;
 		slave.weight = -20;
-		slave.height = random(160, 200);
+		slave.natural.height = random(160, 200);
+		slave.height = slave.natural.height;
 		slave.face = random(15, 100);
 		slave.butt = random(1, 2);
 		slave.lips = 0;
diff --git a/src/events/recFS/recfsStatuesqueGlorification.js b/src/events/recFS/recfsStatuesqueGlorification.js
index a8701cd3b7b499207e9c4cdb148589c803017a85..9e22ea676caa876e6e0547bf9a5cd610d6abb3bd 100644
--- a/src/events/recFS/recfsStatuesqueGlorification.js
+++ b/src/events/recFS/recfsStatuesqueGlorification.js
@@ -18,7 +18,8 @@ App.Events.recFSStatuesqueGlorification = class recFSStatuesqueGlorification ext
 		const slave = GenerateNewSlave(null, {disableDisability: 1});
 		generateSalonModifications(slave);
 		slave.origin = "$He offered $himself for voluntary enslavement to avoid being singled out by ruthless slavers.";
-		slave.height = Height.forAge(random(200, 264), slave);
+		slave.natural.height = random(200, 264);
+		slave.height = Height.forAge(slave.natural.height, slave);
 		setHealth(slave, jsRandom(20, 40), undefined, undefined, 0, 0);
 		slave.geneticQuirks.gigantism = 2;
 		slave.devotion = random(15, 20);
diff --git a/src/events/recFS/recfsStatuesqueGlorificationTwo.js b/src/events/recFS/recfsStatuesqueGlorificationTwo.js
index 7ba3ebf7ab06a76a9aae4573ac6d916ec1635587..dfd7bcefebbdd31d290b0cde529092d8a6d5afcb 100644
--- a/src/events/recFS/recfsStatuesqueGlorificationTwo.js
+++ b/src/events/recFS/recfsStatuesqueGlorificationTwo.js
@@ -10,7 +10,8 @@ App.Events.recFSStatuesqueGlorificationTwo = class recFSStatuesqueGlorificationT
 		let r = [];
 		const slave = GenerateNewSlave(null, {disableDisability: 1});
 		slave.origin = "$He offered $himself for voluntary enslavement knowing $he would only fit in with your help.";
-		slave.height = 165;
+		slave.natural.height = 165;
+		slave.height = Height.forAge(slave.natural.height, slave);
 		setHealth(slave, jsRandom(20, 40), undefined, undefined, 0, 0);
 		slave.shoes = "extreme heels";
 		slave.devotion = random(30, 45);
diff --git a/src/events/scheduled/assholeKnight.js b/src/events/scheduled/assholeKnight.js
index 98014450cd255ce3def4a3e0de6e0eeefd78d4ce..77123c11534d50412c50298f47abb69514402b0d 100644
--- a/src/events/scheduled/assholeKnight.js
+++ b/src/events/scheduled/assholeKnight.js
@@ -23,7 +23,8 @@ App.Events.SEAssholeKnight = class SEAssholeKnight extends App.Events.BaseEvent
 		assholeKnight.behavioralQuirk = "none";
 		assholeKnight.trust = random(-30, -20);
 		assholeKnight.butt = random(0, 1);
-		assholeKnight.height = random(175, 195);
+		assholeKnight.natural.height = random(175, 195);
+		assholeKnight.height = assholeKnight.natural.height;
 		assholeKnight.fetish = "sadist";
 		assholeKnight.fetishStrength = 80;
 		assholeKnight.preg = 0;
diff --git a/src/events/scheduled/pitFight.js b/src/events/scheduled/pitFight.js
index e8675c43d9a40a1230886706be4df1913461466c..56e29514dce1d7e9fb274f63acfb864a3a7ff995 100644
--- a/src/events/scheduled/pitFight.js
+++ b/src/events/scheduled/pitFight.js
@@ -2,122 +2,339 @@ App.Events.SEPitFight = class SEPitFight extends App.Events.BaseEvent {
 	eventPrerequisites() {
 		return [
 			() => !!V.pit,
+			() => V.pit.active,
 			() => !V.pit.fought,
 		];
 	}
 
-	castActors() {
-		const available = [...new Set(V.pit.fighterIDs)];
+	/** @param {DocumentFragment} node */
+	execute(node) {
+		V.pit.fought = true;
+		V.nextButton = " ";
+
+		node.append(intro());
+
+		const maxFights = 3 + (V.pit.fightsBase * 2);
+		let completedFights = 0;
+		let totalSuccess = 0;
+		let lethalFights = 0;
+
+		const fighterMap = new App.Facilities.Pit.Fights.FighterMap();
+
+		const interactionSpan = document.createElement("span");
+		interactionSpan.append(selectFight());
+		node.append(interactionSpan);
+
+		function selectFight() {
+			const f = new DocumentFragment();
+
+			App.Events.addParagraph(f, [`Select a fight. You have ${maxFights - completedFights} left.`]);
 
-		if (available.length > 0) {
-			this.actors = getFighters(V.pit.fighters).filter(f => !!f);
+			const availableFights = App.Facilities.Pit.getFights()
+				.filter(f => f.fightPrerequisites().every(p => p()) && f.castActors());
 
-			return this.actors.length > 1 || !!V.pit.slaveFightingAnimal;
+			const choices = [];
+			for (const fight of availableFights) {
+				App.UI.DOM.appendNewElement("div", f, fight.fightDescription());
+				const div = document.createElement("div");
+				div.classList.add("indent");
+				div.append(App.UI.DOM.link("Fight!", () => runFight(fight)));
+				div.append(" Impact: ", expectedImpact(fight.impact), " ");
+				if (fight.lethal) {
+					App.UI.DOM.appendNewElement("span", div, "Lethal", "warning");
+				} else {
+					App.UI.DOM.appendNewElement("span", div, "Safe", "green");
+				}
+				for (const si of fight.actors) {
+					const count = fighterMap.fightCount(si);
+					if (count > 0) {
+						div.append(" ");
+						const span = document.createElement("span");
+						span.classList.add("orange");
+
+						span.append(getSlave(si).slaveName, " already fought ");
+						if (count > 1) {
+							span.append(count + " times today.");
+						} else {
+							span.append("once today.");
+						}
+
+						div.append(span);
+					}
+				}
+				f.append(div);
+			}
+			if (availableFights.length === 0) {
+				App.UI.DOM.appendNewElement("div", f, "No fights available");
+			}
+			App.UI.DOM.appendNewElement("div", f, App.UI.DOM.link("Select different fighters", () => refreshInteractionSpan(selectFight())));
+			App.UI.DOM.appendNewElement("div", f, App.UI.DOM.link("Head back to the penthouse and cancel all the remaining fights", () => refreshInteractionSpan(finishEvent())));
+			App.Events.addResponses(f, choices);
+
+			return f;
 		}
 
-		return false; // couldn't cast second fighter
+		/**
+		 * @param {DocumentFragment|HTMLElement} content
+		 */
+		function refreshInteractionSpan(content) {
+			$(interactionSpan).empty().append(content);
+		}
 
 		/**
-		 * @param {number} setting
-		 * @returns {Array<number>} slave IDs
+		 * @param {number} impact
+		 * @returns {string}
 		 */
-		function getFighters(setting) {
-			if (V.pit.slaveFightingAnimal || V.pit.slaveFightingBodyguard) {
-				return getScheduledFight();
+		function expectedImpact(impact) {
+			if (impact === 0) {
+				return "None";
+			} else if (impact < 0.8) {
+				return "Small";
+			} else if (impact < 1.5) {
+				return "Average";
+			} else if (impact < 8) {
+				return "High";
+			} else {
+				return "Very High";
 			}
-			if (setting === 4) {
-				return getSpecificFight();
+		}
+
+		/**
+		 * @param {App.Facilities.Pit.Fights.BaseFight} fight
+		 */
+		function runFight(fight) {
+			const f = new DocumentFragment();
+			App.UI.DOM.appendNewElement("span", f, `The ${ordinalSuffixWords(completedFights + 1)} fight this day:`, "bold");
+			const success = fight.execute(f, fighterMap);
+			for (const si of fight.actors) {
+				fighterMap.addFight(si);
 			}
-			if (setting === 3) {
-				return getRandomFight();
+			const impact = success * fight.impact;
+			const p = document.createElement("p");
+			p.append(fightSuccess(success), " ", fightImpact(impact));
+			f.append(p);
+			totalSuccess += impact;
+			completedFights++;
+			if (fight.lethal) {
+				lethalFights++;
 			}
-			if (setting === 2) {
-				return getAnimalFight();
+
+			if (completedFights < maxFights) {
+				f.append(selectFight());
+			} else {
+				f.append(finishEvent());
 			}
-			if (setting === 1) {
-				return getBodyguardFight();
+
+			// automatically scroll to the top of the fight.
+			setTimeout(() => window.scrollTo(0, 0), 0);
+
+			refreshInteractionSpan(f);
+		}
+
+		/**
+		 * @param {number} success
+		 * @returns {DocumentFragment}
+		 */
+		function fightSuccess(success) {
+			const f = new DocumentFragment();
+
+			if (success < 0) {
+				f.append("The fight was an embarrassment.");
+			} else if (success === 0) {
+				f.append("The fight had no success.");
+			} else if (success < 0.2) {
+				f.append("The fight had little success.");
+			} else if (success < 0.8) {
+				f.append("The fight had normal success.");
+			} else if (success <= 1) {
+				f.append("The fight had good success.");
+			} else {
+				f.append("The fight had unexpectedly high success.");
+			}
+
+			return f;
+		}
+
+		/**
+		 * @param {number} impact
+		 * @returns {DocumentFragment}
+		 */
+		function fightImpact(impact) {
+			const f = new DocumentFragment();
+
+			impact = Math.abs(impact);
+
+			if (impact === 0) {
+				f.append("The fight had no impact on the total event.");
+			} else if (impact < 0.2) {
+				f.append("The fight had little impact on the total event.");
+			} else if (impact < 0.8) {
+				f.append("The fight had normal impact on the total event.");
+			} else if (impact < 2) {
+				f.append("The fight had high impact on the total event.");
+			} else {
+				f.append("The fight had extreme impact on the total event.");
 			}
-			if (setting === 0) {
-				return getSlavesFight();
+
+			return f;
+		}
+
+		/**
+		 * @param {number} success
+		 * @returns {string}
+		 */
+		function eventSuccess(success) {
+			if (success < 0) {
+				return "The event was an embarrassment.";
+			} else if (success === 0) {
+				return "The event had no success.";
+			} else if (success < 0.2) {
+				return "The event had little success.";
+			} else if (success < 0.8) {
+				return "The event had normal success.";
+			} else if (success < 1.1) {
+				return "The event had high success.";
+			} else {
+				return "The event had extremely high success.";
 			}
+		}
 
-			return [];
+		function intro() {
+			let r = [];
+			if (V.pit.audience === "none") {
+				r.push(`You are alone above the pit, left to watch them square off in private.`);
+				return r[0];
+			} else if (V.pit.audience === "free") {
+				r.push(`Your guests line the rim of the pit, joking and betting.`);
+			} else {
+				r.push(`The attendees line the rim of the pit, betting and arguing.`);
+			}
 
-			function getScheduledFight() {
-				if (V.pit.slaveFightingAnimal) {
-					return [V.pit.slaveFightingAnimal];
-				}
-				if (V.pit.slaveFightingBodyguard) {
-					return [V.pit.slaveFightingBodyguard, S.Bodyguard.ID];
-				}
+			if (V.pit.lethal === 1) {
+				r.push("They expect to see a mix of lethal and nonlethal fights.");
 			}
 
-			function getSpecificFight() {
-				if (V.pit.slavesFighting.length > 1 &&
-					V.pit.slavesFighting.every(a => available.includes(a) && canFight(getSlave(a)))) {
-					return V.pit.slavesFighting.slice(0, 2);	// cut the array off at 2 items in case it was somehow longer
-				}
-				return [];
+			if (V.arcologies[0].FSRomanRevivalist !== "unset") {
+				r.push(`They `, App.UI.DOM.makeElement("span", 'strongly approve', ["reputation",
+					"inc"]), ` of your hosting combat between slaves; this advances ideas from antiquity about what public events should be.`);
+
+				repX(10 * V.FSSingleSlaveRep * (V.arcologies[0].FSRomanRevivalist / V.FSLockinLevel), "pit");
+				V.arcologies[0].FSRomanRevivalist += (0.2 * V.FSSingleSlaveRep);
 			}
 
-			function getRandomFight() {
-				const fightDelegates = [];
+			if (V.pit.minimumHealth) {
+				if (V.arcologies[0].FSPaternalist !== "unset") {
+					r.push(`They `, App.UI.DOM.makeElement("span", 'strongly approve', ["reputation",
+						"inc"]), ` of restricting fights to healthy slaves; this advances ideas about slave well-being.`);
 
-				if (V.active.canine || V.active.hooved || V.active.feline) {
-					fightDelegates.push(getAnimalFight);
-				}
-				if (S.Bodyguard) {
-					fightDelegates.push(getBodyguardFight);
+					repX(10 * V.FSSingleSlaveRep * (V.arcologies[0].FSPaternalist / V.FSLockinLevel), "pit");
+					V.arcologies[0].FSPaternalist += (0.2 * V.FSSingleSlaveRep);
+				} else if (V.arcologies[0].FSDegradationist !== "unset") {
+					r.push(`They `, App.UI.DOM.makeElement("span", 'strongly disapprove', ["reputation",
+						"dec"]), ` of restricting fights to healthy slaves; this hampers ideas about slave degradation.`);
+
+					repX(-10 * V.FSSingleSlaveRep * (V.arcologies[0].FSDegradationist / V.FSLockinLevel), "pit");
+					V.arcologies[0].FSDegradationist -= (0.2 * V.FSSingleSlaveRep);
 				}
-				if (available.length > 1) {
-					fightDelegates.push(getSlavesFight);
+			} else {
+				if (V.arcologies[0].FSPaternalist !== "unset") {
+					r.push(`They `, App.UI.DOM.makeElement("span", 'strongly disapprove', ["reputation",
+						"dec"]), ` of allowing ill slaves to fight; this hampers ideas about slave well-being.`);
+
+					repX(-10 * V.FSSingleSlaveRep * (V.arcologies[0].FSPaternalist / V.FSLockinLevel), "pit");
+					V.arcologies[0].FSPaternalist -= (0.2 * V.FSSingleSlaveRep);
+				} else if (V.arcologies[0].FSDegradationist !== "unset") {
+					r.push(`They `, App.UI.DOM.makeElement("span", 'strongly approve', ["reputation",
+						"inc"]), ` of allowing ill slaves to fight; this advances ideas about slave degradation.`);
+
+					repX(10 * V.FSSingleSlaveRep * (V.arcologies[0].FSDegradationist / V.FSLockinLevel), "pit");
+					V.arcologies[0].FSDegradationist += (0.2 * V.FSSingleSlaveRep);
 				}
+			}
+
+			const f = new DocumentFragment();
+			App.Events.addParagraph(f, r);
+			return f;
+		}
+
+		function finishEvent() {
+			const r = [];
+			V.nextButton = "Continue";
 
-				return fightDelegates.length > 0 ? (fightDelegates.random())() : [];
+			if (V.pit.audience === "none") {
+				return new DocumentFragment();
 			}
 
-			function getAnimalFight() {
-				if ((!V.active.canine && !V.active.hooved && !V.active.feline) ||
-					((!V.active.canine && !V.active.hooved && V.active.feline && getAnimal(V.active.feline).species === "cat"))) {
-					return getSlavesFight();
-				}
-				const fighter = available.pluck();
-				V.pit.slaveFightingAnimal = fighter;
+			if (completedFights === 0) {
+				r.push("Opening the arena without hosting fights <span class='reputation dec'>hurt your reputation.</span>");
+				repX(-100 * maxFights, "pit");
+				const f = new DocumentFragment();
+				App.Events.addParagraph(f, r);
+				return f;
+			}
 
-				return [fighter];
+			if (completedFights < maxFights) {
+				r.push("The audience is disappointed in the few fights this week.");
+				totalSuccess -= (maxFights - completedFights) * 0.2;
 			}
 
-			function getBodyguardFight() {
-				if (!S.Bodyguard) { return getSlavesFight(); }
-				if (available.includes(S.Bodyguard.ID)) {
-					available.delete(S.Bodyguard.ID);
+			if (V.pit.lethal === 1) {
+				if (lethalFights === 0) {
+					r.push("The audience expected to see blood and did not get any.");
+					totalSuccess -= 0.1 * Math.abs(totalSuccess);
+				} else if (lethalFights === completedFights) {
+					r.push("The audience only saw blood today and is missing some other outcomes.");
+					totalSuccess -= 0.1 * Math.abs(totalSuccess);
 				}
-				return [available.pluck(), S.Bodyguard.ID];
 			}
 
-			function getSlavesFight() {
-				return [available.pluck(), available.pluck()];
+			const fighterRatio = fighterMap.fighterCount() / fighterMap.fightsCount();
+			if (fighterRatio > 0.95) {
+				r.push("The audience is <span class='green'>happy</span> seeing a lot of different fighters.");
+				totalSuccess *= 1.1;
+			} else if (fighterRatio > 0.8) {
+				// no reaction
+			} else {
+				if (fighterRatio > 0.5) {
+					r.push("The audience is <span class='red'>unhappy</span> seeing a lot the same fighters.");
+				} else {
+					r.push("Almost every fight had repeat fighters, <span class='red'>boring</span> the audience.");
+				}
+				totalSuccess *= 0.5 + 0.5 * (fighterRatio + 0.1);
 			}
 
-			/** @param {App.Entity.SlaveState} slave */
-			function canFight(slave) {
-				if (!canWalk(slave)) {
-					return false;
-				}
+			totalSuccess *= 0.5 + 0.5 * V.pit.seats;
+			if (V.pit.seats === 0) {
+				r.push("The small visitors section <span class='red'>limited</span> the impact today's fights had.");
+			} else if (V.pit.seats === 2) {
+				r.push("The large visitors section <span class='green'>greatly enhanced</span> the impact today's fights had.");
+			}
+
+			const averageSuccess = totalSuccess / maxFights;
+			r.push(eventSuccess(averageSuccess));
 
-				return true;
+			r.push("At the and of the day you");
+
+			const repGain = 100 * totalSuccess;
+			const cashGain = 2000 * totalSuccess;
+			const direction = totalSuccess > 0 ? "gained" : "lost";
+			const cssDir = totalSuccess > 0 ? "inc" : "dec";
+			if (V.pit.audience === "free") {
+				r.push(`<span class='reputation ${cssDir}'>${direction} reputation.</span>`);
+				repX(repGain, "pit");
+			} else if (V.pit.audience === "paid") {
+				r.push(`<span class='cash ${cssDir}'>${direction} credits.</span>`);
+				cashX(cashGain, "pit");
 			}
-		}
-	}
 
-	/** @param {DocumentFragment} node */
-	execute(node) {
-		V.pit.fought = true;
+			console.log("PIT:");
+			console.log("total success:", totalSuccess, "avg:", averageSuccess);
+			console.log("possible rep gain: ", repGain);
+			console.log("possible cash gain:", cashGain);
 
-		if (V.pit.lethal) {
-			node.append(App.Facilities.Pit.lethalFight(this.actors));
-		} else {
-			node.append(App.Facilities.Pit.nonlethalFight(this.actors));
+			const f = new DocumentFragment();
+			App.Events.addParagraph(f, r);
+			return f;
 		}
 	}
 };
diff --git a/src/events/scheduled/pitFightLethal.js b/src/events/scheduled/pitFightLethal.js
deleted file mode 100644
index 7646a0e98ab5ee3b9757d6f75264fdfbe500a181..0000000000000000000000000000000000000000
--- a/src/events/scheduled/pitFightLethal.js
+++ /dev/null
@@ -1,862 +0,0 @@
-// TODO: add devotion and trust effects to animal variant
-App.Facilities.Pit.lethalFight = function(fighters) {
-	const frag = new DocumentFragment();
-
-	const animals = [];
-	/** @type {FC.AnimalState} */
-	let animal = null;
-
-	if (V.active.canine) {
-		animals.push(V.active.canine);
-	}
-	if (V.active.hooved) {
-		animals.push(V.active.hooved);
-	}
-	if (V.active.feline) {
-		animals.push(V.active.feline);
-	}
-
-	if (V.pit.fighters === 2 || V.pit.slaveFightingAnimal) {
-		animal = V.pit.animal === 'random'
-			? getAnimal(animals.random())
-			: getAnimal(V.pit.animal);
-	}
-
-	let winner;
-	let loser;
-
-	if (animal) {
-		winner = getWinner() ? getSlave(fighters[0]) : animal;
-		loser = winner.hasOwnProperty('species') ? getSlave(fighters[0]) : animal;
-	} else {
-		winner = getWinner() ? getSlave(fighters[0]) : getSlave(fighters[1]);
-		loser = winner.ID === fighters[0] ? getSlave(fighters[1]) : getSlave(fighters[0]);
-	}
-
-	if (V.debugMode) {
-		console.log(winner, loser, animal);
-	}
-
-	intro(frag);
-	fighterDeadliness(frag, getSlave(fighters[0]));
-	if (!animal) {
-		fighterDeadliness(frag, getSlave(fighters[1]));
-	}
-	fight(frag);
-	postFight(frag);
-
-	V.pit.slaveFightingBodyguard = null;
-	V.pit.slaveFightingAnimal = null;
-	V.pit.slavesFighting = [];
-
-	return frag;
-
-	/** @param {DocumentFragment} parent */
-	function intro(parent) {
-		const fighterOne = getSlave(fighters[0]);
-		const fighterTwo = getSlave(fighters[1]) || null;
-
-		if (V.debugMode) {
-			console.log(fighterOne, fighterTwo);
-		}
-
-		const r = [];
-
-		App.Events.drawEventArt(parent, fighters.map(id => getSlave(id)), "no clothing");
-
-		const anAnimal = animal ? `${animal.articleAn} ${animal.name}.` : null;
-
-		r.push(`This week's fight is between`,
-			App.UI.DOM.slaveDescriptionDialog(fighterOne), `and`,
-			animal
-				? anAnimal
-				: App.UI.DOM.combineNodes(contextualIntro(fighterOne, fighterTwo, true), "."));
-
-		if (V.pit.audience === "none") {
-			r.push(`You are alone above the pit, left to watch them kill and die in private.`);
-		} else if (V.pit.audience === "free") {
-			r.push(`Your guests line the rim of the pit, joking and betting, nervous and excited by the close prospect of watching a slave die.`);
-		} else {
-			r.push(`The attendees line the rim of the pit, betting and arguing, nervous and excited by the close prospect of watching a slave die.`);
-		}
-
-		if (V.arcologies[0].FSRomanRevivalist !== "unset") {
-			r.push(`They `, App.UI.DOM.makeElement("span", `passionately approve`, ['reputation', 'inc']), ` of your hosting lethal combat between slaves; this advances ideas from antiquity about what public events should be.`);
-
-			repX(20 * V.FSSingleSlaveRep * (V.arcologies[0].FSRomanRevivalist / V.FSLockinLevel), "pit");
-			V.arcologies[0].FSRomanRevivalist += (0.4 * V.FSSingleSlaveRep);
-		} else if (V.arcologies[0].FSAztecRevivalist !== "unset") {
-			r.push(`They `, App.UI.DOM.makeElement("span", `approve`, ['reputation', 'inc']), ` of your hosting lethal combat; this advances ideas that blood must flow as it did in ancient times.`);
-
-			repX(10 * V.FSSingleSlaveRep * (V.arcologies[0].FSAztecRevivalist / V.FSLockinLevel), "pit");
-			V.arcologies[0].FSAztecRevivalist += (0.2 * V.FSSingleSlaveRep);
-		}
-
-		if (animal) {
-			const slave = getSlave(fighters[0]);
-			const {he, him, his} = getPronouns(slave);
-
-			r.push(`You review the rules — the slave will use ${his} choice of swords, and the fight will be to the death. If ${he} wins, ${he} will earn two complete days of rest, not to mention continued life. You take a moment to look over ${fighterOne.slaveName} one more time before giving the word. After all, it might be the last time you'll see ${him} alive.`);
-		} else {
-			r.push(`You review the rules — the combatants will use their choice of swords, and the fight will be to the death, with both fighters executed if no decision is reached. The winner will earn two complete days of rest, not to mention continued life. You take a moment to look over your fighters one more time before giving the word. After all, this is likely the last time you'll see one of them alive.`);
-		}
-
-		App.Events.addParagraph(parent, r);
-	}
-
-	/**
-	 * @param {DocumentFragment} parent
-	 * @param {App.Entity.SlaveState} fighter
-	 */
-	function fighterDeadliness(parent, fighter) {
-		const {he, his, him, himself, He, His} = getPronouns(fighter);
-		const fighterDeadliness = deadliness(fighter).value;
-
-		const r = [];
-
-		r.push(
-			confidence(),
-			willingness(),
-			skill(),
-			age(),
-			muscles(),
-			height(),
-			health(),
-			weight(),
-			tired(),
-			pregnancy(),
-			labor(),
-			bellyFluid(),
-			sight(),
-			hearing(),
-			prosthetics(),
-		);
-
-		App.Events.addParagraph(parent, r);
-
-		function confidence() {
-			if (fighter.fetish === Fetish.MINDBROKEN) {
-				return `${fighter.slaveName} is too broken to care about whether ${he} lives or dies;`;
-			} else if (fighterDeadliness > 5) {
-				return `${fighter.slaveName} seems very confident;`;
-			} else if (fighterDeadliness > 3) {
-				return `${fighter.slaveName} seems nervous, but steels ${himself};`;
-			} else if (fighterDeadliness > 1) {
-				return `${fighter.slaveName} seems hesitant and unsure;`;
-			} else {
-				return `${fighter.slaveName} is obviously terrified, and might flee if there were a way out of the pit;`;
-			}
-		}
-
-		function willingness() {
-			if (fighter.fetish === Fetish.MINDBROKEN) {
-				return `${he} is indifferent to the prospect of killing, as well.`;
-			} else if (fighter.devotion > 95) {
-				return `${he} is clearly willing to do ${his} best to kill for you.`;
-			} else if (fighter.fetish === "sadist" && fighter.fetishKnown && fighter.fetishStrength > 60) {
-				return `the prospect of killing does not seem to concern ${him}.`;
-			} else if (fighter.devotion > 50) {
-				return `${he} obviously does not want to kill, but will do as you order.`;
-			} else if (fighter.devotion > -20) {
-				return `${he} is clearly unhappy at the prospect of killing, but knows that the alternative is death.`;
-			} else {
-				return `${he} knows that it's kill or be killed, and puts aside ${his} hatred of you in an effort to live.`;
-			}
-		}
-
-		function skill() {
-			if (fighter.skill.combat > 30) {
-				return `${His} grip on ${his} sword is sure and easy.`;
-			}
-		}
-
-		function age() {
-			if (V.AgePenalty !== 0) {
-				if (fighter.physicalAge >= 100) {
-					return `${He} seems prepared for death, in a way.`;
-				} else if (fighter.physicalAge >= 85) {
-					return `${He} tries not to waste ${his} strength before the fight, knowing that ${his} extreme age won't allow ${him} a second wind.`;
-				} else if (fighter.physicalAge >= 70) {
-					return `${He} steadies ${himself} as well as ${he} can in ${his} advanced age.`;
-				}
-			}
-		}
-
-		function muscles() {
-			if (fighter.muscles > 95) {
-				return `${He} is wielding a massive two-handed blade few others could even heft.`;
-			} else if (fighter.muscles > 30) {
-				return `${He} is strong enough to handle a bastard sword.`;
-			} else if (fighter.muscles > 5) {
-				return `${He} has selected a longsword suited to ${his} strength.`;
-			} else if (fighter.muscles < -95) {
-				return `${He} has selected a meager dagger; even then ${he} can barely wield it.`;
-			} else if (fighter.muscles < -30) {
-				return `${He} has selected a dagger, the heaviest weapon ${he} can manage.`;
-			} else if (fighter.muscles < -5) {
-				return `${He} has selected a short sword, despite being able to barely lift it.`;
-			} else {
-				return `${He} has selected a short sword, the heaviest weapon ${he} can manage.`;
-			}
-		}
-
-		function height() {
-			if (fighter.height > 170) {
-				return `${His} height gives ${him} a reach advantage.`;
-			}
-		}
-
-		function health() {
-			if (fighter.health.condition > 50) {
-				return `${His} shining health makes ${him} a better fighter.`;
-			} else if (fighter.health.condition) {
-				return `${His} poor health makes ${him} a weaker combatant.`;
-			}
-		}
-
-		function weight() {
-			if (fighter.weight > 190) {
-				return `${His} extreme weight nearly immobilizes ${him}. ${He} struggles to move let alone fight.`;
-			} else if (fighter.weight > 160) {
-				return `${His} extreme weight limits ${his} mobility and range of motion, making ${him} an easy target.`;
-			} else if (fighter.weight > 130) {
-				return `${His} extreme weight holds ${him} back as a pit fighter.`;
-			} else if (fighter.weight > 30) {
-				return `${His} heavy weight is an impediment as a pit fighter.`;
-			} else if (fighter.weight < -10) {
-				return `${His} light weight is an impediment as a pit fighter.`;
-			}
-		}
-
-		function tired() {
-			if (fighter.health.tired > 90) {
-				return `${He} is exhausted and can barely stay awake; ${he} won't put up a fight.`;
-			} else if (fighter.health.tired > 60) {
-				return `${He} is fatigued, sapping the strength ${he}'ll need to strike true.`;
-			} else if (fighter.health.tired > 30) {
-				return `${He} is tired and more likely to take a hit than to give one.`;
-			}
-		}
-
-		function pregnancy() {
-			if (fighter.pregKnown || fighter.bellyPreg > 1500) {
-				if (fighter.bellyPreg > 750000) {
-					return `${His} monolithic pregnancy guarantees ${his} and ${his} many, many children's deaths; not only is ${he} on the verge of splitting open, but it is an unmissable, indefensible target. ${He} has no hope of attacking around the straining mass, let alone stopping ${his} opponent. ${He} is damned.`;
-				} else if (fighter.bellyPreg > 600000) {
-					return `${His} titanic pregnancy is practically a death sentence; not only does ${he} risk bursting, but it is an unmissable, indefensible target. ${He} can barely keep it together while thinking about the lives of ${his} brood.`;
-				} else if (fighter.bellyPreg > 450000) {
-					return `${His} gigantic pregnancy practically damns ${him}; it presents an unmissable, indefensible target for ${his} adversary. ${He} can barely keep it together while thinking about the lives of ${his} brood.`;
-				} else if (fighter.bellyPreg > 300000) {
-					return `${His} massive pregnancy obstructs ${his} movement and greatly hinders ${him}. ${He} struggles to think of how ${he} could even begin to defend it from harm.`;
-				} else if (fighter.bellyPreg > 150000) {
-					return `${His} giant pregnancy obstructs ${his} movement and greatly slows ${him} down. ${He} tries not to think of how many lives are depending on ${him}.`;
-				} else if (fighter.bellyPreg > 100000) {
-					return `${His} giant belly gets in ${his} way and weighs ${him} down. ${He} is terrified for the lives of ${his} many children.`;
-				} else if (fighter.bellyPreg > 10000) {
-					return `${His} huge belly gets in ${his} way and weighs ${him} down. ${He} is terrified for the ${fighter.pregType > 1 ? `lives of ${his} children` : `life of ${his} child`}.`;
-				} else if (fighter.bellyPreg > 5000) {
-					return `${His} advanced pregnancy makes ${him} much less effective, not to mention terrified for ${his} child${fighter.pregType > 1 ? `ren` : ``}.`;
-				} else if (fighter.bellyPreg > 1500) {
-					return `${His} growing pregnancy distracts ${him} with concern over the life growing within ${him}.`;
-				} else {
-					return `The life just beginning to grow inside ${him} distracts ${him} from the fight.`;
-				}
-			} else if (fighter.bellyImplant > 1500) {
-				if (fighter.bellyImplant > 750000) {
-					return `${His} monolithic, ${fighter.bellyImplant}cc implant-filled belly guarantees ${his} death; not only is ${he} on the verge of splitting open, but it is an unmissable, indefensible target that threatens to drag ${him} to the ground. ${He} has no hope of attacking around the straining mass, let alone stopping ${his} opponent.`;
-				} else if (fighter.bellyImplant > 600000) {
-					return `${His} titanic, ${fighter.bellyImplant}cc implant-filled belly is practically a guaranteed death; ${he} can barely stand let alone fight. Not only is it cripplingly heavy, unwieldy and an easy target, but ${he} can feel it straining to hold the sheer amount of filler forced into it.`;
-				} else if (fighter.bellyImplant > 450000) {
-					return `${His} gigantic, ${fighter.bellyImplant}cc implant-filled belly is nearly a guaranteed death; it presents an unmissable, indefensible target for ${his} adversary.`;
-				} else if (fighter.bellyImplant > 300000) {
-					return `${His} massive, ${fighter.bellyImplant}cc implant-filled belly is extremely heavy, unwieldy and an easy target, practically damning ${him} in combat.`;
-				} else if (fighter.bellyImplant > 150000) {
-					return `${His} giant, ${fighter.bellyImplant}cc implant-filled belly obstructs ${his} movement and greatly slows ${him} down.`;
-				} else if (fighter.bellyImplant > 100000) {
-					return `${His} giant, ${fighter.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`;
-				} else if (fighter.bellyImplant > 10000) {
-					return `${His} huge, ${fighter.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`;
-				} else if (fighter.bellyImplant > 5000) {
-					return `${His} large, ${fighter.bellyImplant}cc implant-filled belly is heavy and unwieldy, rendering ${him} less effective.`;
-				} else if (fighter.bellyImplant > 1500) {
-					return `${His} swollen, ${fighter.bellyImplant}cc implant-filled belly is heavy and makes ${him} less effective.`;
-				}
-			}
-		}
-
-		function labor() {
-			if (isInLabor(fighter)) {
-				return `${He}'s feeling labor pains. ${His} ${fighter.pregType > 1 ? `children are` : `child is`} ready to be born, oblivious to the fact that it will mean the death of ${fighter.pregType > 1 ? `their` : `its`} mother.`;
-			} else if (fighter.preg > fighter.pregData.normalBirth && fighter.pregControl !== "labor suppressors") {
-				return `${He}'ll be going into labor any time now and ${he} knows it. ${He}'s terrified of the thought of ${his} water breaking during the fight.`;
-			}
-		}
-
-		function bellyFluid() {
-			if (fighter.bellyFluid > 10000) {
-				return `${His} hugely bloated, ${fighter.inflationType}-filled belly is taut and painful, hindering ${his} ability to fight.`;
-			} else if (fighter.bellyFluid > 5000) {
-				return `${His} bloated, ${fighter.inflationType}-stuffed belly is constantly jiggling and moving, distracting ${him} and throwing off ${his} weight.`;
-			} else if (fighter.bellyFluid > 2000) {
-				return `${His} distended, ${fighter.inflationType}-belly is uncomfortable and heavy, distracting ${him}.`;
-			}
-		}
-
-		function sight() {
-			if (!canSee(fighter)) {
-				return `${His} lack of eyesight is certain death.`;
-			} else if (!canSeePerfectly(fighter)) {
-				return `${His} poor eyesight makes ${him} a weaker combatant.`;
-			}
-		}
-
-		function hearing() {
-			if (!canHear(fighter)) {
-				return `${His} lack of hearing is a major detriment.`;
-			} else if ((fighter.hears === -1 && fighter.earwear !== "hearing aids") || (fighter.hears === 0 && fighter.earwear === "muffling ear plugs")) {		// TODO: replace with canHearPerfectly
-				return `${His} poor hearing is a minor detriment.`;
-			}
-		}
-
-		function prosthetics() {
-			if (hasAnyProstheticLimbs(fighter) && !hasAnyQuadrupedLimbs(fighter)) {
-				const r = [];
-
-				r.push(`The pit lights gleam on ${his} P-Limbs.`);
-
-				if (getLimbCount(fighter, 6) > 0) {
-					r.push(`The limits on ${his} cybernetic limbs have been lifted, turning them deadly.`);
-				} else if (getLimbCount(fighter, 5) > 0) {
-					r.push(`Their integral weapons are fully uncaged.`);
-				}
-
-				return r.join(' ');
-			}
-			if (hasAnyProstheticLimbs(fighter) && hasAnyQuadrupedLimbs(fighter)) {
-				const r = [];
-
-				r.push(`The pit lights gleam on ${his} quadrupedal limbs. The retractable claws of ${his} paws have been fully extended, ready to rip and tear.`);
-				return r.join(' ');
-			}
-		}
-	}
-
-	/** @param {DocumentFragment} parent */
-	function fight(parent) {
-		const r = [];
-
-		r.push(`In any case, ${animal ? `the slave and the ${animal.name} have both` : `both of the slaves`} been dosed with aggression enhancers and inhibition blockers; they'll fight to kill.`);
-
-		if (animal) {
-			if (winner.hasOwnProperty('slaveName')) {
-				const {he, his, him, himself, girl, He} = getPronouns(winner);
-
-				if (!canSee(winner)) {
-					r.push(`${winner.slaveName} centers ${himself} and hones in on the ${animal.name}'s rapid breath. ${He} readies ${himself}, knowing ${he} has a single chance to live. With heavy steps, the ${animal.species} rushes at ${him}, fully prepared to slaughter the helpless combatant. ${winner.slaveName} gambles everything on a single high slash, a slash that cuts the ${animal.species}'s undefended neck wide open. ${winner.slaveName} collapses to the ground, fully aware of the ${animal.species}'s final gurgles and the `, App.UI.DOM.makeElement('span', `deep scratch in ${his} side.`, ['health', 'dec']), ` ${He} lived this time, barely, but ${he} doubts ${he} can do it again.`);
-
-					healthDamage(winner, 75);
-
-					if (V.pit.audience === 'paid') {
-						r.push(`The audience is awestruck by the blind ${girl}'s triumph, and your`, App.UI.DOM.makeElement('span', `cut of the betting`, ['cash', 'inc']), ` is enormous.`);
-
-						cashX(10000, "pit", winner);
-					} else if (V.pit.audience === "free") {
-						r.push(`The audience is `, App.UI.DOM.makeElement("span", `awestruck`, ['reputation', 'inc']), `by the blind ${girl}'s triumph.`);
-
-						repX(1000, "pit", winner);
-					}
-				} else if (winner.muscles) {
-					r.push(`${winner.slaveName} is so massively muscular that ${he}'s actually impeded by ${his} lack of speed and flexibility. The ${animal.species} is suitably cautious, and it does its best to avoid ${his} sword. The two go back and forth for a while – the slave slashing and swinging, the animal leaping out of the way. ${winner.slaveName} finally manages to get the better of the ${animal.species}, though, and manages to catch the tip of ${his} sword on the animal's leg. With a loud ${animal.type === 'canine' ? `yelp` : animal.type === 'hooved' ? `whinny` : `howl`}, the ${animal.species} stumbles back, giving the slave a chance to bring ${his} sword down in an overhead swing, nearly removing the ${animal.species}'s head.`);
-
-					if (V.pit.audience === 'paid') {
-						r.push(`The audience is awestruck by the blind ${girl}'s triumph, and your`, App.UI.DOM.makeElement('span', `cut of the betting`, ['cash', 'inc']), ` is enormous.`);
-
-						cashX(10000, "pit", winner);
-					} else if (V.pit.audience === "free") {
-						r.push(`The audience is `, App.UI.DOM.makeElement("span", `awestruck`, ['reputation', 'inc']), `by the blind ${girl}'s triumph.`);
-
-						repX(1000, "pit", winner);
-					}
-				} else {
-					if (V.pit.audience === 'paid') {
-						r.push(`The audience is awestruck by the blind ${girl}'s triumph, and your`, App.UI.DOM.makeElement('span', `cut of the betting`, ['cash', 'inc']), ` is enormous.`);
-
-						cashX(10000, "pit", winner);
-					} else if (V.pit.audience === "free") {
-						r.push(`The audience is `, App.UI.DOM.makeElement("span", `awestruck`, ['reputation', 'inc']), `by the blind ${girl}'s triumph.`);
-
-						repX(1000, "pit", winner);
-					}
-				}
-			} else {
-				const {he, his, him, He} = getPronouns(loser);
-
-				if (!canSee(loser)) {
-					r.push(`The ${animal.species} isn't aware that its opponent is blind, and either way, it wouldn't have cared. It slowly paces around the flailing ${loser.slaveName}, looking for an opening. Seeing one, the ${animal.species} ${animal.type === "hooved" ? `rushes` : `lunges`} at ${him}, ending ${his} life in one fell swoop.`);
-
-					if (V.pit.audience === "paid") {
-						r.push(`The audience found the fight embarrassing, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is pitiful.`);
-
-						cashX(40, "pit", loser);
-					} else if (V.pit.audience === "free") {
-						r.push(`The audience is `, App.UI.DOM.makeElement("span", `annoyed`, ["reputation", "dec"]), ` by this waste of a fight.`);
-
-						repX(-20, "pit", loser);
-					}
-				} else if (animal.deadliness < deadliness(loser).value + 3) {
-					if (loser.skill.combat > 30) {
-						r.push(`${loser.slaveName} is fairly confident in ${his} fighting abilities, and ${he} knows that this fight is fairly evenly matched.`);
-					} else {
-						r.push(`${loser.slaveName} doesn't know how to handle a sword, but ${he} feels fairly confident in ${his} chances all the same.`);
-					}
-
-					r.push(`${He} doesn't know how to go about attacking an animal, though, so ${he} decides to play it safe and keep the ${animal.species} at sword's length. The ${animal.species} make a few false lunges at the slave, all the while keeping out of reach. After a few minutes of this, though, it's evident that ${loser.slaveName} is beginning to tire: ${his} sword is beginning to swing slower and slower, and ${his} stance isn't as straight. The animal seems to sense this, and, spotting an opening, makes a final lunge. Its ${animal.type === "hooved" ? `hooves connect with ${his} skull` : `teeth sink into ${his} throat`}, ending ${his} life almost immediately.`);
-				} else if (loser.belly > 300000) {
-					r.push(`${loser.slaveName}'s belly is too big to possibly defend, so ${he} can't help but ${canSee(loser) ? `watch` : `cringe`} in horror as the ${animal.species} lunges at ${him}, ${animal.type === "hooved" ? `headfirst` : `fangs and claws outstretched`}. ${loser.slaveName}'s belly ruptures like a popped water balloon, showering the animal with`);
-
-					if (loser.pregType > 0) {
-						r.push(`blood. ${loser.slaveName} collapses into the pile of organs and babies released from ${his} body.`);
-					} else if (loser.bellyImplant > 0) {
-						r.push(`blood and filler. ${loser.slaveName} collapses into the pool of organs and fluid released from ${his} body.`);
-					} else {
-						r.push(`blood and ${loser.inflationType}. ${loser.slaveName} collapses into the pool of organs and fluid released from ${his} body.`);
-					}
-
-					r.push(`With a ${animal.type === "hooved" ? `growl` : `snort`}, the ${animal.species} quickly finishes ${him} off${animal.type === "hooved" ? ` with a swift kick to the head` : ``}.`);
-
-					if (V.pit.audience === "paid") {
-						r.push(`The audience is not very impressed by this easy kill, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is also unimpressive.`);
-
-						cashX(2000, "pit", loser);
-					} else if (V.pit.audience === "free") {
-						r.push(`the audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ['reputation', 'inc']), ` by this easy kill.`);
-
-						repX(100, "pit", loser);
-					}
-				} else if (loser.boobs > 1200) {
-					r.push(`${loser.slaveName}'s tits are too big to possibly defend, so ${he} can't help but ${canSee(loser) ? `watch` : `cringe`} in horror in horror as the ${animal.species} lunges at ${him}, ${animal.type === "hooved" ? `headfirst` : `fangs and claws outstretched`}. ${loser.slaveName}'s reflexively drops ${his} sword to clasp ${his} ${hasBothArms(loser) ? `hands` : `hand`} over ${his} ruined breasts, gushing blood${loser.boobsImplant > 400 ? ` and implant fluid` : ``}. The ${animal.species} follows up with a ${animal.type === "hooved"
-						? `fierce bite to ${hasBothLegs(loser) ? `one of ${his} legs` : hasAnyLegs(loser) ? `${his} leg` : `${his} rear`}, causing ${him} to collapse. A second later, than animal's fangs have finished ${him} off.`
-						: `swift kick to the chest, causing ${him} to drop like a rock. Another blow to the head finishes ${him} off.`}`);
-
-					if (V.pit.audience === "paid") {
-						r.push(`The audience is not very impressed by this easy kill, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is also unimpressive.`);
-
-						cashX(2000, "pit", loser);
-					} else if (V.pit.audience === "free") {
-						r.push(`The audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ['reputation', 'inc']), ` by this easy kill.`);
-
-						repX(100, "pit", loser);
-					}
-				} else {
-					if (loser.skill.combat > 30) {
-						r.push(`${loser.slaveName} is reasonably confident in ${his} fighting abilities, but ${he} isn't sure how to go about attacking the ${animal.species}. ${He} decides to open with a series of wide horizontal slashes, but the beast manages to stay out of range of ${his} sword. Realizing this isn't working, ${he} lunges at the animal, leaving ${his} side exposed. The ${animal.species} sees this and ${animal.type === "hooved"
-							? `headbutts ${him} as hard as it can, sending ${him} flying into the side of ${V.pit.name}. Battered`
-							: `leaves some ${App.UI.DOM.makeElement("span", `deep claw marks in ${his} side.`, ['health', 'dec'])} Bleeding`} and unable to stand, ${loser.slaveName} can do little to stop the ${animal.species} from finishing ${him} off with a ${animal.type === "canine" ? `fierce bite of its fangs to ${his} throat.` : animal.type === "hooved" ? `swift kick to the head.` : `ferocious swipe of its claws to ${his} throat.`}`);
-
-						if (V.pit.audience === "paid") {
-							r.push(`The audience is reasonably impressed by the blood, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is reasonable.`);
-
-							cashX(5000, "pit", loser);
-						} else if (V.pit.audience === "free") {
-							r.push(`The audience is `, App.UI.DOM.makeElement("span", `reasonably impressed`, ['reputation', 'inc']), ` by the blood.`);
-
-							repX(250, "pit", loser);
-						}
-					} else {
-						r.push(animal.type === "hooved"
-							? `The ${animal.species} paws at the ground for a few seconds before launching itself at ${loser.slaveName}. ${He} just barely manages to get out of the way, and the ${animal.species} has to backpedal to avoid smashing into the wall. ${loser.slaveName} isn't out of danger just yet, though — ${he} is still standing directly behind the ${animal.species}. ${He} realizes this too late, as both of the its hooves connect with ${his} jaw. With a sickening ${App.UI.DOM.makeElement("span", `crunch`, ["note"])}, ${he} flies backwards, ${his} body slamming into the other wall of ${V.pit.name} before crumpling in a heap on the ground.`
-							: `${loser.slaveName} doesn't stand a chance, and ${he} knows it. ${He} comes in with a furious overhead slash, which the ${animal.species} dodges with ease. It also dodges the next few slashes before coming to a standstill. With a furious growl, it runs around ${him}, just out of reach of ${his} sword, before jumping at the wall of ${V.pit.name} and launching itself off. Its ${animal.type === "canine" ? `teeth` : `claws`} connect with ${loser.slaveName}'s throat, completely severing ${his} windpipe. ${He} falls to ${his} knees, eyes wide and clutching ${his} throat, before completely collapsing.`,
-						);
-
-						if (V.pit.audience === "paid") {
-							r.push(`The audience is reasonably impressed by the violence, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is also reasonable.`);
-
-							cashX(5000, "pit", loser);
-						} else if (V.pit.audience === "free") {
-							r.push(`The audience is `, App.UI.DOM.makeElement("span", `reasonably impressed`, ['reputation', 'inc']), ` by the violence.`);
-
-							repX(250, "pit", loser);
-						}
-					}
-				}
-			}
-		} else {
-			const winnerDeadliness = deadliness(winner).value;
-			const loserDeadliness = deadliness(loser).value;
-
-			const {he, his, him, himself, girl, He} = getPronouns(winner);
-			const {He: He2, he: he2, his: his2, him: him2, girl: girl2} = getPronouns(loser);
-
-			if (!canSee(winner) && !canSee(loser)) {
-				r.push(`${winner.slaveName} and ${loser.slaveName} are both blind, making the fight a staredown. Neither slave wants to make the first move, especially with the drowning cacophony coming from the jeering crowd. Slowly, ${winner.slaveName} moves forward, waving ${his} sword side to side in the hopes of finding ${his} opponent before ${he} ${himself} gets found. ${loser.slaveName}'s sword clips the tip of ${winner.slaveName}'s setting off a surprisingly brutal series of slashes. The two slaves violently lay into each other, suffering more and more strikes as the struggle goes on. Less than a minute from first contact, both slaves are lying in their combined blood. As you begin to call it a draw, you notice ${winner.slaveName} start to stir. ${He} staggers to ${his} feet, coated in ${his} and ${loser.slaveName}'s blood, before dropping back to ${his} knees. It seems ${he} lived through this fight; odds aren't likely ${he}'ll do it again.`);
-
-				healthDamage(winner, 50);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is surprised by the sudden violence after so much standing around, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is modest.`);
-
-					cashX(5000, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `surprised`, ['reputation', 'inc']), ` by the sudden violence after so much standing around.`);
-
-					repX(250, "pit", winner);
-				}
-			} else if (winnerDeadliness > (loserDeadliness + 1) && getArmCount(winner, 6) > 1) {
-				r.push(`Upon your word the two combatants approach each other. ${winner.slaveName} does not carry a sword, raising only ${his} hands, but these are terrifying, modern weapons themselves. ${loser.slaveName} tries a probing sweep, but ${winner.slaveName} catches ${his2} blade in one hand, slides it down to the hilt with a shriek of metal on metal, and snaps the blade cleanly. ${loser.slaveName} ${canSee(loser) ? `watches this` : `freezes in place`}, dumbstruck, before regaining composure and taking a fighting stance again. ${winner.slaveName} manages to touch ${his} opponent's bare skin with ${his} own cybernetics, incapacitating ${loser.slaveName} with an electric shock. While ${loser.slaveName} is temporarily stunned, ${winner.slaveName} strikes ${loser.slaveName} on the head with deadly force, crushing ${his} opponent's skull. Though the fight was short,`);
-
-				if (V.pit.audience === "free") {
-					r.push(`the audience is `, App.UI.DOM.makeElement("span", `very impressed`, ['reputation', 'inc']), ` by the display.`);
-
-					repX(500, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`the audience is quite impressed by the display, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is quite good.`);
-
-					cashX(10000, "pit", winner);
-				}
-			} else if (winnerDeadliness > (loserDeadliness + 1) && getArmCount(winner, 5) > 1) {
-				r.push(`Upon your word the two combatants approach each other. ${winner.slaveName} drops ${his} sword as ${he} comes, raising only ${his} hands, but these are terrifying, modern weapons themselves. ${loser.slaveName} tries a probing sweep, but ${winner.slaveName} catches ${his2} blade in one hand, slides it down to the hilt with a shriek of metal on metal, and snaps the blade cleanly. As ${loser.slaveName} watches this, dumbstruck, ${winner.slaveName} places a gentle hand under ${his2} chin and then extends that arm's integral blade up and through ${his} opponent's skull. Though the fight was short,`);
-
-				if (V.pit.audience === "free") {
-					r.push(`the audience is `, App.UI.DOM.makeElement("span", `very impressed`, ['reputation', 'inc']), ` by the display.`);
-
-					repX(500, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`the audience is quite impressed by the display, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is quite good.`);
-
-					cashX(10000, "pit", winner);
-				}
-			} else if (!canSee(winner)) {
-				r.push(`${winner.slaveName} centers ${himself} and hones in on ${loser.slaveName}'s rapid breath. ${He} readies ${himself}, knowing ${he} has a single chance to live. With heavy steps, ${loser.slaveName} rushes ${him}, fully prepared to slaughter the helpless combatant. ${winner.slaveName} gambles everything on a single high slash, a slash that cut ${loser.slaveName}'s undefended neck wide open. ${winner.slaveName} collapses to the ground, fully aware of ${loser.slaveName}'s final gurgles, and the sword `, App.UI.DOM.makeElement("span", `firmly planted in ${his} side.`, ['health', 'dec']), ` ${He} lived this time, barely, but ${he} doubts ${he} can do it again.`);
-
-				healthDamage(winner, 80);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `awestruck`, ['reputation', 'inc']), ` by the blind ${girl}'s triumph.`);
-
-					repX(2000, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is awestruck by the blind ${girl}'s triumph, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is enormous.`);
-
-					cashX(40000, "pit", winner);
-				}
-			} else if (!canSee(loser)) {
-				r.push(`${winner.slaveName} sighs at ${loser.slaveName}'s random slashing and calmly struts around the panicking slave. In one quick swoop, ${he} buries ${his} blade in ${loser.slaveName}'s back, ending the poor ${girl2}'s flailing.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `annoyed`, ["reputation", "dec"]), ` by this waste of a fight.`);
-
-					repX(-20, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience found the fight embarrassing, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is pitiful.`);
-
-					cashX(40, "pit", winner);
-				}
-			} else if (winnerDeadliness > (loserDeadliness + 3)) {
-				if (winner.skill.combat > 30) {
-					r.push(`${winner.slaveName} wants to win, and ${he} opens the fight with a furious attack. ${loser.slaveName} manages to get ${his2} blade up, blocking a strike with a ringing clash and a few sparks, but by doing so leaves ${his2} abdomen open and obscures ${his2} vision enough that ${he2} is unprepared for the following horizontal slash, which opens ${his2} belly wide. The stricken ${girl2} collapses, feebly trying to push ${his2} viscera back into place. Whether out of mercy or a desire to get it over with, ${winner.slaveName} quickly removes the dying ${girl2}'s head.`);
-
-					if (V.pit.audience === "free") {
-						r.push(`The audience is `, App.UI.DOM.makeElement("span", `reasonably impressed`, ['reputation', 'inc']), ` by the gore.`);
-
-						repX(200, "pit", winner);
-					} else if (V.pit.audience === "paid") {
-						r.push(`The audience is reasonably impressed by the gore, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is reasonable.`);
-
-						cashX(4000, "pit", winner);
-					}
-				} else {
-					r.push(`${winner.slaveName} wants to win and is confident ${he} will, but ${he} isn't particularly sure about how to do so. ${He} fights cautiously, swinging ${his} sword in powerful but inaccurate strokes. It is only a matter of time before one of these strikes gets through; it's telling that rather than hitting what ${he} aimed at, ${winner.slaveName} accidentally opens a massive gash down ${loser.slaveName}'s thigh. Realizing ${he2} has to do something, ${loser.slaveName} makes a desperate counterattack, pouring blood as ${he2} goes. ${winner.slaveName} panics and fails to parry one of the last counterstrikes before loss of blood ends the attack, suffering a `, App.UI.DOM.makeElement("span", `terrible cut`, ['health', 'dec']), ` to ${his} shoulder. Down to one arm, ${winner.slaveName} is forced to make a long, loud butchery of ending the fight.`);
-
-					healthDamage(winner, 20);
-
-					if (V.pit.audience === "free") {
-						r.push(`The audience is `, App.UI.DOM.makeElement("span", `reasonably impressed`, ['reputation', 'inc']), ` by the blood.`);
-
-						repX(200, "pit", winner);
-					} else if (V.pit.audience === "paid") {
-						r.push(`The audience is reasonably impressed by the blood, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is reasonable.`);
-
-						cashX(4000, "pit", winner);
-					}
-				}
-			} else if (winner.skill.combat > 30 && loser.skill.combat > 30) {
-				r.push(`Upon your word the two combatants approach each other warily, both knowing the other is reasonably competent. Before long they are trading thrust and parry, swing and block. ${winner.slaveName} is slowly pressed back, so ${he} decides to change the nature of the fight. After three tries ${he} manages to force ${loser.slaveName} to close, suffering a `, App.UI.DOM.makeElement("span", `nearly severed ear`, ['health', 'dec']), ` as ${he} does. ${loser.slaveName} realizes ${he2} only retains an advantage at long range but cannot back up fast enough to avoid close combat. ${loser.slaveName} is forced back fast enough that ${he2} trips; ${he2}'s barely fallen on ${his2} back before ${he2} grunts with shock and pain, dying with a look of surprise as ${he2} stares at the sword growing out of ${his2} chest.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `very impressed`, ['reputation', 'inc']), ` by the expert fight.`);
-
-					repX(500, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is quite impressed by the expert fight, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is quite good.`);
-
-					cashX(10000, "pit", winner);
-				}
-			} else if (winner.height - loser.height < -10) {
-				r.push(`${winner.slaveName} realizes that ${loser.slaveName}'s wingspan gives ${him2} a huge reach advantage. ${He} bores straight in, taking `, App.UI.DOM.makeElement("span", `a glancing scalp wound`, ['health', 'dec']), ` but coming on regardless. ${loser.slaveName} understands ${his2} opponent's intention and backs off, but the pit is small and there isn't much room to retreat. When ${his2} back hits a padded wall, ${winner.slaveName} aims a gutting cut that ${loser.slaveName} struggles to block. ${He2} manages it, but the wall catches ${his2} point, so the block is with ${his2} wrist, not ${his2} sword. The sharp blade cuts almost all the way through the joint, leaving ${him2} in agony and totally incapable of defense. ${winner.slaveName} pushes ${his2} head back against the wall and cuts ${his2} throat down to the spine.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `reasonably impressed`, ['reputation', 'inc']), ` by the blood.`);
-
-					repX(200, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is reasonably impressed by the blood, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is reasonable.`);
-
-					cashX(4000, "pit", winner);
-				}
-			} else if (winner.muscles > 30) {
-				r.push(`${winner.slaveName} is so massively muscular that ${he}'s actually impeded by ${his} lack of speed and flexibility. ${loser.slaveName} is properly afraid of ${his2} strength, though, so ${he2} tries to stay away as much as ${he2} can. The few times their blades clash reinforces this approach, since ${winner.slaveName} is able to beat ${his} opponent's blocks out of the way with contemptuous ease. The fight takes a long, long time, but it takes more out of ${loser.slaveName} to survive than it takes out of ${winner.slaveName} to keep swinging. Eventually the gasping, weeping ${loser.slaveName} trips and does not struggle to ${his2} feet in time. It takes ${his2} tired opponent several overhead butcher's cleaves to end it.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `reasonably impressed`, ['reputation', 'inc']), ` by the show of strength.`);
-
-					repX(50, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is reasonably impressed by the show of strength, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is reasonable.`);
-
-					cashX(1000, "pit", winner);
-				}
-			} else if (loser.belly > 300000) {
-				r.push(`${winner.slaveName} wants to live badly enough that ${he} takes an extremely brutal shortcut to victory. The instant the fight starts, ${he} quickly slices right across ${loser.slaveName}'s massive belly, which is far too large to possibly defend. ${loser.slaveName}'s belly ruptures like a popped water balloon, showering ${winner.slaveName} with`);
-
-				if (loser.pregType > 0) {
-					r.push(`blood. ${loser.slaveName} collapses into the pile of organs and babies released from ${his2} body.`);
-				} else if (loser.bellyImplant > 0) {
-					r.push(`blood and filler. ${loser.slaveName} collapses into the pool of organs and fluid released from ${his2} body.`);
-				} else {
-					r.push(`blood and ${loser.inflationType}. ${loser.slaveName} collapses into the pool of organs and fluid released from ${his2} body.`);
-				}
-
-				r.push(`${winner.slaveName} walks over to the bleeding out slave and quickly cuts ${his2} throat.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`the audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ['reputation', 'inc']), ` by this easy kill.`);
-
-					repX(100, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is not very impressed by this easy kill, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is unimpressive.`);
-
-					cashX(2000, "pit", winner);
-				}
-			} else if (loser.boobs > 1200) {
-				r.push(`${winner.slaveName} takes an extremely simple shortcut to victory. The instant the fight starts, ${he} slices ${loser.slaveName} right across ${his2} huge tits, which are so large they cannot properly be defended. ${loser.slaveName} reflexively drops ${his2} sword to clasp ${his2} ${hasBothArms(loser) ? `hands` : `hand`} over ${his2} ruined breasts, gushing blood${loser.boobsImplant > 400 ? ` and implant fluid` : ``}. ${winner.slaveName}'s follow-up is neither artful nor particularly well planned, but it is effective. ${He} hits the distracted ${girl2}'s neck from the side, almost but not quite separating ${his2} head from ${his2} body.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ['reputation', 'inc']), ` by this easy kill.`);
-
-					repX(100, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is not very impressed by this easy kill, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is unimpressive.`);
-
-					cashX(2000, "pit", winner);
-				}
-			} else if (loser.dick > 0) {
-				r.push(`${winner.slaveName} wants to live badly enough that ${he} takes an extremely brutal shortcut to victory. The instant the fight starts, ${he} furiously swings for ${loser.slaveName}'s face. ${loser.slaveName} reflexively raises ${his2} sword to block, at which point ${winner.slaveName} simply kicks ${him2} in the dick. ${loser.slaveName} goes down like a marionette with cut strings, ${his2} mouth soundlessly opening and closing and tears leaking from ${his2} closed eyes. ${winner.slaveName} walks over to the prostrate slave and cuts ${his2} throat without much trouble.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ['reputation', 'inc']), ` by this easy kill.`);
-
-					repX(100, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is not very impressed by this easy kill, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is unimpressive.`);
-
-					cashX(2000, "pit", winner);
-				}
-			} else {
-				r.push(`${winner.slaveName} wants to live badly enough that ${he} takes an extremely brutal shortcut to victory. The instant the fight starts, ${he} furiously swings for ${loser.slaveName}'s face. ${loser.slaveName} reflexively raises ${his2} sword to block, at which point ${winner.slaveName} simply kicks ${him2} in the cunt. ${loser.slaveName} goes down like a marionette with cut strings, ${his2} mouth soundlessly opening and closing and tears leaking from ${his2} closed eyes. ${winner.slaveName} walks over to the prostrate slave and cuts ${his2} throat without much trouble.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ['reputation', 'inc']), ` by this easy kill.`);
-
-					repX(100, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is not very impressed by this easy kill, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']), ` is unimpressive.`);
-
-					cashX(2000, "pit", winner);
-				}
-			}
-		}
-
-		App.Events.addParagraph(parent, r);
-	}
-
-	/** @param {DocumentFragment} parent */
-	function postFight(parent) {
-		const r = [];
-
-		if (animal) {
-			if (winner.hasOwnProperty('slaveName')) {
-				const {he, his, himself, hers, He} = getPronouns(winner);
-
-				r.push(`You let the winner ${winner.slaveName}, shaking as ${he} comes off the adrenaline, drugs, and fear, exit the pit.`);
-
-				if (winner.fetish === Fetish.MINDBROKEN) {
-					r.push(`${He} was already so broken before today that ${he} will not be seriously affected by having killed another creature with ${his} own ${hasBothArms ? `hands` : `hand`}.`);
-				} else if (winner.devotion > 50) {
-					r.push(`${He} is so devoted that ${he} doesn't see anything wrong with killing another creature.`);
-				} else {
-					r.push(`${He} isn't happy about having to have taken another creature's life, and tells ${himself} that it was the animal's life or ${hers}.`);
-				}
-			} else {
-				r.push(`Another week, another slave killed by your animals.`);
-			}
-		} else {
-			const {he, his, him, himself, He} = getPronouns(winner);
-			const {sister: sister2} = getPronouns(loser);
-			const mindbrokenSpan = App.UI.DOM.makeElement("span", `no longer capable`, ["red"]);
-
-			r.push(`You let the winner ${winner.slaveName}, shaking as ${he} comes off the adrenaline, drugs, and fear, exit the pit.`);
-
-			if (winner.fetish === Fetish.MINDBROKEN) {
-				r.push(`${He} was already so broken before today that ${he} will not be seriously affected by having killed with ${his} own ${hasBothArms(winner) ? `hands` : `hand`}.`);
-			} else if (winner.devotion > 95) {
-				r.push(`${He} is so worshipful of you that ${he} does not see killing ${loser.slaveName} as special in ${his} own internal listing of things that ${he} has willingly done and would willingly do again on your behalf.`);
-			} else if (winner.devotion > 80) {
-				r.push(`${He} will never forget having killed ${loser.slaveName} with ${his} own ${hasBothArms(winner) ? `hands` : `hand`}. The only way ${he} will be able to live with ${himself} is to `, App.UI.DOM.makeElement("span", `subsume ${his} will to yours,`, ["devotion", "inc"]), ` telling ${himself} that the killing was to serve and obey you.`);
-
-				winner.devotion += 10;
-			} else if (winner.fetish === "sadist" && winner.fetishKnown && winner.fetishStrength > 60) {
-				r.push(`${He} has sunk even deeper into cruelty, callousness, and a total disregard of the value of other slaves' lives. Going forward, ${he}'s even `, App.UI.DOM.makeElement("span", `less likely to question`, ["devotion", "inc"]), ` even the most abominable commands.`);
-
-				winner.devotion += 10;
-			} else if (winner.devotion > 50) {
-				r.push(`${He} will never forget having killed ${loser.slaveName} with ${his} own ${hasBothArms(winner) ? `hands` : `hand`}. The only way ${he} will be able to live with ${himself} is to tell ${himself} that the killing was done on your orders.`);
-			} else {
-				r.push(`${He} will never forget having killed ${loser.slaveName} with ${his} own ${hasBothArms(winner) ? `hands` : `hand`}. The only way ${he} will be able to live with ${himself} is to `, App.UI.DOM.makeElement("span", `blame you,`, ["devotion", "dec"]), ` telling ${himself} that the killing was the only choice you gave ${him} if ${he} wanted to live.`);
-
-				winner.devotion -= 10;
-			}
-
-			if (winner.fetish !== "sadist") {
-				if (random(1, 100) > 50) {
-					r.push(`Cruelty and callousness seeps its way into ${his} sexuality; ${he} has become a `, App.UI.DOM.makeElement("span", `bloody sadist.`, ["fetish", "gain"]));
-
-					winner.fetish = "sadist";
-					winner.fetishKnown = 1;
-					winner.fetishStrength = 65;
-				}
-			}
-
-			if (winner.rivalry && loser.ID === winner.rivalryTarget) {
-				if (winner.devotion > 75) {
-					r.push(`${He} is so accepting of the low value of slave life that ${he} `, App.UI.DOM.makeElement("span", `is pleased`, ["devotion", "inc"]), ` to have killed ${his} rival ${loser.slaveName}.`);
-
-					winner.devotion += 4;
-				}
-			} else if (winner.relationship && loser.ID === winner.relationshipTarget) {
-				if (winner.devotion > 95) {
-					r.push(`${He} is so worshipful of you that ${he} sees the death of ${his} only friend at ${his} own hand as an `, App.UI.DOM.makeElement("span", `honorable`, ["devotion", "inc"]), ` end to their doomed slave relationship.`);
-
-					winner.devotion += 4;
-				} else {
-					r.push(`${He} shows little reaction to the death of ${his} only friend at ${his} own hand. In the coming days, it becomes clear that this is because ${he} is `, mindbrokenSpan, ` of reacting to anything on an emotional level. Ever again.`);
-
-					applyMindbroken(winner);
-					winner.fetishKnown = 1;
-				}
-			} else if (isParentP(winner, loser) || isParentP(loser, winner)) {
-				if (winner.devotion > 95) {
-					r.push(`${He} is so worshipful of you that ${he} sees the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand as an `, App.UI.DOM.makeElement("span", `honorable`, ["devotion", "inc"]), ` end to their doomed family.`);
-
-					winner.devotion += 4;
-				} else {
-					r.push(`${He} shows little reaction to the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand. In the coming days, it becomes clear that this is because ${he} is `, mindbrokenSpan, ` of reacting to anything on an emotional level. Ever again.`);
-
-					applyMindbroken(winner);
-					winner.fetishKnown = 1;
-				}
-			} else if (winner.sisters > 0) {
-				switch (areSisters(winner, loser)) {
-					case 1:
-						if (winner.devotion > 95) {
-							r.push(`${He} is so worshipful of you that ${he} sees the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand as an `, App.UI.DOM.makeElement("span", `honorable`, ["devotion", "inc"]), ` end to their doomed family.`);
-
-							winner.devotion += 4;
-						} else {
-							r.push(`${He} shows little reaction to the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand. In the coming days, it becomes clear that this is because ${he} is `, mindbrokenSpan, ` of reacting to anything on an emotional level. Ever again.`);
-
-							applyMindbroken(winner);
-							winner.fetishKnown = 1;
-						}
-						break;
-					case 2:
-						if (winner.devotion > 90) {
-							r.push(`${He} is so worshipful of you that ${he} sees the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand as an `, App.UI.DOM.makeElement("span", `honorable`, ["devotion", "inc"]), ` end to their doomed family.`);
-
-							winner.devotion += 4;
-						} else {
-							r.push(`${He} shows little reaction to the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand. In the coming days, it becomes clear that this is because ${he} is `, mindbrokenSpan, ` of reacting to anything on an emotional level. Ever again.`);
-
-							applyMindbroken(winner);
-							winner.fetishKnown = 1;
-						}
-						break;
-					case 3:
-						if (winner.devotion > 85) {
-							r.push(`${He} is so worshipful of you that ${he} sees the death of ${his} half-${sister2} at ${his} own hand as an `, App.UI.DOM.makeElement("span", `honorable`, ["devotion", "inc"]), ` end to their doomed family.`);
-
-							winner.devotion += 4;
-						} else {
-							r.push(`${He} is `, App.UI.DOM.makeElement("span", `utterly devastated`, ["devotion", "dec"]), ` at being forced to take the life of ${his} half-${sister2}.`);
-
-							winner.devotion -= 50;
-						}
-						break;
-				}
-			}
-
-			V.pit.slaveFightingBodyguard = null;
-
-			if (winner.skill.combat < 60) {
-				const experienceSpan = App.UI.DOM.makeElement("span", `improved ${his} combat skills.`, ["improvement"]);
-
-				winner.skill.combat += 5 + Math.floor(0.5 * (winner.intelligence + winner.intelligenceImplant) / 32);
-				r.push(`With lethal experience in ${V.pit.name}, ${winner.slaveName} has `, experienceSpan);
-			}
-
-			winner.counter.pitKills++;
-			winner.counter.pitWins++;
-		}
-
-		V.pitKillsTotal++;
-		V.pitFightsTotal++;
-
-		if (loser.hasOwnProperty('slaveName')) {
-			V.pit.fighterIDs.delete(loser.ID);
-
-			if (V.pit.slavesFighting.length > 0) {
-				V.pit.slavesFighting = [];
-			}
-
-			removeSlave(loser);
-		}
-
-		App.Events.addParagraph(parent, r);
-	}
-
-	// Helper Functions
-
-	/** @returns {boolean} Returns true if fighters[0] won */
-	function getWinner() {
-		if (animal) {
-			if (deadliness(getSlave(fighters[0])).value > animal.deadliness) {
-				return random(1, 100) > 20;	// 80% chance of winning
-			} else if (deadliness(getSlave(fighters[0])).value < animal.deadliness) {
-				return random(1, 100) > 80;	// 20% chance of winning
-			} else if (random(1, 100) > 50) { // 50/50
-				return true;
-			}
-
-			return false;
-		}
-
-		if (deadliness(getSlave(fighters[0])).value > deadliness(getSlave(fighters[1])).value) {
-			return random(1, 100) > 20;	// 80% chance of winning
-		} else if (deadliness(getSlave(fighters[0])).value < deadliness(getSlave(fighters[1])).value) {
-			return random(1, 100) > 80;	// 20% chance of winning
-		} else if (random(1, 100) > 50) { // 50/50
-			return true;
-		}
-
-		return false;
-	}
-};
diff --git a/src/events/scheduled/pitFightNonlethal.js b/src/events/scheduled/pitFightNonlethal.js
deleted file mode 100644
index 0c7605ee61c1a46db44a9f09fbd4e06f1f4e3b28..0000000000000000000000000000000000000000
--- a/src/events/scheduled/pitFightNonlethal.js
+++ /dev/null
@@ -1,1271 +0,0 @@
-// TODO: add devotion and trust effects to animal variant
-App.Facilities.Pit.nonlethalFight = function(fighters) {
-	const frag = new DocumentFragment();
-
-	const animals = [];
-	/** @type {FC.AnimalState} */
-	let animal = null;
-
-	if (V.active.canine) {
-		animals.push(V.active.canine);
-	}
-	if (V.active.hooved) {
-		animals.push(V.active.hooved);
-	}
-	if (V.active.feline) {
-		animals.push(V.active.feline);
-	}
-
-	if ((V.pit.fighters === 2 || V.pit.slaveFightingAnimal) && animals.length > 0) {
-		animal = V.pit.animal === 'random'
-			? getAnimal(animals.random())
-			: getAnimal(V.pit.animal);
-	}
-
-	/** @param {App.Entity.SlaveState} slave */
-	const canRun = slave => slave.muscles > -30 &&
-		slave.weight < 95 &&
-		slave.health.condition > -50 &&
-		slave.bellyPreg < 5000 &&
-		slave.bellyImplant < 4000 &&
-		slave.bellyFluid < 2000 &&
-		!isInLabor(slave);
-
-	let winner;
-	let loser;
-
-	if (animal) {
-		winner = getWinner() ? getSlave(fighters[0]) : animal;
-		loser = winner.hasOwnProperty('species') ? getSlave(fighters[0]) : animal;
-	} else {
-		winner = getWinner() ? getSlave(fighters[0]) : getSlave(fighters[1]);
-		loser = winner.ID === fighters[0] ? getSlave(fighters[1]) : getSlave(fighters[0]);
-	}
-
-	if (V.debugMode) {
-		console.log(winner, loser);
-	}
-
-	intro(frag);
-	fighterDeadliness(frag, getSlave(fighters[0]));
-	if (!animal) {
-		fighterDeadliness(frag, getSlave(fighters[1]));
-	}
-	fight(frag);
-	postFight(frag);
-
-	V.pit.slaveFightingBodyguard = null;
-	V.pit.slaveFightingAnimal = null;
-	V.pit.slavesFighting = [];
-
-	return frag;
-
-	/**
-	 * TODO: update to use "run" if animal
-	 *
-	 * @param {DocumentFragment} parent
-	 */
-	function intro(parent) {
-		const fighterOne = getSlave(fighters[0]);
-		const fighterTwo = getSlave(fighters[1]) || null;
-
-		if (V.debugMode) {
-			console.log(fighterOne, fighterTwo);
-		}
-
-		const r = [];
-
-		App.Events.drawEventArt(frag, fighters.map(id => getSlave(id)), "no clothing");
-
-		const anAnimal = animal ? `${animal.articleAn} ${animal.name}` : null;
-
-		if (animal) {
-			r.push(`This week ${anAnimal} is going to try to use ${fighterOne.slaveName}.`);
-		} else {
-			r.push(`This week's fight is between`, App.UI.DOM.slaveDescriptionDialog(fighterOne), `and`,
-				App.UI.DOM.combineNodes(contextualIntro(fighterOne, fighterTwo, true), "."));
-		}
-
-		if (animal) {
-			const slave = getSlave(fighters[0]);
-
-			if (V.pit.audience === "none") {
-				r.push(`You are alone above the pit, left to watch the animal try use your slave in private.`);
-			} else if (V.pit.audience === "free") {
-				r.push(`Your guests line the rim of the pit, joking and laughing.`);
-			} else {
-				r.push(`The attendees line the rim of the pit, making bets on how long ${slave.slaveName} will last.`);
-			}
-		} else {
-			if (V.pit.audience === "none") {
-				r.push(`You are alone above the pit, left to watch them square off in private.`);
-			} else if (V.pit.audience === "free") {
-				r.push(`Your guests line the rim of the pit, joking and betting.`);
-			} else {
-				r.push(`The attendees line the rim of the pit, betting and arguing.`);
-			}
-		}
-
-		if (V.arcologies[0].FSRomanRevivalist !== "unset") {
-			r.push(`They `, App.UI.DOM.makeElement("span", 'strongly approve', ["reputation", "inc"]), ` of your hosting combat between slaves; this advances ideas from antiquity about what public events should be.`);
-
-			repX(10 * V.FSSingleSlaveRep * (V.arcologies[0].FSRomanRevivalist / V.FSLockinLevel), "pit");
-			V.arcologies[0].FSRomanRevivalist += (0.2 * V.FSSingleSlaveRep);
-		}
-
-		if (animal) {
-			const slave = getSlave(fighters[0]);
-			const {he, his} = getPronouns(slave);
-
-			const approves = slave.devotion > 50 || (slave.devotion > 20 && (slave.fetish === "masochist" || slave.fetish === "humiliation" || slave.sexualQuirk === "perverted" || slave.behavioralQuirk === "sinful"));
-
-			r.push(`${slave.slaveName} and the ${animal.name} enter ${V.pit.name} from opposite sides. ${slave.slaveName} is naked except for a ring gag, ${his} wrists have been bound, and ${he} has already been given ${his} instructions: ${he} is to try to avoid being caught and ${approves ? `fucked` : `raped`} by the animal for five minutes, and if ${he} succeeds, ${he} wins two complete days of rest. The ${animal.name} has been given a large dose of aphrodisiacs, and its lust is apparent – its ${animal.dick.desc} cock is clearly visible, even from where you're seated.`);
-		} else {
-			r.push(`You review the rules — the combatants are wearing light gloves, and the fight will be nonlethal, with you as the judge. The winner will have the right to do anything they wish to the loser,`);
-
-			switch (V.pit.virginities) {
-				case "all":
-					r.push(`except take their virginity,`);
-					break;
-				case "anal":
-					r.push(`except take their anal virginity,`);
-					break;
-				case "vaginal":
-					r.push(`except take virginities,`);
-					break;
-				case "neither":
-					r.push(`even take virginities,`);
-					break;
-				default:
-					throw new Error(`Unexpected V.pit.virginities value of '${V.pit.virginities}' found`);
-			}
-
-			r.push(`and earn two complete days of rest. You take a moment to look over your fighters before giving the word.`);
-		}
-
-		App.Events.addParagraph(parent, r);
-	}
-
-	/**
-	 * @param {DocumentFragment} parent
-	 * @param {App.Entity.SlaveState} fighter
-	 */
-	function fighterDeadliness(parent, fighter) {
-		const {he, his, him, himself, He, His} = getPronouns(fighter);
-		const fighterDeadliness = deadliness(fighter).value;
-
-		const r = [];
-
-		r.push(
-			confidence(),
-			skill(),
-			age(),
-			muscles(),
-			height(),
-			health(),
-			weight(),
-			tired(),
-			pregnancy(),
-			labor(),
-			bellyFluid(),
-			sight(),
-			hearing(),
-			prosthetics(),
-			willingness(),
-		);
-
-		App.Events.addParagraph(parent, r);
-
-		function confidence() {
-			if (fighter.fetish === Fetish.MINDBROKEN) {
-				return `${fighter.slaveName} is too broken to care what happens to ${him}.`;
-			} else if (fighterDeadliness > 5) {
-				return `${fighter.slaveName} seems very confident, even eager to win a break.`;
-			} else if (fighterDeadliness > 3) {
-				return `${fighter.slaveName} seems nervous, but steels ${himself} to fight for time off.`;
-			} else if (fighterDeadliness > 1) {
-				return `${fighter.slaveName} seems hesitant and unsure.`;
-			} else {
-				return `${fighter.slaveName} is obviously terrified, and might flee if there were a way out of the pit.`;
-			}
-		}
-
-		function willingness() {
-			if (fighter.devotion < 20 && fighter.trust < -20) {
-				return `${He} is unwilling to fight, but ${he} knows the punishment for refusing to do so will be even worse.`;
-			}
-		}
-
-		function skill() {
-			if (fighter.skill.combat > 30) {
-				return `${His} stance is obviously well-practiced.`;
-			}
-		}
-
-		function age() {
-			if (V.AgePenalty !== 0) {
-				if (fighter.physicalAge >= 100) {
-					return `${He} seems preoccupied, which is unsurprising given ${his} age and resulting fragility.`;
-				} else if (fighter.physicalAge >= 85) {
-					return `${He} tries not to waste ${his} strength before the fight, knowing that ${his} extreme age won't allow ${him} a second wind.`;
-				} else if (fighter.physicalAge >= 70) {
-					return `${He} steadies ${himself} as well as ${he} can in ${his} advanced age.`;
-				}
-			}
-		}
-
-		function muscles() {
-			if (fighter.muscles > 95 && fighter.height > 185) {
-				return `${His} huge muscles are an intimidating sight and, despite their massive size, ${he} is tall enough to not be hindered by them.`;
-			} else if (fighter.muscles > 95) {
-				return `${His} huge muscles are an intimidating sight, but may hinder ${his} flexibility.`;
-			} else if (fighter.muscles > 30) {
-				return `${His} muscles are a trim and powerful sight.`;
-			} else if (fighter.muscles < -95) {
-				return `${He} can barely stand, let alone defend ${himself}.`;
-			} else if (fighter.muscles < -30) {
-				return `${He} is very weak; a single punch will likely floor ${him}.`;
-			} else if (fighter.muscles < -5) {
-				return `${He} is rather unfit; ${he} will likely be outmatched by near any real opponent.`;
-			} else {
-				return `${He} is only somewhat fit and will likely not be able to win through pure strength.`;
-			}
-		}
-
-		function height() {
-			if (fighter.height > 170) {
-				return `${His} height gives ${him} a reach advantage with ${his} fists and feet.`;
-			}
-		}
-
-		function health() {
-			if (fighter.health.condition > 50) {
-				return `${His} shining health makes ${him} a better fighter.`;
-			} else if (fighter.health.condition) {
-				return `${His} poor health makes ${him} a weaker combatant.`;
-			}
-		}
-
-		function weight() {
-			if (fighter.weight > 190) {
-				return `${His} extreme weight nearly immobilizes ${him}. ${He} is essentially a fleshy punching bag.`;
-			} else if (fighter.weight > 160) {
-				return `${His} extreme weight limits ${his} mobility and range of motion even if ${he} can take punches like nothing.`;
-			} else if (fighter.weight > 130) {
-				return `${His} extreme weight holds ${him} back as a pit fighter.`;
-			} else if (fighter.weight > 30) {
-				return `${His} heavy weight is an impediment as a pit fighter.`;
-			} else if (fighter.weight < -10) {
-				return `${His} light weight is an impediment as a pit fighter.`;
-			}
-		}
-
-		function tired() {
-			if (fighter.health.tired > 90) {
-				return `${He} is exhausted and can barely stay awake; ${he} won't put up a fight.`;
-			} else if (fighter.health.tired > 60) {
-				return `${He} is fatigued, sapping the strength ${he}'ll need in ${his} strikes.`;
-			} else if (fighter.health.tired > 30) {
-				return `${He} is tired and more likely to take a hit than to give one.`;
-			}
-		}
-
-		function pregnancy() {
-			if (fighter.pregKnown || fighter.bellyPreg > 1500) {
-				if (fighter.bellyPreg > 750000) {
-					return `${His} monolithic pregnancy guarantees ${his} loss; not only is ${he} on the verge of splitting open, but it is an unmissable, indefensible target that threatens to drag ${him} to the ground. ${He} has no hope of attacking around the straining mass, let alone stopping ${his} opponent. The fear of what would happen should ${his} adversary land a hit on ${his} belly also weighs upon ${his} mind.`;
-				} else if (fighter.bellyPreg > 600000) {
-					return `${His} titanic pregnancy is practically a guaranteed loss; ${he} can barely stand let alone fight. The worry of a solid hit striking ${his} life-swollen womb also weighs on ${his} mind.`;
-				} else if (fighter.bellyPreg > 450000) {
-					return `${His} gigantic pregnancy is nearly a guaranteed loss; it presents an unmissable, indefensible target for ${his} adversary.`;
-				} else if (fighter.bellyPreg > 300000) {
-					return `${His} massive pregnancy obstructs ${his} movement and greatly hinders ${him}. ${He} struggles to think of how ${he} could even begin to defend ${his} bulk.`;
-				} else if (fighter.bellyPreg > 150000) {
-					return `${His} giant pregnancy obstructs ${his} movement and greatly slows ${him} down.`;
-				} else if (fighter.bellyPreg > 100000) {
-					return `${His} giant belly gets in ${his} way and weighs ${him} down.`;
-				} else if (fighter.bellyPreg > 10000) {
-					return `${His} huge belly is unwieldy and hinders ${his} efforts.`;
-				} else if (fighter.bellyPreg > 5000) {
-					return `${His} advanced pregnancy makes ${him} much less effective.`;
-				} else if (fighter.bellyPreg > 1500) {
-					return `${His} growing pregnancy distracts ${him} from the fight.`;
-				} else {
-					return `The life just beginning to grow inside ${him} distracts ${him} from the fight.`;
-				}
-			} else if (fighter.bellyImplant > 1500) {
-				if (fighter.bellyImplant > 750000) {
-					return `${His} monolithic, ${fighter.bellyImplant}cc implant-filled belly guarantees ${his} defeat; not only is ${he} on the verge of splitting open, but it is an unmissable, indefensible target that threatens to drag ${him} to the ground. ${He} has no hope of attacking around the straining mass, let alone stopping ${his} opponent.`;
-				} else if (fighter.bellyImplant > 600000) {
-					return `${His} titanic, ${fighter.bellyImplant}cc implant-filled belly is practically a guaranteed defeat; ${he} can barely stand let alone fight. Not only is it cripplingly heavy, unwieldy and an easy target, but ${he} can feel it straining to hold the sheer amount of filler forced into it.`;
-				} else if (fighter.bellyImplant > 450000) {
-					return `${His} gigantic, ${fighter.bellyImplant}cc implant-filled belly is nearly a guaranteed defeat; it presents an unmissable, indefensible target for ${his} adversary.`;
-				} else if (fighter.bellyImplant > 300000) {
-					return `${His} massive, ${fighter.bellyImplant}cc implant-filled belly is extremely heavy, unwieldy and an easy target, practically damning ${him} in combat.`;
-				} else if (fighter.bellyImplant > 150000) {
-					return `${His} giant, ${fighter.bellyImplant}cc implant-filled belly obstructs ${his} movement and greatly slows ${him} down.`;
-				} else if (fighter.bellyImplant > 100000) {
-					return `${His} giant, ${fighter.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`;
-				} else if (fighter.bellyImplant > 10000) {
-					return `${His} huge, ${fighter.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`;
-				} else if (fighter.bellyImplant > 5000) {
-					return `${His} large, ${fighter.bellyImplant}cc implant-filled belly is heavy and unwieldy, rendering ${him} less effective.`;
-				} else if (fighter.bellyImplant > 1500) {
-					return `${His} swollen, ${fighter.bellyImplant}cc implant-filled belly is heavy and makes ${him} less effective.`;
-				}
-			}
-		}
-
-		function labor() {
-			if (isInLabor(fighter)) {
-				return `${He}'s feeling labor pains. ${His} ${fighter.pregType > 1 ? `children are` : `child is`} ready to be born, oblivious to the fact that it will put ${fighter.pregType > 1 ? `their` : `its`} mother at the mercy of ${his} opponent.`;
-			} else if (fighter.preg > fighter.pregData.normalBirth && fighter.pregControl !== "labor suppressors") {
-				return `${He}'ll be going into labor any time now and ${he} knows it. ${He}'s terrified of the thought of ${his} water breaking during the fight.`;
-			}
-		}
-
-		function bellyFluid() {
-			if (fighter.bellyFluid > 10000) {
-				return `${His} hugely bloated, ${fighter.inflationType}-filled belly is taut and painful, hindering ${his} ability to fight.`;
-			} else if (fighter.bellyFluid > 5000) {
-				return `${His} bloated, ${fighter.inflationType}-stuffed belly is constantly jiggling and moving, distracting ${him} and throwing off ${his} weight.`;
-			} else if (fighter.bellyFluid > 2000) {
-				return `${His} distended, ${fighter.inflationType}-belly is uncomfortable and heavy, distracting ${him}.`;
-			}
-		}
-
-		function sight() {
-			if (!canSee(fighter)) {
-				return `${His} lack of eyesight means certain defeat.`;
-			} else if (!canSeePerfectly(fighter)) {
-				return `${His} poor eyesight makes ${him} a weaker fighter.`;
-			}
-		}
-
-		function hearing() {
-			if (!canHear(fighter)) {
-				return `${His} lack of hearing is a major detriment.`;
-			} else if ((fighter.hears === -1 && fighter.earwear !== "hearing aids") || (fighter.hears === 0 && fighter.earwear === "muffling ear plugs")) {		// TODO: replace with canHearPerfectly
-				return `${His} poor hearing is a minor detriment.`;
-			}
-		}
-
-		function prosthetics() {
-			if (hasAnyProstheticLimbs(fighter) && !hasAnyQuadrupedLimbs(fighter)) {
-				const r = [];
-
-				r.push(`The pit lights gleam on ${his} P-Limbs.`);
-
-				if (getLimbCount(fighter, 6) > 0) {
-					r.push(`${His} advanced cybernetic limbs are faster than natural limbs, and their force is amplified, so that they can become potent weapons.`);
-				} else if (getLimbCount(fighter, 5) > 0) {
-					r.push(`Though their integral weapons are disabled, ${his} upgraded prosthetics are almost as fast as natural limbs, and they can hit much, much harder.`);
-				}
-
-				return r.join(' ');
-			}
-		}
-		if (hasAnyProstheticLimbs(fighter) && hasAnyQuadrupedLimbs(fighter)) {
-			const r = [];
-
-			r.push(`The pit lights gleam on ${his} prosthetic limbs. They have the advantage of being quadrupedal, keeping ${him} low to the ground and providing better mobility.`);
-			return r.join(' ');
-		}
-	}
-
-	/**
-	 * @param {DocumentFragment} parent
-	 */
-	function fight(parent) {
-		const r = [];
-
-		if (animal) {
-			const slave = getSlave(fighters[0]);
-			const {he, him, his, He} = getPronouns(slave);
-
-			const approves = slave.devotion > 50 || (slave.devotion > 20 && (slave.fetish === "masochist" || slave.fetish === "humiliation" || slave.sexualQuirk === "perverted" || slave.behavioralQuirk === "sinful"));
-
-			// TODO: expand this with more fight variants
-			r.push(`The ${animal.name} isn't in a hurry and slowly saunters towards the ${approves ? `determined` : `terrified`} slave. After what appears to be a moment of deliberation, ${he} finally makes ${his} move. ${He} starts ${canRun ? `running` : `moving as quickly as ${he} can`} in the opposite direction. The ${animal.species} follows suit and breaks out into a full sprint towards ${him}.`);
-
-			// TODO: expand this to rely more on slave's ability to run
-			if (winner.hasOwnProperty('slaveName')) {
-				r.push(`${slave.slaveName} is quick, though, and manages to avoid the animal for the full five minutes. ${He} drops to ${his} knees in relief and exhaustion once the bell sounds and the animal is leashed and pulled back into its pen.`);
-
-				if (V.pit.audience === "paid") {
-					r.push(`The audience is fairly impressed with this impressive display of sportsmanship, and your `, App.UI.DOM.makeElement('span', `cut of the betting`, ["cash", "inc"]), ` is equally impressive.`);
-
-					cashX(2500, "pit", slave);
-				} else if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement('span', `fairly impressed`, ["reputation", "inc"]), ` with this impressive display of sportsmanship.`);
-
-					repX(250, "pit", slave);
-				}
-			} else {
-				const minutesLasted = random(2, 5);
-				const secondsLasted = random(15, 45);
-
-				if (canRun) {
-					r.push(`${slave.slaveName} is quick, but not quick enough. ${He} manages to last almost ${num(minutesLasted)} full minutes before the ${animal.name} finally manages to catch ${him}.`);
-				} else {
-					r.push(`${slave.slaveName} isn't quick enough to avoid the beast, and only manages to last a pitiful ${num(secondsLasted)} seconds before the ${animal.name} catches ${him}.`);
-				}
-
-				if (V.pit.audience === "paid") {
-					r.push(`Your audience is not very impressed with this mediocre display, and your `, App.UI.DOM.makeElement('span', `cut of the betting`, ["cash", "inc"]), ` is equally unimpressive.`);
-
-					cashX(500, "pit", slave);
-				} else if (V.pit.audience === "free") {
-					r.push(`Your audience is `, App.UI.DOM.makeElement('span', `not very impressed`, ["reputation", "inc"]), ` with this mediocre display.`);
-
-					repX(25, "pit", slave);
-				}
-			}
-		} else {
-			const winnerDeadliness = deadliness(winner).value;
-			const loserDeadliness = deadliness(loser).value;
-
-			const {he, his, him, himself, girl, He} = getPronouns(winner);
-			const {
-				he: he2,
-				his: his2,
-				him: him2,
-				himself: himself2,
-				girl: girl2,
-				He: He2,
-				His: His2,
-			} = getPronouns(loser);
-
-			if (!canSee(winner) && !canSee(loser)) {
-				r.push(`${winner.slaveName} and ${loser.slaveName} are both blind, making the fight a staredown. Neither slave wants to make the first move, especially with the drowning cacophony coming from the jeering crowd. Slowly, ${winner.slaveName} moves forward, waving feeling for ${his} opponent before ${he} ${himself} gets found. ${loser.slaveName}'s hand meets ${winner.slaveName}'s and the two move to grab each other in a headlock. The two slaves violently thrash against each other, suffering more and more strikes as the struggle goes on. Eventually, ${loser.slaveName} can take no more and releases ${his2} grip on ${winner.slaveName} neck. It takes a moment for ${winner.slaveName} to stop wrestling the submitting ${loser.slaveName} and accept ${his} victory.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `surprised`, ["reputation", "inc"]), ` by the impromptu wrestling match.`);
-
-					repX(50, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is surprised by the sudden wrestling match, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is modest.`);
-
-					cashX(500, "pit", winner);
-				}
-			} else if (winnerDeadliness > (loserDeadliness + 1) && getArmCount(winner, 6) > 1) {
-				r.push(`Upon your word the two combatants approach each other. ${winner.slaveName} keeps ${his} advanced cybernetic limbs up in a protective position. ${loser.slaveName} probes ${him} with some light blows, puzzled by this ironclad defense. Gradually, ${he2} hits harder and harder, ${his2} opponent grunting under the impacts but holding steady. Finally, ${loser.slaveName} tires, gets off balance, and ${winner.slaveName} manages to grab ${his2} forearm. ${winner.slaveName}'s limbs emit an electric shock that temporarily incapacitates ${his} opponent. ${winner.slaveName} uses ${his} grip to pull ${his} stunned opponent in and grab ${his2} neck with the other hand, using it to exert just the right amount of pressure to choke ${him2} out harmlessly. Though the fight was short,`);
-
-				if (V.pit.audience === "free") {
-					r.push(`the audience is `, App.UI.DOM.makeElement("span", `very impressed`, ["reputation", "inc"]), ` by the display.`);
-
-					repX(100, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`the audience is quite impressed by the display, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is quite good.`);
-
-					cashX(2000, "pit", winner);
-				}
-			} else if (winnerDeadliness > (loserDeadliness + 1) && getArmCount(winner, 5) > 1) {
-				r.push(`Upon your word the two combatants approach each other. ${winner.slaveName} keeps ${his} artificial limbs up in a protective position. ${loser.slaveName} probes ${him} with some light blows, puzzled by this ironclad defense. Gradually, ${he2} hits harder and harder, ${his2} opponent grunting under the impacts but holding steady. Finally, ${loser.slaveName} overcommits to a body blow, and ${winner.slaveName} grips ${his2} forearm. That is the end. The augmented grip is effectively unbreakable, and ${winner.slaveName} uses it to pull ${his} opponent in and grab ${his2} neck with the other hand, using it to exert just the right amount of pressure to choke ${him2} out harmlessly. Though the fight was short,`);
-
-				if (V.pit.audience === "free") {
-					r.push(`the audience is `, App.UI.DOM.makeElement("span", `very impressed`, ["reputation", "inc"]), ` by the display.`);
-
-					repX(100, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`the audience is quite impressed by the display, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is quite good.`);
-
-					cashX(2000, "pit", winner);
-				}
-			} else if (!canSee(winner)) {
-				r.push(`${winner.slaveName} centers ${himself} and hones in on ${loser.slaveName}'s rapid breath. ${He} readies ${himself}, knowing ${he} has a single chance to win. With heavy steps, ${loser.slaveName} rushes ${him}, fully prepared to tackle the helpless combatant. ${winner.slaveName} gambles everything on a single high punch, a strike that slams ${loser.slaveName}'s undefended neck. ${loser.slaveName} falls to the ground before the panicking ${winner.slaveName}, who quickly pins the coughing loser.`);
-
-				healthDamage(winner, 80);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `awestruck`, ["reputation", "inc"]), ` by the blind ${girl}'s triumph.`);
-
-					repX(200, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is awestruck by the blind ${girl}'s triumph, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is enormous.`);
-
-					cashX(4000, "pit", winner);
-				}
-			} else if (!canSee(loser)) {
-				r.push(`${winner.slaveName} grins at ${loser.slaveName}'s random swings and poor form. ${He} centers in on ${his} favorite part of ${loser.slaveName}'s body before rushing between ${his2} strikes and tackling ${him2} to the ground. ${loser.slaveName} lays there, helpless to stop ${winner.slaveName} from molesting ${him2}.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `annoyed`, ["reputation", "dec"]), ` by this lack of a fight.`);
-
-					repX(-20, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience found the fight embarrassing, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is pitiful.`);
-
-					cashX(40, "pit", winner);
-				}
-			} else if (winnerDeadliness > (loserDeadliness + 3)) {
-				if (winner.skill.combat > 30) {
-					r.push(`${winner.slaveName} wants to win, and ${he} opens the fight with a furious attack. ${loser.slaveName} manages to get ${his2} ${hasBothArms(loser) ? `forearms` : `forearm`} up, blocking a few blows, but by doing so leaves ${his2} abdomen open and obscures ${his2} vision enough that ${he2} is unprepared for the following kidney strike, which brings ${him2} gasping to one knee. ${winner.slaveName} lets ${him2} rise just a little before delivering a calculated hard right that sends ${loser.slaveName} to the mat.`);
-
-					if (V.pit.audience === "free") {
-						r.push(`The audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]), ` by this execution.`);
-
-						repX(25, "pit", winner);
-					} else if (V.pit.audience === "paid") {
-						r.push(`The audience is not very impressed by this execution, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is unimpressive.`);
-
-						cashX(500, "pit", winner);
-					}
-				} else {
-					r.push(`${winner.slaveName} wants to win and is confident ${he} will, but ${he} isn't particularly sure about how to do so. ${He} fights cautiously, mostly hitting ${loser.slaveName} from afar. Slowly, the rain of blows begins to tell, opening ${loser.slaveName}'s lip, giving ${him2} a bloody nose, and bruising ${his2} face. Realizing ${he2} has to do something, ${loser.slaveName} makes a desperate counterattack, `, App.UI.DOM.makeElement("span", `dripping blood`, ["health", "dec"]), ` as ${he2} goes. As ${he2} does ${he2} manages to get ${his2} face in the way of another of ${winner.slaveName}'s inexpert strikes and goes down hard. ${He2} makes to rise, but ${winner.slaveName} decides the fight by the simple expedient of kicking ${him2} in the crotch.`);
-
-					healthDamage(winner, 20);
-
-					if (V.pit.audience === "free") {
-						r.push(`The audience is `, App.UI.DOM.makeElement("span", `reasonably impressed`, ["reputation", "inc"]), ` by the beating.`);
-
-						repX(50, "pit", winner);
-					} else if (V.pit.audience === "paid") {
-						r.push(`The audience is reasonably impressed by the beating, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is reasonable.`);
-
-						cashX(100, "pit", winner);
-					}
-				}
-			} else if (winner.belly > 60000 && loser.belly > 60000) {
-				r.push(`${winner.slaveName} and ${loser.slaveName} stare each other down and both come to a realization. Neither can reach the other around their massive bellies. Instead, they choose to ram their bulk into each other in hopes of toppling the weaker. After a drawn out struggle, both slaves' middles are `, App.UI.DOM.makeElement("span", `dark red and shuddering,`, ["health", "dec"]), ` ready to burst open. Rather than continue, ${loser.slaveName} lets the next strike down ${him2} hoping that the outcome of this fight isn't fatal.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `very impressed`, ["reputation", "dec"]), ` by the showdown.`);
-
-					repX(75, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is very impressed by the showdown, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is good.`);
-
-					cashX(1500, "pit", winner);
-				}
-			} else if (winner.belly > 60000 && loser.belly < 30000) {
-				r.push(`${loser.slaveName} spies an easy win against ${his2} massively bloated opponent and rushes in to topple ${winner.slaveName}. In an effort to defend ${himself}, ${winner.slaveName} hoists ${his} belly and turns suddenly, accidentally impacting ${loser.slaveName} with ${his} massive middle and knocking ${him2} to the ground. Seeing an opportunity, ${winner.slaveName} releases ${his} grip and slams ${his} weighty womb down on ${loser.slaveName}, bashing the wind out of ${him2}. ${loser.slaveName} struggles to slip out from under the mass, but the weight is too great and ${he2} passes out.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `impressed`, ["reputation", "dec"]), ` by this absurd win.`);
-
-					repX(50, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is impressed by this absurd win, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is reasonably.`);
-
-					cashX(1000, "pit", winner);
-				}
-			} else if (winner.skill.combat > 30 && loser.skill.combat > 30) {
-				const healthSpans = [App.UI.DOM.makeElement("span", `broken nose`, ["health", "dec"]), App.UI.DOM.makeElement("span", `to the point of damage`, ["health", "dec"])];
-
-				r.push(`Upon your word the two combatants approach each other warily, both knowing the other is reasonably competent. Before long they are trading expert blows. ${winner.slaveName} is getting the worst of it, so ${he} decides to change the nature of the fight. After three tries ${he} manages to bring ${loser.slaveName} to the ground, suffering a `, healthSpans[0], ` as ${he} does. ${loser.slaveName} tries to break the imperfect hold but only earns ${himself2} an elbow to the face. ${He2}'s furious and ${winner.slaveName} is obliged to wrench ${his2} arm `, healthSpans[1], ` before ${he2} allows ${himself2} to go limp.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `very impressed`, ["reputation", "inc"]), ` by the expert fight.`);
-
-					repX(100, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is quite impressed by the expert fight, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is quite good.`);
-
-					cashX(2000, "pit", winner);
-				}
-			} else if (winner.height - loser.height < -10) {
-				r.push(`${winner.slaveName} realizes that ${loser.slaveName}'s wingspan gives ${him2} a huge reach advantage. ${He} bores straight in, taking a hit or two but coming on regardless. ${loser.slaveName} understands ${his2} opponent's intention and backs off, but the pit is small and there isn't much room to retreat. When ${his2} back hits a padded wall, ${winner.slaveName} manages to land a light hit to ${his2} stomach that leaves ${loser.slaveName} winded enough that a hard kick to the side of ${his2} knee goes undefended. It causes `, App.UI.DOM.makeElement("span", `considerable damage,`, ["health", "dec"]), ` dropping ${him2} and ending the fight.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `reasonably impressed`, ["reputation", "inc"]), ` by the takedown.`);
-
-					repX(50, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is reasonably impressed by the takedown, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is reasonable.`);
-
-					cashX(1000, "pit", winner);
-				}
-			} else if (loser.piercing.eyebrow.weight > 0) {
-				r.push(`The fight starts slowly, with the two trading jabs. Just as the spectators are getting bored, ${loser.slaveName} takes a glancing blow to the eyebrow. ${His2} piercing catches on ${winner.slaveName}'s glove and tears out. ${loser.slaveName} goes after ${his2} tormentor in fury, streaming blood, the piercing forgotten on the mat. Any tendency ${winner.slaveName} might have had to feel badly about this is extinguished by the assault, and soon ${winner.slaveName} is even willing to follow up on the success by targeting pierced body parts. The fight ends with poor ${loser.slaveName} writhing in pain on the mat, `, App.UI.DOM.makeElement("span", `leaking blood`, ["health", "dec"]), ` from several terribly shredded areas.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `reasonably impressed`, ["reputation", "inc"]), ` by the gory spectacle.`);
-
-					repX(50, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is reasonably impressed by the gory spectacle, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is reasonable.`);
-
-					cashX(1000, "pit", winner);
-				}
-			} else if (winner.muscles > 30) {
-				r.push(`${winner.slaveName} is so massively muscular that ${he}'s actually impeded by ${his} size. ${loser.slaveName} is properly afraid of ${his} strength, though, so ${he2} tries to stay away as much as ${he2} can. The pit isn't large, however, and eventually ${winner.slaveName} manages to lay a hand on ${him2}. ${He} pulls ${him2} down, and then it's all over but the beating. ${loser.slaveName} rains blows on ${his2} huge oppressor, but all ${winner.slaveName} has to do is hold on with one arm and deliver damage with the other. By the time ${he2} gives up and goes limp, ${loser.slaveName} has collected `, App.UI.DOM.makeElement("span", `many minor injuries.`, ["health", "dec"]));
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `reasonably impressed`, ["reputation", "inc"]), ` by the show of strength.`);
-
-					repX(50, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is reasonably impressed by the show of strength, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is reasonable.`);
-
-					cashX(1000, "pit", winner);
-				}
-			} else if (loser.belly > 300000) {
-				r.push(`${winner.slaveName} wants to win badly enough that ${he} takes an extremely brutal shortcut to victory. The instant the fight starts, ${he} quickly knees ${loser.slaveName} in the stomach. The massively swollen ${loser.slaveName} goes down with a loud thud and plenty of jiggling. ${winner.slaveName} gloats over the struggling ${loser.slaveName} watching as ${he2} is unable to pull ${his2} bloated form off the ground.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]), ` by this easy win.`);
-
-					repX(50, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is not very impressed by this easy win, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is unimpressive.`);
-
-					cashX(500, "pit", winner);
-				}
-			} else if (loser.boobs > 1200) {
-				r.push(`${winner.slaveName} wants to win badly enough that ${he} takes an extremely simple shortcut to victory. The instant the fight starts, ${he} hits ${loser.slaveName} right in ${his2} huge tits, as hard as ${he} can. This is a sucker punch of the worst kind; ${loser.slaveName}'s boobs are so big that ${he2} has no real chance of defending them. ${He2} gasps with pain${hasAnyArms(loser) ? ` and wraps ${his2} ${hasBothArms(loser) ? `arms` : `arm`} around ${his2} aching bosom` : ``}, giving ${winner.slaveName} a clear opening to deliver a free and easy blow to the jaw that sends the poor top-heavy slave to the mat. Any chance of ${loser.slaveName} rising is extinguished by ${his2} breasts; it takes ${him2} so long to muster an attempt to get up that ${winner.slaveName} can rain hits on ${him2} while ${he2} does.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]), ` by this easy win.`);
-
-					repX(25, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is not very impressed by this easy win, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is unimpressive.`);
-
-					cashX(500, "pit", winner);
-				}
-			} else if (loser.dick > 0) {
-				r.push(`${winner.slaveName} wants to win badly enough that ${he} takes an extremely unpleasant shortcut to victory. The instant the fight starts, ${he} furiously goes for ${loser.slaveName}'s eyes${hasBothArms(winner) ? `, hands forming claws` : hasAnyArms(winner) ? `, ${his} hand forming a claw` : ``}. ${loser.slaveName} ${hasAnyArms(loser) ? `defends ${himself2} with ${his2} ${hasBothArms(loser) ? `arms` : `arm`}` : `tries to defend ${himself} as best ${he} can`}, at which point ${winner.slaveName} delivers a mighty cunt punt. ${loser.slaveName} goes straight down, ${his2} mouth soundlessly opening and closing and tears leaking from ${his2} closed eyes${hasAnyArms(loser)
-					? ` while ${his} ${hasBothArms(loser)
-						? `hands desperately shield`
-						: `hand desperately shields`} ${his2} outraged pussy`
-					: ``}. ${winner.slaveName} follows ${him2} down and puts the unresisting ${girl2}'s head in a simple lock.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]), ` by this easy win.`);
-
-					repX(25, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is not very impressed by this easy win, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is unimpressive.`);
-
-					cashX(500, "pit", winner);
-				}
-			} else if (loser.vagina > 0) {
-				r.push(`${winner.slaveName} wants to win badly enough that ${he} takes an extremely unpleasant shortcut to victory. The instant the fight starts, ${he} furiously goes for ${loser.slaveName}'s eyes${hasBothArms(winner) ? `, hands forming claws` : hasAnyArms(winner) ? `, ${his} hand forming a claw` : ``}. ${loser.slaveName} ${hasAnyArms(loser) ? `defends ${himself2} with ${his2} ${hasBothArms(loser) ? `arms` : `arm`}` : `tries to defend ${himself} as best ${he} can`}, at which point ${winner.slaveName} delivers a mighty cunt punt. ${loser.slaveName} goes straight down, ${his2} mouth soundlessly opening and closing and tears leaking from ${his2} closed eyes${hasAnyArms(loser) ? ` while ${his} ${hasBothArms(loser) ? `hands` : `hand`} desperately shield${!hasBothArms(loser) ? `s` : ``} ${his2} outraged pussy` : ``}. ${winner.slaveName} follows ${him2} down and puts the unresisting ${girl2}'s head in a simple lock.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]), ` by this easy win.`);
-
-					repX(25, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					r.push(`The audience is not very impressed by this easy win, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]), ` is unimpressive.`);
-
-					cashX(500, "pit", winner);
-				}
-			} else {
-				r.push(`${winner.slaveName} wants to win badly enough that ${he} takes an extremely unpleasant shortcut to victory. The instant the fight starts, ${he} furiously goes for ${loser.slaveName}'s eyes, hands forming claws. ${loser.slaveName} defends ${himself2} with ${his2} arms, at which point ${winner.slaveName} delivers a clenched fist to ${loser.slaveName}'s throat. ${loser.slaveName} staggers back, wheezing for breath with tears leaking from ${his2} closed eyes. ${winner.slaveName} takes advantage of ${loser.slaveName}'s vulnerability to quickly trip and pin the coughing loser.`);
-
-				if (V.pit.audience === "free") {
-					r.push(`The audience is `, App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]), ` by this easy win.`);
-
-					repX(25, "pit", winner);
-				} else if (V.pit.audience === "paid") {
-					const cashSpan = App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]);
-
-					r.push(`The audience is not very impressed by this easy win, and your `, cashSpan, ` is unimpressive.`);
-
-					cashX(500, "pit", winner);
-				}
-			}
-		}
-
-		App.Events.addParagraph(parent, r);
-	}
-
-	/** @param {DocumentFragment} parent */
-	function postFight(parent) {
-		let r = [];
-
-		const anus = "anus";
-		const cunt = "cunt";
-		const oral = "oral";
-		const vaginal = "vaginal";
-		const anal = "anal";
-
-		if (animal) {
-			if (winner.hasOwnProperty('species')) {
-				// TODO: add effects (gain masochist, etc)
-				const slave = getSlave(fighters[0]);
-				const {him, his} = getPronouns(slave);
-
-				const approves = slave.devotion > 50 || (slave.devotion > 20 && (slave.fetish === "masochist" || slave.fetish === "humiliation" || slave.sexualQuirk === "perverted" || slave.behavioralQuirk === "sinful"));
-				const isVirgin = (canDoVaginal(slave) && slave.vagina === 0) || (canDoAnal(slave) && slave.anus === 0);
-
-				const pussy = ['pussy', 'cunt', 'slit'];
-				const asshole = ['asshole', 'rear hole', 'anus'];
-				const mouth = ['mouth', 'throat'];
-
-				const orifice = () => canDoVaginal(slave) ? either(pussy) : canDoAnal(slave) ? either(asshole) : either(mouth);
-				const consummation = App.UI.DOM.makeElement('span', `breaks in`, ["virginity", "loss"]);
-
-				// TODO: redo this to better account for oral
-				r.push(`It ${animal.type === "hooved" ? `headbutts ${him}` : `swipes at ${his} ${hasAnyLegs(slave) ? hasBothLegs(slave) ? `legs` : `leg` : `lower body`}`}, causing ${him} to go down hard. The ${animal.name} doesn't waste a moment, and mounts ${him} quicker than you thought was possible${animal.type === "hooved" ? ` for ${animal.articleAn} ${animal.name}` : ``}. It takes a few tries, but it finally manages to sink its ${animal.dick.desc} cock into ${slave.slaveName}'s ${orifice()}, causing${V.pit.audience !== 'none' ? ` the crowd to go wild and` : ``} the slave to give a long, loud, drawn-out ${approves ? `moan` : `scream`} as its ${animal.dick.desc} dick `, isVirgin ? consummation : `fills`, `${his} ${orifice()}. Without pausing for even a second, it begins to steadily thrust, pounding ${him} harder and harder as it gets closer and closer to climax. After several minutes, you see the animal ${animal.type === "canine" ? `push its knot into ${slave.slaveName}'s ${orifice()} and` : ``} finally stop thrusting while the barely-there slave gives a loud ${approves ? `moan` : `groan`}. ${V.pit.audience !== "none" ? `The crowd gives a loud cheer as the` : `The`} animal pulls out, leaving the thoroughly fucked-out ${slave.slaveName} lying there, ${animal.species} cum streaming out of ${his} ${orifice()}.`);
-
-				if (canDoVaginal(slave)) {
-					seX(slave, 'vaginal', 'animal');
-					slave.vagina = slave.vagina < animal.dick.size ? animal.dick.size : slave.vagina;
-				} else if (canDoAnal(slave)) {
-					seX(slave, 'anal', 'animal');
-					// @ts-ignore
-					slave.anus = Math.max(slave.anus, stretchedAnusSize(animal.dick.size));
-				} else {
-					seX(slave, 'oral', 'animal');
-				}
-			}
-		} else {
-			const {he, his, him, He} = getPronouns(winner);
-			const {his: his2, him: him2} = getPronouns(loser);
-
-			const facefuck = `${He} considers ${his} options briefly, then hauls the loser to ${his2} knees for a facefuck.`;
-			const winnerPenetrates = orifice => `${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`}, and penetrates the loser's ${orifice}.`;
-			const loserProtest = `${canTalk(loser)
-				? `${loser.slaveName} starts to scream a protest to stop ${winner.slaveName} raping ${him2} pregnant, but ${winner.slaveName} grinds ${his2} face into the mat to shut ${him2} up`
-				: `${loser.slaveName} tries to gesture a protest before ${winner.slaveName} fills ${his2} fertile ${loser.mpreg && V.pit.virginities !== anal ? `asspussy` : `pussy`} with cum, but ${winner.slaveName} grabs ${his2} ${hasBothArms(loser) ? `hands and pins them` : hasAnyArms(loser) ? `hand and pins it` : `neck firmly`} to keep ${him2} from complaining`}.`;
-
-			const virginitySpan = App.UI.DOM.makeElement("span", ``, ["virginity", "loss"]);
-
-			r.push(`You throw the victor's strap-on down to ${winner.slaveName}.`);
-
-			if (canPenetrate(winner)) {
-				r.push(`${He} has no need of it, only taking a moment to pump ${his} dick a few times to get it to rock hardness.`);
-			} else if (winner.clit > 4) {
-				r.push(`${He} has no need of it, since ${his} clit is big enough to use instead.`);
-			} else if (winner.dick > 6 && !canAchieveErection(winner)) {
-				r.push(`${He} needs it, since ${his} enormous dick can't get hard any longer (not like it would fit in ${loser.slaveName} anyway).`);
-			} else if (winner.dick > 0) {
-				r.push(`${He} needs it, since ${his} soft dick won't be raping anything.`);
-			}
-
-			if (V.pit.virginities === "all") {
-				if (loser.vagina === 0 && canDoVaginal(loser) && loser.anus === 0 && canDoAnal(loser)) {
-					r.push(`${He} respects ${loser.slaveName}'s virgin holes, and hauls the loser to ${his2} knees for a facefuck.`);
-
-					actX(loser, oral);
-				} else if (loser.vagina === 0 && canDoVaginal(loser) && canDoAnal(loser)) {
-					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
-
-					if (winner.fetish === "pregnancy") {
-						r.push(`and, after ${canSee(winner) ? `eyeing` : `feeling up`} ${his2} virgin vagina with desire, penetrates the loser's anus.`);
-					} else {
-						r.push(`and respects the rules by penetrating the loser's anus.`);
-					}
-
-					if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 1, winner.ID);
-					}
-
-					actX(loser, anal);
-				} else if (loser.anus === 0 && canDoVaginal(loser) && canDoAnal(loser)) {
-					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
-
-					if (winner.fetish === "buttslut" || (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg && winner.fetish === "pregnancy")) {
-						r.push(`and, after ${canSee(winner) ? `eyeing` : `feeling up`} ${his2} virgin anus with desire, penetrates the loser's cunt.`);
-					} else {
-						r.push(`and respects the rules by penetrating the loser's cunt.`);
-					}
-
-					if (canPenetrate(winner) && canImpreg(loser, winner)) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 0, winner.ID);
-					}
-
-					actX(loser, vaginal);
-				} else if (canDoVaginal(loser)) {
-					r.push(winnerPenetrates(cunt));
-
-					if (canPenetrate(winner) && canImpreg(loser, winner)) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 0, winner.ID);
-					}
-
-					actX(loser, vaginal);
-				} else if (canDoAnal(loser)) {
-					r.push(winnerPenetrates(anus));
-
-					if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 1, winner.ID);
-					}
-
-					actX(loser, anal);
-				} else {
-					r.push(facefuck);
-
-					actX(loser, oral);
-				}
-			} else if (V.pit.virginities === "anal") {
-				if (loser.vagina === 0 && canDoVaginal(loser)) {
-					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
-
-					if (winner.fetish === "pregnancy") {
-						virginitySpan.append(`take ${his2} virginity.`);
-						r.push(`and gleefully takes advantage of your rules to `, virginitySpan);
-					} else {
-						virginitySpan.append(`breaks in ${his2} virgin vagina.`);
-						r.push(`and `, virginitySpan);
-					}
-
-					if (canPenetrate(winner) && canImpreg(loser, winner)) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 0, winner.ID);
-					}
-
-					loser.vagina++;
-					actX(loser, vaginal);
-				} else if (loser.anus === 0 && canDoAnal(loser)) {
-					r.push(`${canTalk(loser)
-						? `${loser.slaveName} starts to scream a protest to stop ${winner.slaveName} raping ${him2} pregnant, but ${winner.slaveName} grinds ${his2} face into the mat to shut ${him2} up`
-						: `${loser.slaveName} tries to gesture a protest before ${winner.slaveName} fills ${his2} fertile pussy with cum, but ${winner.slaveName} grabs ${his2} ${hasBothArms(loser) ? `hands and pins them` : hasAnyArms(loser) ? `hand and pins it` : `neck firmly`} to keep ${him2} from complaining`}.`);
-
-					if (winner.fetish === "buttslut" || (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg && winner.fetish === "pregnancy")) {
-						if (canDoVaginal(loser)) {
-							r.push(`and penetrates the loser's cunt.`);
-
-							if (canPenetrate(winner) && canImpreg(loser, winner)) {
-								r.push(loserProtest);
-
-								knockMeUp(loser, 50, 0, winner.ID);
-							}
-
-							loser.counter.vaginal++;
-							V.vaginalTotal++;
-						} else {
-							r.push(`and finds only a pristine butthole waiting for ${him}. Respecting ${his2} anal virginity, ${he} hauls the loser onto ${his2} knees for a facefuck.`);
-
-							actX(loser, oral);
-						}
-					}
-				} else if (canDoVaginal(loser)) {
-					r.push(winnerPenetrates(cunt));
-
-					if (canPenetrate(winner) && canImpreg(loser, winner)) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 0, winner.ID);
-					}
-
-					actX(loser, vaginal);
-				} else if (canDoAnal(loser)) {
-					r.push(winnerPenetrates(anus));
-
-					if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 1, winner.ID);
-					}
-
-					actX(loser, anal);
-				} else {
-					r.push(facefuck);
-
-					actX(loser, oral);
-				}
-			} else if (V.pit.virginities === "vaginal") {
-				if (loser.vagina === 0 && canDoVaginal(loser)) {
-					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
-
-					if (winner.fetish === "pregnancy") {
-						if (canDoAnal(loser)) {
-							r.push(`and hungrily eyes ${his2} pristine vagina before penetrating the loser's ass.`);
-
-							if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
-								r.push(loserProtest);
-
-								knockMeUp(loser, 50, 1, winner.ID);
-							}
-
-							actX(loser, anal);
-						} else {
-							r.push(`and hungrily eyes ${his2} pristine vagina before hauling the loser onto ${his2} knees for a facefuck.`);
-
-							actX(loser, oral);
-						}
-					} else {
-						if (canDoAnal(loser)) {
-							r.push(`and penetrates the loser's ass.`);
-
-							if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
-								r.push(loserProtest);
-
-								knockMeUp(loser, 50, 1, winner.ID);
-							}
-
-							actX(loser, anal);
-						} else {
-							r.push(`and finds only a pristine butthole waiting for ${him}. Respecting ${his2} anal virginity, ${he} hauls the loser onto ${his2} knees for a facefuck.`);
-
-							actX(loser, oral);
-						}
-					}
-				} else if (loser.anus === 0 && canDoAnal(loser)) {
-					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
-
-					if (winner.fetish === "buttslut" || (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg && winner.fetish === "pregnancy")) {
-						virginitySpan.append(`take ${his2} anal virginity.`);
-						r.push(`and gleefully takes advantage of your rules to `, virginitySpan);
-					} else {
-						virginitySpan.append(`breaks in ${his2} virgin anus.`);
-						r.push(`and `, virginitySpan);
-					}
-
-					if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 1, winner.ID);
-					}
-
-					loser.anus++;
-					actX(loser, anal);
-				} else if (canDoVaginal(loser)) {
-					r.push(winnerPenetrates(cunt));
-
-					if (canPenetrate(winner) && canImpreg(loser, winner)) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 0, winner.ID);
-					}
-
-					actX(loser, vaginal);
-				} else if (canDoAnal(loser)) {
-					r.push(winnerPenetrates(anus));
-
-					if (canPenetrate(winner) && canImpreg(loser, winner)) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 0, winner.ID);
-					}
-
-					actX(loser, anal);
-				} else {
-					r.push(facefuck);
-
-					actX(loser, oral);
-				}
-			} else {
-				if (loser.vagina === 0 && canDoVaginal(loser)) {
-					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
-
-					if (winner.fetish === "pregnancy") {
-						virginitySpan.append(`take ${his2} virginity.`);
-						r.push(`and gleefully takes advantage of your rules to `, virginitySpan);
-					} else {
-						virginitySpan.append(`breaks in ${his2} virgin vagina.`);
-						r.push(`and `, virginitySpan);
-					}
-
-					if (canPenetrate(winner) && canImpreg(loser, winner)) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 0, winner.ID);
-					}
-
-					loser.vagina++;
-					actX(loser, vaginal);
-				} else if (loser.anus === 0 && canDoAnal(loser)) {
-					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
-
-					if (winner.fetish === "buttslut" || (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg && winner.fetish === "pregnancy")) {
-						virginitySpan.append(`take ${his2} anal virginity.`);
-						r.push(`and gleefully takes advantage of your rules to `, virginitySpan);
-					} else {
-						virginitySpan.append(`breaks in ${his2} virgin anus.`);
-						r.push(`and `, virginitySpan);
-					}
-
-					if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 1, winner.ID);
-					}
-
-					loser.anus++;
-					actX(loser, anal);
-				} else if (canDoVaginal(loser)) {
-					r.push(winnerPenetrates(cunt));
-
-					if (canPenetrate(winner) && canImpreg(loser, winner)) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 0, winner.ID);
-					}
-
-					actX(loser, vaginal);
-				} else if (canDoAnal(loser)) {
-					r.push(winnerPenetrates(anus));
-
-					if (canPenetrate(winner) && canImpreg(loser, winner)) {
-						r.push(loserProtest);
-
-						knockMeUp(loser, 50, 1, winner.ID);
-					}
-
-					actX(loser, anal);
-				} else {
-					r.push(facefuck);
-
-					actX(loser, oral);
-				}
-			}
-
-			App.Events.addParagraph(parent, r);
-
-			App.Events.addParagraph(parent, [...rape(), ...rapeEffects()]);
-
-			r = [];
-			if (winner.skill.combat < 60) {
-				const experienceSpan = App.UI.DOM.makeElement("span", `improved ${his} combat skills.`, ["improvement"]);
-
-				winner.skill.combat += 5 + Math.floor(0.5 * (winner.intelligence + winner.intelligenceImplant) / 32);
-				r.push(`With experience in ${V.pit.name}, ${winner.slaveName} has `, experienceSpan);
-			}
-
-			loser.counter.pitLosses++;
-			actX(winner, "penetrative");
-
-			winner.counter.pitWins++;
-		}
-
-		V.pitFightsTotal++;
-
-		App.Events.addParagraph(parent, r);
-
-		function rape() {
-			const repSpan = App.UI.DOM.makeElement("span", ``, ["reputation", "inc"]);
-
-			const r = [];
-
-			const {he, his, He} = getPronouns(winner);
-			const {he: he2, his: his2, him: him2, girl: girl2} = getPronouns(loser);
-
-			if (winner.sexualFlaw === "malicious") {
-				r.push(`${winner.slaveName} lives to torment and violate slaves. ${He} uses ${loser.slaveName} for ${his} `, App.UI.DOM.makeElement("span", `pleasure`, ["devotion", "inc"]), ` slapping ${him2} viciously, pinching ${him2} until ${he} draws blood, and showing off for the spectators.`);
-
-				if (V.pit.audience !== "none") {
-					repSpan.append(`greatly enjoys`);
-					r.push(`The audience `, repSpan, ` the depraved spectacle.`);
-
-					repX(50, "pit", winner);
-				}
-
-				winner.devotion++;
-			} else if (winner.sexualFlaw === "abusive") {
-				r.push(`${winner.slaveName} lives to abuse and violate slaves. ${He} uses ${loser.slaveName} for ${his} `, App.UI.DOM.makeElement("span", `pleasure`, ["devotion", "inc"]), ` raping ${him2} mercilessly, striking ${him2} until ${he2} turns a deep reddish-purple, and showing off for the spectators.`);
-
-				if (V.pit.audience !== "none") {
-					repSpan.append(`greatly enjoys`);
-					r.push(`The audience `, repSpan, ` the depraved spectacle.`);
-
-					repX(50, "pit", winner);
-				}
-
-				winner.devotion++;
-			} else if (winner.energy > 95) {
-				r.push(`${winner.slaveName} doesn't have to feign willingness to rape a slave ${girl2}. ${He} uses ${loser.slaveName} for ${his} `, App.UI.DOM.makeElement("span", `pleasure,`, ["devotion", "inc"]), ` groping ${him2}, kissing ${his2} unwilling mouth, and showing off for the spectators.`);
-
-				if (V.pit.audience !== "none") {
-					repSpan.append(`greatly enjoys`);
-					r.push(`The audience `, repSpan, ` the depraved spectacle.`);
-
-					repX(50, "pit", winner);
-				}
-
-				winner.devotion++;
-			} else if (winner.fetish === "sadist" && winner.fetishStrength > 60) {
-				r.push(`${winner.slaveName} doesn't have to feign willingness abuse and violate a slave ${girl2}. ${He} uses ${loser.slaveName} for ${his} `, App.UI.DOM.makeElement("span", `pleasure`, ["devotion", "inc"]), ` slapping ${him2} cruelly, pinching ${him2} until ${he} draws blood, and showing off for the spectators.`);
-
-				if (V.pit.audience !== "none") {
-					repSpan.append(`greatly enjoys`);
-					r.push(`The audience `, repSpan, ` the depraved spectacle.`);
-
-					repX(50, "pit", winner);
-				}
-
-				winner.devotion++;
-			} else if (winner.devotion > 75) {
-				r.push(`${winner.slaveName} is so broken to slavery that ${he} `, App.UI.DOM.makeElement("span", `enjoys`, ["devotion", "inc"]), ` winning the fight and raping ${loser.slaveName}.`);
-
-				if (V.pit.audience !== "none") {
-					repSpan.append(`greatly enjoys`);
-					r.push(`The audience `, repSpan, ` the depraved spectacle.`);
-
-					repX(50, "pit", winner);
-				}
-
-				winner.devotion++;
-			} else if (winner.devotion > 20) {
-				r.push(`${winner.slaveName} understands ${his} role and thoroughly rapes ${loser.slaveName}.`);
-
-				if (V.pit.audience !== "none") {
-					repSpan.append(`enjoys`);
-					r.push(`The audience `, repSpan, ` the spectacle.`);
-
-					repX(25, "pit", winner);
-				}
-			} else {
-				r.push(`${winner.slaveName} is unenthusiastic and just thrusts mechanically, to avoid being punished. ${He} `, App.UI.DOM.makeElement("span", `resents`, ["devotion", "dec"]), ` having to fight and fuck.`);
-
-				if (V.pit.audience !== "none") {
-					r.push(`The audience barely pays attention.`);
-				}
-
-				winner.devotion -= 2;
-			}
-
-			return r;
-		}
-
-		function rapeEffects() {
-			const r = [];
-
-			const {he, his, him, himself, He} = getPronouns(winner);
-			const {he: he2, him: him2, He: He2} = getPronouns(loser);
-
-			r.push(...winnerEffects(), ...loserEffects());
-
-			if (loser.fetish !== "masochist" && loser.fetish !== "humiliation" && loser.sexualFlaw !== "self hating" && loser.relationship && loser.relationship < 5 && winner.ID === loser.relationshipTarget) {
-				r.push(`Fighting and rape have `, App.UI.DOM.makeElement("span", `damaged`, ["relationship", "dec"]), ` the relationship between the slaves.`);
-			}
-
-			return r;
-
-			function winnerEffects() {
-				const r = [];
-
-				if (winner.rivalry && loser.ID === winner.rivalryTarget) {
-					r.push(`${He} `, App.UI.DOM.makeElement("span", `relishes`, ["devotion", "inc"]), ` the chance to abuse ${loser.slaveName}, whom ${he} dislikes.`);
-
-					winner.devotion += 5;
-				} else if (winner.relationship && loser.ID === winner.relationshipTarget) {
-					if (winner.devotion > 20) {
-						r.push(`${He} accepts having to abuse ${loser.slaveName}, and plans to make it up to ${him2} later.`);
-					} else {
-						r.push(`${He} `, App.UI.DOM.makeElement("span", `hates`, ["devotion", "dec"]), ` having to abuse ${loser.slaveName}.`);
-
-						winner.devotion -= 10;
-					}
-				} else if (areRelated(winner, loser)) {
-					if (winner.devotion > 20) {
-						r.push(`${He} accepts having to abuse ${his} ${relativeTerm(winner, loser)}, ${loser.slaveName}, and plans to make it up to ${him2} later.`);
-					} else {
-						r.push(`${He} `, App.UI.DOM.makeElement("span", `hates`, ["devotion", "dec"]), ` having to abuse ${his} ${relativeTerm(winner, loser)}, ${loser.slaveName}.`);
-
-						winner.devotion -= 10;
-					}
-				}
-
-				if (winner.fetish === "sadist" && winner.fetishStrength > 90 && winner.sexualFlaw !== "malicious" && winner.devotion > 20) {
-					r.push(`${He} noticed something while ${he} was raping ${loser.slaveName}; watching the way ${he2} writhed in pain was strangely satisfying, as ${he} was making ${him2} suffer. ${winner.slaveName} cums powerfully at the mere thought; ${he} has become `, App.UI.DOM.makeElement("span", `sexually addicted to inflicting pain and anguish.`, ["noteworthy"]));
-
-					winner.sexualFlaw = "malicious";
-				} else if (winner.fetish === "masochist" && winner.fetishStrength > 90 && winner.sexualFlaw !== "self hating" && winner.devotion < 20) {
-					r.push(`${He} feels horrible after forcing ${himself} on ${loser.slaveName}; ${he} is the one that should suffer, not ${him2}. ${winner.slaveName} has `, App.UI.DOM.makeElement("span", `descended into true self hatred.`, ["noteworthy"]));
-
-					winner.sexualFlaw = "self hating";
-				} else if (winner.fetish === "dom" && winner.fetishStrength > 90 && winner.sexualFlaw !== "abusive" && winner.devotion > 20) {
-					r.push(`${He} noticed something while ${he} was raping ${loser.slaveName}; watching the way ${he2} cowered before ${hasAnyArms(winner) ? `${his} raised palm` : `${him}`} was strangely satisfying, as were the painful moans that accompanied every forceful thrust. ${winner.slaveName} cums powerfully at the mere thought; ${he} has become `, App.UI.DOM.makeElement("span", `sexually abusive, getting off on the thrill of forcing ${himself} on other slaves.`, ["noteworthy"]));
-
-					winner.sexualFlaw = "abusive";
-				} else if (winner.behavioralFlaw === "none" && random(1, 100) < 5 && winner.devotion < 20) {
-					r.push(`${He} begins to act `, App.UI.DOM.makeElement("span", `oddly`, ["flaw", "gain"]), ` after the fight; having to beat down and rape another slave may have affected ${him} mentally.`);
-
-					winner.behavioralFlaw = "odd";
-				}
-
-				return r;
-			}
-
-			function loserEffects() {
-				const trustSpan = App.UI.DOM.makeElement("span", `fears`, ["trust", "dec"]);
-
-				const r = [];
-
-				if (loser.sexualFlaw === "self hating") {
-					r.push(`${loser.slaveName} feels ${he2} `, App.UI.DOM.makeElement("span", `deserved this.`, ["devotion", "inc"]));
-
-					loser.devotion += 5;
-				} else if (loser.fetish === "masochist" && loser.fetishStrength > 60 && loser.fetishKnown) {
-					r.push(`${loser.slaveName} `, App.UI.DOM.makeElement("span", `gets off`, ["devotion", "inc"]), ` on being beaten and molested.`);
-
-					loser.devotion += 5;
-				} else if (loser.fetish === "humiliation" && loser.fetishStrength > 60 && loser.fetishKnown) {
-					r.push(`${loser.slaveName} `, App.UI.DOM.makeElement("span", `enjoys`, ["devotion", "inc"]), ` the humiliation of being openly beaten and raped.`);
-
-					loser.devotion += 5;
-				} else if (loser.devotion < 50) {
-					r.push(`${loser.slaveName} `, App.UI.DOM.makeElement("span", `resents`, ["devotion", "dec"]), ` being beaten and molested and `, trustSpan, ` that it will happen again.`);
-
-					loser.devotion -= 10;
-					loser.trust -= 10;
-				}
-
-				if (loser.rivalry && winner.ID === loser.rivalryTarget) {
-					r.push(`${He2} is `, App.UI.DOM.makeElement("span", `embarrassed`, ["devotion", "dec"]), ` by losing to and being raped by ${winner.slaveName}, whom ${he2} dislikes, and `, trustSpan, ` that it will happen again.`);
-
-					loser.devotion -= 10;
-					loser.trust -= 10;
-				} else if (loser.relationship && winner.ID === loser.relationshipTarget) {
-					if (loser.devotion > 20) {
-						r.push(`${He2} accepts ${winner.slaveName} having to rape ${him2}.`);
-					} else {
-						r.push(`${He2} `, App.UI.DOM.makeElement("span", `hates`, ["devotion", "dec"]), ` having to accept rape from ${winner.slaveName}, and `, trustSpan, ` that it will happen again.`);
-
-						loser.devotion -= 10;
-						loser.trust -= 10;
-					}
-				} else if (areRelated(loser, winner)) {
-					if (loser.devotion > 20) {
-						r.push(`${He2} accepts ${his} ${relativeTerm(loser, winner)}, ${winner.slaveName}, having to rape ${him2}, but ${he2} `, trustSpan, ` that it will happen again.`);
-
-						loser.trust -= 10;
-					} else {
-						r.push(`${He2} `, App.UI.DOM.makeElement("span", `hates`, ["devotion", "dec"]), ` having to accept rape from ${his} ${relativeTerm(loser, winner)}, ${winner.slaveName}, and `, trustSpan, ` that it will happen again.`);
-
-						loser.devotion -= 10;
-						loser.trust -= 10;
-					}
-				}
-
-				if (loser.fetish === "masochist" && loser.fetishStrength > 90 && loser.sexualFlaw !== "self hating") {
-					r.push(`${He2} feels strangely content after being abused and violated; ${he2} is the one that should suffer, after all. ${loser.slaveName} has `, App.UI.DOM.makeElement("span", `descended into true self hatred.`, ["flaw", "gain"]));
-
-					loser.sexualFlaw = "self hating";
-				} else if (loser.behavioralFlaw === "none" && random(1, 100) < 5 && loser.devotion < 20) {
-					r.push(`${He2} begins to act `, App.UI.DOM.makeElement("span", `oddly`, ["flaw", "gain"]), ` after the fight; losing and getting raped may have affected ${him2} mentally.`);
-
-					loser.behavioralFlaw = "odd";
-				}
-
-				return r;
-			}
-		}
-	}
-
-	// Helper Functions
-
-	/** @returns {boolean} Returns true if fighters[0] won */
-	function getWinner() {
-		if (animal) {
-			if (canRun(getSlave(fighters[0]))) {
-				return random(1, 100) > 20;	// 80% chance of winning
-			} else {
-				return random(1, 100) > 80;	// 20% chance of winning
-			}
-		}
-
-		if (deadliness(getSlave(fighters[0])).value > deadliness(getSlave(fighters[1])).value) {
-			return random(1, 100) > 20;	// 80% chance of winning
-		} else if (deadliness(getSlave(fighters[0])).value < deadliness(getSlave(fighters[1])).value) {
-			return random(1, 100) > 80;	// 20% chance of winning
-		} else if (random(1, 100) > 50) { // 50/50
-			return true;
-		}
-
-		return false;
-	}
-};
diff --git a/src/events/scheduled/seCustomSlaveDelivery.js b/src/events/scheduled/seCustomSlaveDelivery.js
index 3fc0fa58f9759c7f164ee6f7592142c0b6488932..6fce1c98df4fb76f06b4edd8b87279b10dfae3f7 100644
--- a/src/events/scheduled/seCustomSlaveDelivery.js
+++ b/src/events/scheduled/seCustomSlaveDelivery.js
@@ -193,16 +193,17 @@ App.Events.SEcustomSlaveDelivery = class SEcustomSlaveDelivery extends App.Event
 
 			/* I have no clue what I'm doing here */
 			if (V.customSlave.heightMod === "greatly below average") {
-				delivery.height = Height.random(delivery, {skew: -5, spread: 0.15, limitMult: [-5, -2]});
+				delivery.natural.height = Height.randomAdult(delivery, {skew: -5, spread: 0.15, limitMult: [-5, -2]});
 			} else if (V.customSlave.heightMod === "below average") {
-				delivery.height = Height.random(delivery, {skew: -1, limitMult: [-2, 0]});
+				delivery.natural.height = Height.randomAdult(delivery, {skew: -1, limitMult: [-2, 0]});
 			} else if (V.customSlave.heightMod === "normal") {
-				delivery.height = Height.random(delivery, {limitMult: [-1, 1]});
+				delivery.natural.height = Height.randomAdult(delivery, {limitMult: [-1, 1]});
 			} else if (V.customSlave.heightMod === "above average") {
-				delivery.height = Height.random(delivery, {skew: 1, limitMult: [0, 2]});
+				delivery.natural.height = Height.randomAdult(delivery, {skew: 1, limitMult: [0, 2]});
 			} else {
-				delivery.height = Height.random(delivery, {skew: 5, spread: 0.15, limitMult: [2, 5]});
+				delivery.natural.height = Height.randomAdult(delivery, {skew: 5, spread: 0.15, limitMult: [2, 5]});
 			}
+			delivery.height = Height.forAge(delivery.natural.height, delivery);
 
 			if (V.customSlave.intelligence === 3) {
 				delivery.intelligence = random(96, 100);
diff --git a/src/events/scheduled/seRecruiterSuccess.js b/src/events/scheduled/seRecruiterSuccess.js
index 68e7acbdab755d1592829856f8816e08a77d3daa..3855c82e52d666c3c86367128e173aeeedbc81f8 100644
--- a/src/events/scheduled/seRecruiterSuccess.js
+++ b/src/events/scheduled/seRecruiterSuccess.js
@@ -141,7 +141,8 @@ App.Events.SERecruiterSuccess = class SERecruiterSuccess extends App.Events.Base
 				slave.intelligence = Intelligence.random({limitIntelligence: [40, 100]});
 			}
 			if (V.policies.SMR.eugenics.heightSMR === 1) {
-				slave.height = Height.mean(slave) + random(15, 30);
+				slave.natural.height = Height.mean(slave.nationality, slave.race, slave.genes, 20) + random(15, 30);
+				slave.height = Height.forAge(slave.natural.height, slave);
 			}
 			if (V.policies.SMR.eugenics.faceSMR === 1) {
 				slave.face = random(40, 100);
diff --git a/src/facilities/farmyard/animals/Animal.js b/src/facilities/farmyard/animals/Animal.js
index dde095cc057da57576306689fbf220a389973a07..7f30b113735a6ede33dcb794fadf518b94a438b2 100644
--- a/src/facilities/farmyard/animals/Animal.js
+++ b/src/facilities/farmyard/animals/Animal.js
@@ -38,11 +38,11 @@ App.Entity.Animal = class Animal {
 	/** @returns {this} */
 	purchase() {
 		V.animals[this.type].push(this.name);
-
+		/*
 		if (V.pit && !V.pit.animal) {
 			V.pit.animal = this.name;
 		}
-
+		*/
 		return this;
 	}
 
@@ -51,11 +51,11 @@ App.Entity.Animal = class Animal {
 		if (this.isActive) {
 			V.active[this.type] = V.animals[this.type].random() || null;
 		}
-
+		/*
 		if (V.pit && V.pit.animal === this.name) {
 			V.pit.animal = null;
 		}
-
+		*/
 		V.animals[this.type] = V.animals[this.type].filter(animal => animal !== this.name);
 
 		return this;
diff --git a/src/facilities/farmyard/farmyard.js b/src/facilities/farmyard/farmyard.js
index d7b88f3578079493340bf3bd1e1004967d06b765..5f6f2c008d8f3ce68a4aeebd0455627959e176c6 100644
--- a/src/facilities/farmyard/farmyard.js
+++ b/src/facilities/farmyard/farmyard.js
@@ -21,11 +21,11 @@ App.Facilities.Farmyard.farmyard = class Farmyard extends App.Facilities.Facilit
 			V.farmyardKennels = 0;
 			V.farmyardStables = 0;
 			V.farmyardCages = 0;
-
+			/*
 			if (V.pit) {
 				V.pit.animal = null;
 			}
-
+			*/
 			V.farmyardUpgrades = {
 				pump: 0,
 				fertilizer: 0,
@@ -717,10 +717,11 @@ App.Facilities.Farmyard.farmyard = class Farmyard extends App.Facilities.Facilit
 							hooved: null,
 							feline: null,
 						};
-
+						/*
 						if (V.pit) {
 							V.pit.animal = null;
 						}
+						*/
 
 						V.farmyardShows = 0;
 						V.farmyardBreeding = 0;
diff --git a/src/facilities/nursery/utils/nurseryUtils.js b/src/facilities/nursery/utils/nurseryUtils.js
index 914c006e347d7d037271d8193429749f809e9660..7240d517b2f56b2e21aa0bdfd110963ff4121a18 100644
--- a/src/facilities/nursery/utils/nurseryUtils.js
+++ b/src/facilities/nursery/utils/nurseryUtils.js
@@ -200,7 +200,6 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	setHealth(child, jsRandom(80, 100), 0, 0, 0, 0);
 	child.hears = 0;
 	child.heels = 0;
-	child.height = jsRandom(85, 105);
 	child.hips = 0;
 	child.hormoneBalance = 0;
 	child.hormones = 0;
@@ -354,6 +353,7 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) {
 	child.wombImplant = "none";
 	resetEyeColor(child, "both");
 	generatePronouns(child);
+	child.height = Height.forAge(child.natural.height, child);
 
 	return child;
 };
diff --git a/src/facilities/pit/fights/0_lethalRandom.js b/src/facilities/pit/fights/0_lethalRandom.js
new file mode 100644
index 0000000000000000000000000000000000000000..f9c7f49fe3884dda10ce80f67cdfdc1d0638e640
--- /dev/null
+++ b/src/facilities/pit/fights/0_lethalRandom.js
@@ -0,0 +1,704 @@
+/** Lethal 1v1 between random slaves. */
+App.Facilities.Pit.Fights.LR1v1 = class extends App.Facilities.Pit.Fights.BaseFight {
+	fightDescription() {
+		const f = new DocumentFragment();
+		f.append("1-vs-1 fight between ", App.UI.DOM.slaveDescriptionDialog(getSlave(this.actors[0])), ` and `,
+			contextualIntro(getSlave(this.actors[0]), getSlave(this.actors[1]), true), ".");
+		return f;
+	}
+
+	get lethal() {
+		return true;
+	}
+
+	get impact() {
+		return 5;
+	}
+
+	actorPrerequisites() {
+		return [
+			[],
+			[]
+		];
+	}
+
+	execute(node, fighterMap) {
+		const that = this; // Thanks, JS!
+		const [slave1, slave2] = this.actors.map(a => getSlave(a));
+
+		const winner = getWinner() ? slave1 : slave2;
+		const loser = winner === slave1 ? slave2 : slave1;
+
+		let success = 0;
+
+		intro(node);
+		fighterDeadliness(node, slave1);
+		fighterDeadliness(node, slave2);
+		fight(node);
+		postFight(node);
+
+		return success;
+
+		/** @param {DocumentFragment} parent */
+		function intro(parent) {
+			const r = [];
+
+			App.Events.drawEventArt(node, [slave1, slave2], "no clothing");
+
+			r.push(...that.introCombatants(slave1, slave2));
+
+			if (V.pit.audience === "none") {
+				r.push(`You are alone above the pit, left to watch them kill and die in private.`);
+			} else if (V.pit.audience === "free") {
+				r.push(`Your guests line the rim of the pit, joking and betting, nervous and excited by the close prospect of watching a slave die.`);
+			} else {
+				r.push(`The attendees line the rim of the pit, betting and arguing, nervous and excited by the close prospect of watching a slave die.`);
+			}
+
+			if (V.arcologies[0].FSRomanRevivalist !== "unset") {
+				r.push(`They `, App.UI.DOM.makeElement("span", `passionately approve`, ['reputation',
+					'inc']), ` of your hosting lethal combat between slaves; this advances ideas from antiquity about what public events should be.`);
+
+				repX(20 * V.FSSingleSlaveRep * (V.arcologies[0].FSRomanRevivalist / V.FSLockinLevel), "pit");
+				V.arcologies[0].FSRomanRevivalist += (0.4 * V.FSSingleSlaveRep);
+			} else if (V.arcologies[0].FSAztecRevivalist !== "unset") {
+				r.push(`They `, App.UI.DOM.makeElement("span", `approve`, ['reputation',
+					'inc']), ` of your hosting lethal combat; this advances ideas that blood must flow as it did in ancient times.`);
+
+				repX(10 * V.FSSingleSlaveRep * (V.arcologies[0].FSAztecRevivalist / V.FSLockinLevel), "pit");
+				V.arcologies[0].FSAztecRevivalist += (0.2 * V.FSSingleSlaveRep);
+			}
+
+			r.push(`You review the rules — the combatants will use their choice of swords, and the fight will be to the death, with both fighters executed if no decision is reached. The winner will earn two complete days of rest, not to mention continued life. You take a moment to look over your fighters one more time before giving the word. After all, this is likely the last time you'll see one of them alive.`);
+
+
+			App.Events.addParagraph(parent, r);
+		}
+
+		/**
+		 * @param {DocumentFragment} parent
+		 * @param {App.Entity.SlaveState} fighter
+		 */
+		function fighterDeadliness(parent, fighter) {
+			const {he, his, him, himself, He, His} = getPronouns(fighter);
+			const fighterDeadliness = deadliness(fighter).value;
+
+			const r = [];
+
+			r.push(
+				confidence(),
+				willingness(),
+				skill(),
+				age(),
+				muscles(),
+				height(),
+				health(),
+				weight(),
+				tired(),
+				pregnancy(),
+				labor(),
+				bellyFluid(),
+				sight(),
+				hearing(),
+				prosthetics(),
+			);
+
+			App.Events.addParagraph(parent, r);
+
+			function confidence() {
+				if (fighter.fetish === Fetish.MINDBROKEN) {
+					return `${fighter.slaveName} is too broken to care about whether ${he} lives or dies;`;
+				} else if (fighterDeadliness > 5) {
+					return `${fighter.slaveName} seems very confident;`;
+				} else if (fighterDeadliness > 3) {
+					return `${fighter.slaveName} seems nervous, but steels ${himself};`;
+				} else if (fighterDeadliness > 1) {
+					return `${fighter.slaveName} seems hesitant and unsure;`;
+				} else {
+					return `${fighter.slaveName} is obviously terrified, and might flee if there were a way out of the pit;`;
+				}
+			}
+
+			function willingness() {
+				if (fighter.fetish === Fetish.MINDBROKEN) {
+					return `${he} is indifferent to the prospect of killing, as well.`;
+				} else if (fighter.devotion > 95) {
+					return `${he} is clearly willing to do ${his} best to kill for you.`;
+				} else if (fighter.fetish === "sadist" && fighter.fetishKnown && fighter.fetishStrength > 60) {
+					return `the prospect of killing does not seem to concern ${him}.`;
+				} else if (fighter.devotion > 50) {
+					return `${he} obviously does not want to kill, but will do as you order.`;
+				} else if (fighter.devotion > -20) {
+					return `${he} is clearly unhappy at the prospect of killing, but knows that the alternative is death.`;
+				} else {
+					return `${he} knows that it's kill or be killed, and puts aside ${his} hatred of you in an effort to live.`;
+				}
+			}
+
+			function skill() {
+				if (fighter.skill.combat > 30) {
+					return `${His} grip on ${his} sword is sure and easy.`;
+				}
+			}
+
+			function age() {
+				if (V.AgePenalty !== 0) {
+					if (fighter.physicalAge >= 100) {
+						return `${He} seems prepared for death, in a way.`;
+					} else if (fighter.physicalAge >= 85) {
+						return `${He} tries not to waste ${his} strength before the fight, knowing that ${his} extreme age won't allow ${him} a second wind.`;
+					} else if (fighter.physicalAge >= 70) {
+						return `${He} steadies ${himself} as well as ${he} can in ${his} advanced age.`;
+					}
+				}
+			}
+
+			function muscles() {
+				if (fighter.muscles > 95) {
+					return `${He} is wielding a massive two-handed blade few others could even heft.`;
+				} else if (fighter.muscles > 30) {
+					return `${He} is strong enough to handle a bastard sword.`;
+				} else if (fighter.muscles > 5) {
+					return `${He} has selected a longsword suited to ${his} strength.`;
+				} else if (fighter.muscles < -95) {
+					return `${He} has selected a meager dagger; even then ${he} can barely wield it.`;
+				} else if (fighter.muscles < -30) {
+					return `${He} has selected a dagger, the heaviest weapon ${he} can manage.`;
+				} else if (fighter.muscles < -5) {
+					return `${He} has selected a short sword, despite being able to barely lift it.`;
+				} else {
+					return `${He} has selected a short sword, the heaviest weapon ${he} can manage.`;
+				}
+			}
+
+			function height() {
+				if (fighter.height > 170) {
+					return `${His} height gives ${him} a reach advantage.`;
+				}
+			}
+
+			function health() {
+				if (fighter.health.condition > 50) {
+					return `${His} shining health makes ${him} a better fighter.`;
+				} else if (fighter.health.condition) {
+					return `${His} poor health makes ${him} a weaker combatant.`;
+				}
+			}
+
+			function weight() {
+				if (fighter.weight > 190) {
+					return `${His} extreme weight nearly immobilizes ${him}. ${He} struggles to move let alone fight.`;
+				} else if (fighter.weight > 160) {
+					return `${His} extreme weight limits ${his} mobility and range of motion, making ${him} an easy target.`;
+				} else if (fighter.weight > 130) {
+					return `${His} extreme weight holds ${him} back as a pit fighter.`;
+				} else if (fighter.weight > 30) {
+					return `${His} heavy weight is an impediment as a pit fighter.`;
+				} else if (fighter.weight < -10) {
+					return `${His} light weight is an impediment as a pit fighter.`;
+				}
+			}
+
+			function tired() {
+				if (fighter.health.tired > 90) {
+					return `${He} is exhausted and can barely stay awake; ${he} won't put up a fight.`;
+				} else if (fighter.health.tired > 60) {
+					return `${He} is fatigued, sapping the strength ${he}'ll need to strike true.`;
+				} else if (fighter.health.tired > 30) {
+					return `${He} is tired and more likely to take a hit than to give one.`;
+				}
+			}
+
+			function pregnancy() {
+				if (fighter.pregKnown || fighter.bellyPreg > 1500) {
+					if (fighter.bellyPreg > 750000) {
+						return `${His} monolithic pregnancy guarantees ${his} and ${his} many, many children's deaths; not only is ${he} on the verge of splitting open, but it is an unmissable, indefensible target. ${He} has no hope of attacking around the straining mass, let alone stopping ${his} opponent. ${He} is damned.`;
+					} else if (fighter.bellyPreg > 600000) {
+						return `${His} titanic pregnancy is practically a death sentence; not only does ${he} risk bursting, but it is an unmissable, indefensible target. ${He} can barely keep it together while thinking about the lives of ${his} brood.`;
+					} else if (fighter.bellyPreg > 450000) {
+						return `${His} gigantic pregnancy practically damns ${him}; it presents an unmissable, indefensible target for ${his} adversary. ${He} can barely keep it together while thinking about the lives of ${his} brood.`;
+					} else if (fighter.bellyPreg > 300000) {
+						return `${His} massive pregnancy obstructs ${his} movement and greatly hinders ${him}. ${He} struggles to think of how ${he} could even begin to defend it from harm.`;
+					} else if (fighter.bellyPreg > 150000) {
+						return `${His} giant pregnancy obstructs ${his} movement and greatly slows ${him} down. ${He} tries not to think of how many lives are depending on ${him}.`;
+					} else if (fighter.bellyPreg > 100000) {
+						return `${His} giant belly gets in ${his} way and weighs ${him} down. ${He} is terrified for the lives of ${his} many children.`;
+					} else if (fighter.bellyPreg > 10000) {
+						return `${His} huge belly gets in ${his} way and weighs ${him} down. ${He} is terrified for the ${fighter.pregType > 1 ? `lives of ${his} children` : `life of ${his} child`}.`;
+					} else if (fighter.bellyPreg > 5000) {
+						return `${His} advanced pregnancy makes ${him} much less effective, not to mention terrified for ${his} child${fighter.pregType > 1 ? `ren` : ``}.`;
+					} else if (fighter.bellyPreg > 1500) {
+						return `${His} growing pregnancy distracts ${him} with concern over the life growing within ${him}.`;
+					} else {
+						return `The life just beginning to grow inside ${him} distracts ${him} from the fight.`;
+					}
+				} else if (fighter.bellyImplant > 1500) {
+					if (fighter.bellyImplant > 750000) {
+						return `${His} monolithic, ${fighter.bellyImplant}cc implant-filled belly guarantees ${his} death; not only is ${he} on the verge of splitting open, but it is an unmissable, indefensible target that threatens to drag ${him} to the ground. ${He} has no hope of attacking around the straining mass, let alone stopping ${his} opponent.`;
+					} else if (fighter.bellyImplant > 600000) {
+						return `${His} titanic, ${fighter.bellyImplant}cc implant-filled belly is practically a guaranteed death; ${he} can barely stand let alone fight. Not only is it cripplingly heavy, unwieldy and an easy target, but ${he} can feel it straining to hold the sheer amount of filler forced into it.`;
+					} else if (fighter.bellyImplant > 450000) {
+						return `${His} gigantic, ${fighter.bellyImplant}cc implant-filled belly is nearly a guaranteed death; it presents an unmissable, indefensible target for ${his} adversary.`;
+					} else if (fighter.bellyImplant > 300000) {
+						return `${His} massive, ${fighter.bellyImplant}cc implant-filled belly is extremely heavy, unwieldy and an easy target, practically damning ${him} in combat.`;
+					} else if (fighter.bellyImplant > 150000) {
+						return `${His} giant, ${fighter.bellyImplant}cc implant-filled belly obstructs ${his} movement and greatly slows ${him} down.`;
+					} else if (fighter.bellyImplant > 100000) {
+						return `${His} giant, ${fighter.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`;
+					} else if (fighter.bellyImplant > 10000) {
+						return `${His} huge, ${fighter.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`;
+					} else if (fighter.bellyImplant > 5000) {
+						return `${His} large, ${fighter.bellyImplant}cc implant-filled belly is heavy and unwieldy, rendering ${him} less effective.`;
+					} else if (fighter.bellyImplant > 1500) {
+						return `${His} swollen, ${fighter.bellyImplant}cc implant-filled belly is heavy and makes ${him} less effective.`;
+					}
+				}
+			}
+
+			function labor() {
+				if (isInLabor(fighter)) {
+					return `${He}'s feeling labor pains. ${His} ${fighter.pregType > 1 ? `children are` : `child is`} ready to be born, oblivious to the fact that it will mean the death of ${fighter.pregType > 1 ? `their` : `its`} mother.`;
+				} else if (fighter.preg > fighter.pregData.normalBirth && fighter.pregControl !== "labor suppressors") {
+					return `${He}'ll be going into labor any time now and ${he} knows it. ${He}'s terrified of the thought of ${his} water breaking during the fight.`;
+				}
+			}
+
+			function bellyFluid() {
+				if (fighter.bellyFluid > 10000) {
+					return `${His} hugely bloated, ${fighter.inflationType}-filled belly is taut and painful, hindering ${his} ability to fight.`;
+				} else if (fighter.bellyFluid > 5000) {
+					return `${His} bloated, ${fighter.inflationType}-stuffed belly is constantly jiggling and moving, distracting ${him} and throwing off ${his} weight.`;
+				} else if (fighter.bellyFluid > 2000) {
+					return `${His} distended, ${fighter.inflationType}-belly is uncomfortable and heavy, distracting ${him}.`;
+				}
+			}
+
+			function sight() {
+				if (!canSee(fighter)) {
+					return `${His} lack of eyesight is certain death.`;
+				} else if (!canSeePerfectly(fighter)) {
+					return `${His} poor eyesight makes ${him} a weaker combatant.`;
+				}
+			}
+
+			function hearing() {
+				if (!canHear(fighter)) {
+					return `${His} lack of hearing is a major detriment.`;
+				} else if ((fighter.hears === -1 && fighter.earwear !== "hearing aids") || (fighter.hears === 0 && fighter.earwear === "muffling ear plugs")) {		// TODO: replace with canHearPerfectly
+					return `${His} poor hearing is a minor detriment.`;
+				}
+			}
+
+			function prosthetics() {
+				if (hasAnyProstheticLimbs(fighter) && !hasAnyQuadrupedLimbs(fighter)) {
+					const r = [];
+
+					r.push(`The pit lights gleam on ${his} P-Limbs.`);
+
+					if (getLimbCount(fighter, 6) > 0) {
+						r.push(`The limits on ${his} cybernetic limbs have been lifted, turning them deadly.`);
+					} else if (getLimbCount(fighter, 5) > 0) {
+						r.push(`Their integral weapons are fully uncaged.`);
+					}
+
+					return r.join(' ');
+				}
+				if (hasAnyProstheticLimbs(fighter) && hasAnyQuadrupedLimbs(fighter)) {
+					const r = [];
+
+					r.push(`The pit lights gleam on ${his} quadrupedal limbs. The retractable claws of ${his} paws have been fully extended, ready to rip and tear.`);
+					return r.join(' ');
+				}
+			}
+		}
+
+		/** @param {DocumentFragment} parent */
+		function fight(parent) {
+			const r = [];
+
+			r.push(`In any case, both of the slaves been dosed with aggression enhancers and inhibition blockers; they'll fight to kill.`);
+
+			const winnerDeadliness = deadliness(winner).value;
+			const loserDeadliness = deadliness(loser).value;
+
+			const {he, his, him, himself, girl, He} = getPronouns(winner);
+			const {He: He2, he: he2, his: his2, him: him2, girl: girl2} = getPronouns(loser);
+
+			if (!canSee(winner) && !canSee(loser)) {
+				r.push(`${winner.slaveName} and ${loser.slaveName} are both blind, making the fight a staredown. Neither slave wants to make the first move, especially with the drowning cacophony coming from the jeering crowd. Slowly, ${winner.slaveName} moves forward, waving ${his} sword side to side in the hopes of finding ${his} opponent before ${he} ${himself} gets found. ${loser.slaveName}'s sword clips the tip of ${winner.slaveName}'s setting off a surprisingly brutal series of slashes. The two slaves violently lay into each other, suffering more and more strikes as the struggle goes on. Less than a minute from first contact, both slaves are lying in their combined blood. As you begin to call it a draw, you notice ${winner.slaveName} start to stir. ${He} staggers to ${his} feet, coated in ${his} and ${loser.slaveName}'s blood, before dropping back to ${his} knees. It seems ${he} lived through this fight; odds aren't likely ${he}'ll do it again.`);
+
+				healthDamage(winner, 50);
+				success = 0.25;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `surprised`, ['reputation', 'inc']),
+						` by the sudden violence after so much standing around.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is surprised by the sudden violence after so much standing around, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is modest.`);
+				}
+			} else if (winnerDeadliness > (loserDeadliness + 1) && getArmCount(winner, 6) > 1) {
+				r.push(`Upon your word the two combatants approach each other. ${winner.slaveName} does not carry a sword, raising only ${his} hands, but these are terrifying, modern weapons themselves. ${loser.slaveName} tries a probing sweep, but ${winner.slaveName} catches ${his2} blade in one hand, slides it down to the hilt with a shriek of metal on metal, and snaps the blade cleanly. ${loser.slaveName} ${canSee(loser) ? `watches this` : `freezes in place`}, dumbstruck, before regaining composure and taking a fighting stance again. ${winner.slaveName} manages to touch ${his} opponent's bare skin with ${his} own cybernetics, incapacitating ${loser.slaveName} with an electric shock. While ${loser.slaveName} is temporarily stunned, ${winner.slaveName} strikes ${loser.slaveName} on the head with deadly force, crushing ${his} opponent's skull. Though the fight was short,`);
+
+				success = 0.5;
+
+				if (V.pit.audience === "free") {
+					r.push(`the audience is `,
+						App.UI.DOM.makeElement("span", `very impressed`, ['reputation', 'inc']),
+						` by the display.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`the audience is quite impressed by the display, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is quite good.`);
+				}
+			} else if (winnerDeadliness > (loserDeadliness + 1) && getArmCount(winner, 5) > 1) {
+				r.push(`Upon your word the two combatants approach each other. ${winner.slaveName} drops ${his} sword as ${he} comes, raising only ${his} hands, but these are terrifying, modern weapons themselves. ${loser.slaveName} tries a probing sweep, but ${winner.slaveName} catches ${his2} blade in one hand, slides it down to the hilt with a shriek of metal on metal, and snaps the blade cleanly. As ${loser.slaveName} watches this, dumbstruck, ${winner.slaveName} places a gentle hand under ${his2} chin and then extends that arm's integral blade up and through ${his} opponent's skull. Though the fight was short,`);
+
+				success = 0.5;
+
+				if (V.pit.audience === "free") {
+					r.push(`the audience is `,
+						App.UI.DOM.makeElement("span", `very impressed`, ['reputation', 'inc']),
+						` by the display.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`the audience is quite impressed by the display, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is quite good.`);
+				}
+			} else if (!canSee(winner)) {
+				r.push(`${winner.slaveName} centers ${himself} and hones in on ${loser.slaveName}'s rapid breath. ${He} readies ${himself}, knowing ${he} has a single chance to live. With heavy steps, ${loser.slaveName} rushes ${him}, fully prepared to slaughter the helpless combatant. ${winner.slaveName} gambles everything on a single high slash, a slash that cut ${loser.slaveName}'s undefended neck wide open. ${winner.slaveName} collapses to the ground, fully aware of ${loser.slaveName}'s final gurgles, and the sword `,
+					App.UI.DOM.makeElement("span", `firmly planted in ${his} side.`, ['health', 'dec']),
+					` ${He} lived this time, barely, but ${he} doubts ${he} can do it again.`);
+
+				healthDamage(winner, 80);
+				success = 2;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `awestruck`, ['reputation', 'inc']),
+						` by the blind ${girl}'s triumph.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is awestruck by the blind ${girl}'s triumph, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is enormous.`);
+				}
+			} else if (!canSee(loser)) {
+				r.push(`${winner.slaveName} sighs at ${loser.slaveName}'s random slashing and calmly struts around the panicking slave. In one quick swoop, ${he} buries ${his} blade in ${loser.slaveName}'s back, ending the poor ${girl2}'s flailing.`);
+
+				success = -0.1;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `, App.UI.DOM.makeElement("span", `annoyed`, ["reputation",
+						"dec"]), ` by this waste of a fight.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience found the fight embarrassing, and your `, App.UI.DOM.makeElement("span", `cut of the betting`, ['cash',
+						'dec']), ` is pitiful.`);
+				}
+			} else if (winnerDeadliness > (loserDeadliness + 3)) {
+				if (winner.skill.combat > 30) {
+					r.push(`${winner.slaveName} wants to win, and ${he} opens the fight with a furious attack. ${loser.slaveName} manages to get ${his2} blade up, blocking a strike with a ringing clash and a few sparks, but by doing so leaves ${his2} abdomen open and obscures ${his2} vision enough that ${he2} is unprepared for the following horizontal slash, which opens ${his2} belly wide. The stricken ${girl2} collapses, feebly trying to push ${his2} viscera back into place. Whether out of mercy or a desire to get it over with, ${winner.slaveName} quickly removes the dying ${girl2}'s head.`);
+
+					success = 0.2;
+
+					if (V.pit.audience === "free") {
+						r.push(`The audience is `,
+							App.UI.DOM.makeElement("span", `reasonably impressed`, ['reputation', 'inc']),
+							` by the gore.`);
+					} else if (V.pit.audience === "paid") {
+						r.push(`The audience is reasonably impressed by the gore, and your `,
+							App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+							` is reasonable.`);
+					}
+				} else {
+					r.push(`${winner.slaveName} wants to win and is confident ${he} will, but ${he} isn't particularly sure about how to do so. ${He} fights cautiously, swinging ${his} sword in powerful but inaccurate strokes. It is only a matter of time before one of these strikes gets through; it's telling that rather than hitting what ${he} aimed at, ${winner.slaveName} accidentally opens a massive gash down ${loser.slaveName}'s thigh. Realizing ${he2} has to do something, ${loser.slaveName} makes a desperate counterattack, pouring blood as ${he2} goes. ${winner.slaveName} panics and fails to parry one of the last counterstrikes before loss of blood ends the attack, suffering a `, App.UI.DOM.makeElement("span", `terrible cut`, ['health',
+						'dec']), ` to ${his} shoulder. Down to one arm, ${winner.slaveName} is forced to make a long, loud butchery of ending the fight.`);
+
+					healthDamage(winner, 20);
+					success = 0.2;
+
+					if (V.pit.audience === "free") {
+						r.push(`The audience is `,
+							App.UI.DOM.makeElement("span", `reasonably impressed`, ['reputation', 'inc']),
+							` by the blood.`);
+					} else if (V.pit.audience === "paid") {
+						r.push(`The audience is reasonably impressed by the blood, and your `,
+							App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+							` is reasonable.`);
+					}
+				}
+			} else if (winner.skill.combat > 30 && loser.skill.combat > 30) {
+				r.push(`Upon your word the two combatants approach each other warily, both knowing the other is reasonably competent. Before long they are trading thrust and parry, swing and block. ${winner.slaveName} is slowly pressed back, so ${he} decides to change the nature of the fight. After three tries ${he} manages to force ${loser.slaveName} to close, suffering a `, App.UI.DOM.makeElement("span", `nearly severed ear`, ['health',
+					'dec']), ` as ${he} does. ${loser.slaveName} realizes ${he2} only retains an advantage at long range but cannot back up fast enough to avoid close combat. ${loser.slaveName} is forced back fast enough that ${he2} trips; ${he2}'s barely fallen on ${his2} back before ${he2} grunts with shock and pain, dying with a look of surprise as ${he2} stares at the sword growing out of ${his2} chest.`);
+
+				success = 0.5;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `very impressed`, ['reputation', 'inc']),
+						` by the expert fight.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is quite impressed by the expert fight, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is quite good.`);
+				}
+			} else if (winner.height - loser.height < -10) {
+				r.push(`${winner.slaveName} realizes that ${loser.slaveName}'s wingspan gives ${him2} a huge reach advantage. ${He} bores straight in, taking `, App.UI.DOM.makeElement("span", `a glancing scalp wound`, ['health',
+					'dec']), ` but coming on regardless. ${loser.slaveName} understands ${his2} opponent's intention and backs off, but the pit is small and there isn't much room to retreat. When ${his2} back hits a padded wall, ${winner.slaveName} aims a gutting cut that ${loser.slaveName} struggles to block. ${He2} manages it, but the wall catches ${his2} point, so the block is with ${his2} wrist, not ${his2} sword. The sharp blade cuts almost all the way through the joint, leaving ${him2} in agony and totally incapable of defense. ${winner.slaveName} pushes ${his2} head back against the wall and cuts ${his2} throat down to the spine.`);
+
+				success = 0.2;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `reasonably impressed`, ['reputation', 'inc']),
+						` by the blood.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is reasonably impressed by the blood, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is reasonable.`);
+				}
+			} else if (winner.muscles > 30) {
+				r.push(`${winner.slaveName} is so massively muscular that ${he}'s actually impeded by ${his} lack of speed and flexibility. ${loser.slaveName} is properly afraid of ${his2} strength, though, so ${he2} tries to stay away as much as ${he2} can. The few times their blades clash reinforces this approach, since ${winner.slaveName} is able to beat ${his} opponent's blocks out of the way with contemptuous ease. The fight takes a long, long time, but it takes more out of ${loser.slaveName} to survive than it takes out of ${winner.slaveName} to keep swinging. Eventually the gasping, weeping ${loser.slaveName} trips and does not struggle to ${his2} feet in time. It takes ${his2} tired opponent several overhead butcher's cleaves to end it.`);
+
+				success = 0.05;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `reasonably impressed`, ['reputation', 'inc']),
+						` by the show of strength.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is reasonably impressed by the show of strength, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is reasonable.`);
+				}
+			} else if (loser.belly > 300000) {
+				r.push(`${winner.slaveName} wants to live badly enough that ${he} takes an extremely brutal shortcut to victory. The instant the fight starts, ${he} quickly slices right across ${loser.slaveName}'s massive belly, which is far too large to possibly defend. ${loser.slaveName}'s belly ruptures like a popped water balloon, showering ${winner.slaveName} with`);
+
+				if (loser.pregType > 0) {
+					r.push(`blood. ${loser.slaveName} collapses into the pile of organs and babies released from ${his2} body.`);
+				} else if (loser.bellyImplant > 0) {
+					r.push(`blood and filler. ${loser.slaveName} collapses into the pool of organs and fluid released from ${his2} body.`);
+				} else {
+					r.push(`blood and ${loser.inflationType}. ${loser.slaveName} collapses into the pool of organs and fluid released from ${his2} body.`);
+				}
+
+				r.push(`${winner.slaveName} walks over to the bleeding out slave and quickly cuts ${his2} throat.`);
+
+				success = 0.1;
+
+				if (V.pit.audience === "free") {
+					r.push(`the audience is `,
+						App.UI.DOM.makeElement("span", `not very impressed`, ['reputation', 'inc']),
+						` by this easy kill.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is not very impressed by this easy kill, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is unimpressive.`);
+				}
+			} else if (loser.boobs > 1200) {
+				r.push(`${winner.slaveName} takes an extremely simple shortcut to victory. The instant the fight starts, ${he} slices ${loser.slaveName} right across ${his2} huge tits, which are so large they cannot properly be defended. ${loser.slaveName} reflexively drops ${his2} sword to clasp ${his2} ${hasBothArms(loser) ? `hands` : `hand`} over ${his2} ruined breasts, gushing blood${loser.boobsImplant > 400 ? ` and implant fluid` : ``}. ${winner.slaveName}'s follow-up is neither artful nor particularly well planned, but it is effective. ${He} hits the distracted ${girl2}'s neck from the side, almost but not quite separating ${his2} head from ${his2} body.`);
+
+				success = 0.1;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `not very impressed`, ['reputation', 'inc']),
+						` by this easy kill.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is not very impressed by this easy kill, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is unimpressive.`);
+				}
+			} else if (loser.dick > 0) {
+				r.push(`${winner.slaveName} wants to live badly enough that ${he} takes an extremely brutal shortcut to victory. The instant the fight starts, ${he} furiously swings for ${loser.slaveName}'s face. ${loser.slaveName} reflexively raises ${his2} sword to block, at which point ${winner.slaveName} simply kicks ${him2} in the dick. ${loser.slaveName} goes down like a marionette with cut strings, ${his2} mouth soundlessly opening and closing and tears leaking from ${his2} closed eyes. ${winner.slaveName} walks over to the prostrate slave and cuts ${his2} throat without much trouble.`);
+
+				success = 0.1;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `not very impressed`, ['reputation', 'inc']),
+						` by this easy kill.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is not very impressed by this easy kill, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is unimpressive.`);
+				}
+			} else {
+				r.push(`${winner.slaveName} wants to live badly enough that ${he} takes an extremely brutal shortcut to victory. The instant the fight starts, ${he} furiously swings for ${loser.slaveName}'s face. ${loser.slaveName} reflexively raises ${his2} sword to block, at which point ${winner.slaveName} simply kicks ${him2} in the cunt. ${loser.slaveName} goes down like a marionette with cut strings, ${his2} mouth soundlessly opening and closing and tears leaking from ${his2} closed eyes. ${winner.slaveName} walks over to the prostrate slave and cuts ${his2} throat without much trouble.`);
+
+				success = 0.1;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `not very impressed`, ['reputation', 'inc']),
+						` by this easy kill.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is not very impressed by this easy kill, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ['cash', 'inc']),
+						` is unimpressive.`);
+				}
+			}
+
+			App.Events.addParagraph(parent, r);
+		}
+
+		/** @param {DocumentFragment} parent */
+		function postFight(parent) {
+			const r = [];
+
+			const {he, his, him, himself, He} = getPronouns(winner);
+			const {sister: sister2} = getPronouns(loser);
+			const mindbrokenSpan = App.UI.DOM.makeElement("span", `no longer capable`, ["red"]);
+
+			r.push(`You let the winner ${winner.slaveName}, shaking as ${he} comes off the adrenaline, drugs, and fear, exit the pit.`);
+
+			if (winner.fetish === Fetish.MINDBROKEN) {
+				r.push(`${He} was already so broken before today that ${he} will not be seriously affected by having killed with ${his} own ${hasBothArms(winner) ? `hands` : `hand`}.`);
+			} else if (winner.devotion > 95) {
+				r.push(`${He} is so worshipful of you that ${he} does not see killing ${loser.slaveName} as special in ${his} own internal listing of things that ${he} has willingly done and would willingly do again on your behalf.`);
+			} else if (winner.devotion > 80) {
+				r.push(`${He} will never forget having killed ${loser.slaveName} with ${his} own ${hasBothArms(winner) ? `hands` : `hand`}. The only way ${he} will be able to live with ${himself} is to `, App.UI.DOM.makeElement("span", `subsume ${his} will to yours,`, ["devotion",
+					"inc"]), ` telling ${himself} that the killing was to serve and obey you.`);
+
+				winner.devotion += 10;
+			} else if (winner.fetish === "sadist" && winner.fetishKnown && winner.fetishStrength > 60) {
+				r.push(`${He} has sunk even deeper into cruelty, callousness, and a total disregard of the value of other slaves' lives. Going forward, ${he}'s even `, App.UI.DOM.makeElement("span", `less likely to question`, ["devotion",
+					"inc"]), ` even the most abominable commands.`);
+
+				winner.devotion += 10;
+			} else if (winner.devotion > 50) {
+				r.push(`${He} will never forget having killed ${loser.slaveName} with ${his} own ${hasBothArms(winner) ? `hands` : `hand`}. The only way ${he} will be able to live with ${himself} is to tell ${himself} that the killing was done on your orders.`);
+			} else {
+				r.push(`${He} will never forget having killed ${loser.slaveName} with ${his} own ${hasBothArms(winner) ? `hands` : `hand`}. The only way ${he} will be able to live with ${himself} is to `, App.UI.DOM.makeElement("span", `blame you,`, ["devotion",
+					"dec"]), ` telling ${himself} that the killing was the only choice you gave ${him} if ${he} wanted to live.`);
+
+				winner.devotion -= 10;
+			}
+
+			if (winner.fetish !== "sadist") {
+				if (random(1, 100) > 50) {
+					r.push(`Cruelty and callousness seeps its way into ${his} sexuality; ${he} has become a `, App.UI.DOM.makeElement("span", `bloody sadist.`, ["fetish",
+						"gain"]));
+
+					winner.fetish = "sadist";
+					winner.fetishKnown = 1;
+					winner.fetishStrength = 65;
+				}
+			}
+
+			if (winner.rivalry && loser.ID === winner.rivalryTarget) {
+				if (winner.devotion > 75) {
+					r.push(`${He} is so accepting of the low value of slave life that ${he} `, App.UI.DOM.makeElement("span", `is pleased`, ["devotion",
+						"inc"]), ` to have killed ${his} rival ${loser.slaveName}.`);
+
+					winner.devotion += 4;
+				}
+			} else if (winner.relationship && loser.ID === winner.relationshipTarget) {
+				if (winner.devotion > 95) {
+					r.push(`${He} is so worshipful of you that ${he} sees the death of ${his} only friend at ${his} own hand as an `, App.UI.DOM.makeElement("span", `honorable`, ["devotion",
+						"inc"]), ` end to their doomed slave relationship.`);
+
+					winner.devotion += 4;
+				} else {
+					r.push(`${He} shows little reaction to the death of ${his} only friend at ${his} own hand. In the coming days, it becomes clear that this is because ${he} is `, mindbrokenSpan, ` of reacting to anything on an emotional level. Ever again.`);
+
+					applyMindbroken(winner);
+					winner.fetishKnown = 1;
+				}
+			} else if (isParentP(winner, loser) || isParentP(loser, winner)) {
+				if (winner.devotion > 95) {
+					r.push(`${He} is so worshipful of you that ${he} sees the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand as an `, App.UI.DOM.makeElement("span", `honorable`, ["devotion",
+						"inc"]), ` end to their doomed family.`);
+
+					winner.devotion += 4;
+				} else {
+					r.push(`${He} shows little reaction to the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand. In the coming days, it becomes clear that this is because ${he} is `, mindbrokenSpan, ` of reacting to anything on an emotional level. Ever again.`);
+
+					applyMindbroken(winner);
+					winner.fetishKnown = 1;
+				}
+			} else if (winner.sisters > 0) {
+				switch (areSisters(winner, loser)) {
+					case 1:
+						if (winner.devotion > 95) {
+							r.push(`${He} is so worshipful of you that ${he} sees the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand as an `, App.UI.DOM.makeElement("span", `honorable`, ["devotion",
+								"inc"]), ` end to their doomed family.`);
+
+							winner.devotion += 4;
+						} else {
+							r.push(`${He} shows little reaction to the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand. In the coming days, it becomes clear that this is because ${he} is `, mindbrokenSpan, ` of reacting to anything on an emotional level. Ever again.`);
+
+							applyMindbroken(winner);
+							winner.fetishKnown = 1;
+						}
+						break;
+					case 2:
+						if (winner.devotion > 90) {
+							r.push(`${He} is so worshipful of you that ${he} sees the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand as an `, App.UI.DOM.makeElement("span", `honorable`, ["devotion",
+								"inc"]), ` end to their doomed family.`);
+
+							winner.devotion += 4;
+						} else {
+							r.push(`${He} shows little reaction to the death of ${his} ${relativeTerm(winner, loser)} at ${his} own hand. In the coming days, it becomes clear that this is because ${he} is `, mindbrokenSpan, ` of reacting to anything on an emotional level. Ever again.`);
+
+							applyMindbroken(winner);
+							winner.fetishKnown = 1;
+						}
+						break;
+					case 3:
+						if (winner.devotion > 85) {
+							r.push(`${He} is so worshipful of you that ${he} sees the death of ${his} half-${sister2} at ${his} own hand as an `, App.UI.DOM.makeElement("span", `honorable`, ["devotion",
+								"inc"]), ` end to their doomed family.`);
+
+							winner.devotion += 4;
+						} else {
+							r.push(`${He} is `, App.UI.DOM.makeElement("span", `utterly devastated`, ["devotion",
+								"dec"]), ` at being forced to take the life of ${his} half-${sister2}.`);
+
+							winner.devotion -= 50;
+						}
+						break;
+				}
+			}
+
+			if (winner.skill.combat < 60) {
+				const experienceSpan = App.UI.DOM.makeElement("span", `improved ${his} combat skills.`, ["improvement"]);
+
+				winner.skill.combat += 5 + Math.floor(0.5 * (winner.intelligence + winner.intelligenceImplant) / 32);
+				r.push(`With lethal experience in ${V.pit.name}, ${winner.slaveName} has `, experienceSpan);
+			}
+
+			winner.counter.pitKills++;
+			winner.counter.pitWins++;
+
+
+			V.pitKillsTotal++;
+			V.pitFightsTotal++;
+
+			removeSlave(loser);
+
+			App.Events.addParagraph(parent, r);
+		}
+
+		// Helper Functions
+
+		/** @returns {boolean} Returns true if slave1 won */
+		function getWinner() {
+			if (deadliness(slave1).value > deadliness(slave2).value) {
+				return random(1, 100) > 20;	// 80% chance of winning
+			} else if (deadliness(slave1).value < deadliness(slave2).value) {
+				return random(1, 100) > 80;	// 20% chance of winning
+			} else if (random(1, 100) > 50) { // 50/50
+				return true;
+			}
+
+			return false;
+		}
+	}
+
+	introCombatants(slave1, slave2) {
+		return [`This fight is between`, App.UI.DOM.slaveDescriptionDialog(slave1), `and`,
+			App.UI.DOM.combineNodes(contextualIntro(slave1, slave2, true), ".")];
+	}
+};
diff --git a/src/facilities/pit/fights/0_nonLethalRandom.js b/src/facilities/pit/fights/0_nonLethalRandom.js
new file mode 100644
index 0000000000000000000000000000000000000000..a6d47235d16315e95a72b87e2f0e0bca14f72cf1
--- /dev/null
+++ b/src/facilities/pit/fights/0_nonLethalRandom.js
@@ -0,0 +1,1173 @@
+/** Nonlethal 1v1 between random slaves. */
+App.Facilities.Pit.Fights.NlR1v1 = class extends App.Facilities.Pit.Fights.BaseFight {
+	fightDescription() {
+		const f = new DocumentFragment();
+		f.append("1-vs-1 fight between ", App.UI.DOM.slaveDescriptionDialog(getSlave(this.actors[0])), ` and `,
+			contextualIntro(getSlave(this.actors[0]), getSlave(this.actors[1]), true), ".");
+		return f;
+	}
+
+	actorPrerequisites() {
+		return [
+			[],
+			[]
+		];
+	}
+
+	execute(node, fighterMap) {
+		const that = this; // Thanks, JS!
+		const [slave1, slave2] = this.actors.map(a => getSlave(a));
+
+		const winner = getWinner() ? slave1 : slave2;
+		const loser = winner === slave1 ? slave2 : slave1;
+
+		let success = 0;
+
+		intro(node);
+		fighterDeadliness(node, slave1);
+		fighterDeadliness(node, slave2);
+
+		fight(node);
+		postFight(node);
+
+		return success;
+
+		/**
+		 * @param {DocumentFragment} parent
+		 */
+		function intro(parent) {
+			const r = [];
+
+			App.Events.drawEventArt(node, [slave1, slave2], "no clothing");
+
+			r.push(...that.introCombatants(slave1, slave2));
+
+			r.push(`You review the rules — the combatants are wearing light gloves, and the fight will be nonlethal, with you as the judge. The winner will have the right to do anything they wish to the loser,`);
+
+			switch (V.pit.virginities) {
+				case "all":
+					r.push(`except take their virginity,`);
+					break;
+				case "anal":
+					r.push(`except take their anal virginity,`);
+					break;
+				case "vaginal":
+					r.push(`except take virginities,`);
+					break;
+				case "none":
+					r.push(`even take virginities,`);
+					break;
+				default:
+					throw new Error(`Unexpected V.pit.virginities value of '${that.params.virginities}' found`);
+			}
+
+			r.push(`and earn two complete days of rest. You take a moment to look over your fighters before giving the word.`);
+
+			App.Events.addParagraph(parent, r);
+		}
+
+		/**
+		 * @param {DocumentFragment} parent
+		 * @param {App.Entity.SlaveState} fighter
+		 */
+		function fighterDeadliness(parent, fighter) {
+			const {he, his, him, himself, He, His} = getPronouns(fighter);
+			const fighterDeadliness = deadliness(fighter).value;
+
+			const r = [];
+
+			r.push(
+				confidence(),
+				skill(),
+				age(),
+				muscles(),
+				height(),
+				health(),
+				weight(),
+				tired(),
+				pregnancy(),
+				labor(),
+				bellyFluid(),
+				sight(),
+				hearing(),
+				prosthetics(),
+				willingness(),
+			);
+
+			App.Events.addParagraph(parent, r);
+
+			function confidence() {
+				if (fighter.fetish === Fetish.MINDBROKEN) {
+					return `${fighter.slaveName} is too broken to care what happens to ${him}.`;
+				} else if (fighterDeadliness > 5) {
+					return `${fighter.slaveName} seems very confident, even eager to win a break.`;
+				} else if (fighterDeadliness > 3) {
+					return `${fighter.slaveName} seems nervous, but steels ${himself} to fight for time off.`;
+				} else if (fighterDeadliness > 1) {
+					return `${fighter.slaveName} seems hesitant and unsure.`;
+				} else {
+					return `${fighter.slaveName} is obviously terrified, and might flee if there were a way out of the pit.`;
+				}
+			}
+
+			function willingness() {
+				if (fighter.devotion < 20 && fighter.trust < -20) {
+					return `${He} is unwilling to fight, but ${he} knows the punishment for refusing to do so will be even worse.`;
+				}
+			}
+
+			function skill() {
+				if (fighter.skill.combat > 30) {
+					return `${His} stance is obviously well-practiced.`;
+				}
+			}
+
+			function age() {
+				if (V.AgePenalty !== 0) {
+					if (fighter.physicalAge >= 100) {
+						return `${He} seems preoccupied, which is unsurprising given ${his} age and resulting fragility.`;
+					} else if (fighter.physicalAge >= 85) {
+						return `${He} tries not to waste ${his} strength before the fight, knowing that ${his} extreme age won't allow ${him} a second wind.`;
+					} else if (fighter.physicalAge >= 70) {
+						return `${He} steadies ${himself} as well as ${he} can in ${his} advanced age.`;
+					}
+				}
+			}
+
+			function muscles() {
+				if (fighter.muscles > 95 && fighter.height > 185) {
+					return `${His} huge muscles are an intimidating sight and, despite their massive size, ${he} is tall enough to not be hindered by them.`;
+				} else if (fighter.muscles > 95) {
+					return `${His} huge muscles are an intimidating sight, but may hinder ${his} flexibility.`;
+				} else if (fighter.muscles > 30) {
+					return `${His} muscles are a trim and powerful sight.`;
+				} else if (fighter.muscles < -95) {
+					return `${He} can barely stand, let alone defend ${himself}.`;
+				} else if (fighter.muscles < -30) {
+					return `${He} is very weak; a single punch will likely floor ${him}.`;
+				} else if (fighter.muscles < -5) {
+					return `${He} is rather unfit; ${he} will likely be outmatched by near any real opponent.`;
+				} else {
+					return `${He} is only somewhat fit and will likely not be able to win through pure strength.`;
+				}
+			}
+
+			function height() {
+				if (fighter.height > 170) {
+					return `${His} height gives ${him} a reach advantage with ${his} fists and feet.`;
+				}
+			}
+
+			function health() {
+				if (fighter.health.condition > 50) {
+					return `${His} shining health makes ${him} a better fighter.`;
+				} else if (fighter.health.condition) {
+					return `${His} poor health makes ${him} a weaker combatant.`;
+				}
+			}
+
+			function weight() {
+				if (fighter.weight > 190) {
+					return `${His} extreme weight nearly immobilizes ${him}. ${He} is essentially a fleshy punching bag.`;
+				} else if (fighter.weight > 160) {
+					return `${His} extreme weight limits ${his} mobility and range of motion even if ${he} can take punches like nothing.`;
+				} else if (fighter.weight > 130) {
+					return `${His} extreme weight holds ${him} back as a pit fighter.`;
+				} else if (fighter.weight > 30) {
+					return `${His} heavy weight is an impediment as a pit fighter.`;
+				} else if (fighter.weight < -10) {
+					return `${His} light weight is an impediment as a pit fighter.`;
+				}
+			}
+
+			function tired() {
+				if (fighter.health.tired > 90) {
+					return `${He} is exhausted and can barely stay awake; ${he} won't put up a fight.`;
+				} else if (fighter.health.tired > 60) {
+					return `${He} is fatigued, sapping the strength ${he}'ll need in ${his} strikes.`;
+				} else if (fighter.health.tired > 30) {
+					return `${He} is tired and more likely to take a hit than to give one.`;
+				}
+			}
+
+			function pregnancy() {
+				if (fighter.pregKnown || fighter.bellyPreg > 1500) {
+					if (fighter.bellyPreg > 750000) {
+						return `${His} monolithic pregnancy guarantees ${his} loss; not only is ${he} on the verge of splitting open, but it is an unmissable, indefensible target that threatens to drag ${him} to the ground. ${He} has no hope of attacking around the straining mass, let alone stopping ${his} opponent. The fear of what would happen should ${his} adversary land a hit on ${his} belly also weighs upon ${his} mind.`;
+					} else if (fighter.bellyPreg > 600000) {
+						return `${His} titanic pregnancy is practically a guaranteed loss; ${he} can barely stand let alone fight. The worry of a solid hit striking ${his} life-swollen womb also weighs on ${his} mind.`;
+					} else if (fighter.bellyPreg > 450000) {
+						return `${His} gigantic pregnancy is nearly a guaranteed loss; it presents an unmissable, indefensible target for ${his} adversary.`;
+					} else if (fighter.bellyPreg > 300000) {
+						return `${His} massive pregnancy obstructs ${his} movement and greatly hinders ${him}. ${He} struggles to think of how ${he} could even begin to defend ${his} bulk.`;
+					} else if (fighter.bellyPreg > 150000) {
+						return `${His} giant pregnancy obstructs ${his} movement and greatly slows ${him} down.`;
+					} else if (fighter.bellyPreg > 100000) {
+						return `${His} giant belly gets in ${his} way and weighs ${him} down.`;
+					} else if (fighter.bellyPreg > 10000) {
+						return `${His} huge belly is unwieldy and hinders ${his} efforts.`;
+					} else if (fighter.bellyPreg > 5000) {
+						return `${His} advanced pregnancy makes ${him} much less effective.`;
+					} else if (fighter.bellyPreg > 1500) {
+						return `${His} growing pregnancy distracts ${him} from the fight.`;
+					} else {
+						return `The life just beginning to grow inside ${him} distracts ${him} from the fight.`;
+					}
+				} else if (fighter.bellyImplant > 1500) {
+					if (fighter.bellyImplant > 750000) {
+						return `${His} monolithic, ${fighter.bellyImplant}cc implant-filled belly guarantees ${his} defeat; not only is ${he} on the verge of splitting open, but it is an unmissable, indefensible target that threatens to drag ${him} to the ground. ${He} has no hope of attacking around the straining mass, let alone stopping ${his} opponent.`;
+					} else if (fighter.bellyImplant > 600000) {
+						return `${His} titanic, ${fighter.bellyImplant}cc implant-filled belly is practically a guaranteed defeat; ${he} can barely stand let alone fight. Not only is it cripplingly heavy, unwieldy and an easy target, but ${he} can feel it straining to hold the sheer amount of filler forced into it.`;
+					} else if (fighter.bellyImplant > 450000) {
+						return `${His} gigantic, ${fighter.bellyImplant}cc implant-filled belly is nearly a guaranteed defeat; it presents an unmissable, indefensible target for ${his} adversary.`;
+					} else if (fighter.bellyImplant > 300000) {
+						return `${His} massive, ${fighter.bellyImplant}cc implant-filled belly is extremely heavy, unwieldy and an easy target, practically damning ${him} in combat.`;
+					} else if (fighter.bellyImplant > 150000) {
+						return `${His} giant, ${fighter.bellyImplant}cc implant-filled belly obstructs ${his} movement and greatly slows ${him} down.`;
+					} else if (fighter.bellyImplant > 100000) {
+						return `${His} giant, ${fighter.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`;
+					} else if (fighter.bellyImplant > 10000) {
+						return `${His} huge, ${fighter.bellyImplant}cc implant-filled belly is very heavy and unwieldy, throwing off ${his} weight and making ${him} far less effective.`;
+					} else if (fighter.bellyImplant > 5000) {
+						return `${His} large, ${fighter.bellyImplant}cc implant-filled belly is heavy and unwieldy, rendering ${him} less effective.`;
+					} else if (fighter.bellyImplant > 1500) {
+						return `${His} swollen, ${fighter.bellyImplant}cc implant-filled belly is heavy and makes ${him} less effective.`;
+					}
+				}
+			}
+
+			function labor() {
+				if (isInLabor(fighter)) {
+					return `${He}'s feeling labor pains. ${His} ${fighter.pregType > 1 ? `children are` : `child is`} ready to be born, oblivious to the fact that it will put ${fighter.pregType > 1 ? `their` : `its`} mother at the mercy of ${his} opponent.`;
+				} else if (fighter.preg > fighter.pregData.normalBirth && fighter.pregControl !== "labor suppressors") {
+					return `${He}'ll be going into labor any time now and ${he} knows it. ${He}'s terrified of the thought of ${his} water breaking during the fight.`;
+				}
+			}
+
+			function bellyFluid() {
+				if (fighter.bellyFluid > 10000) {
+					return `${His} hugely bloated, ${fighter.inflationType}-filled belly is taut and painful, hindering ${his} ability to fight.`;
+				} else if (fighter.bellyFluid > 5000) {
+					return `${His} bloated, ${fighter.inflationType}-stuffed belly is constantly jiggling and moving, distracting ${him} and throwing off ${his} weight.`;
+				} else if (fighter.bellyFluid > 2000) {
+					return `${His} distended, ${fighter.inflationType}-belly is uncomfortable and heavy, distracting ${him}.`;
+				}
+			}
+
+			function sight() {
+				if (!canSee(fighter)) {
+					return `${His} lack of eyesight means certain defeat.`;
+				} else if (!canSeePerfectly(fighter)) {
+					return `${His} poor eyesight makes ${him} a weaker fighter.`;
+				}
+			}
+
+			function hearing() {
+				if (!canHear(fighter)) {
+					return `${His} lack of hearing is a major detriment.`;
+				} else if ((fighter.hears === -1 && fighter.earwear !== "hearing aids") || (fighter.hears === 0 && fighter.earwear === "muffling ear plugs")) {		// TODO: replace with canHearPerfectly
+					return `${His} poor hearing is a minor detriment.`;
+				}
+			}
+
+			function prosthetics() {
+				if (hasAnyProstheticLimbs(fighter) && !hasAnyQuadrupedLimbs(fighter)) {
+					const r = [];
+
+					r.push(`The pit lights gleam on ${his} P-Limbs.`);
+
+					if (getLimbCount(fighter, 6) > 0) {
+						r.push(`${His} advanced cybernetic limbs are faster than natural limbs, and their force is amplified, so that they can become potent weapons.`);
+					} else if (getLimbCount(fighter, 5) > 0) {
+						r.push(`Though their integral weapons are disabled, ${his} upgraded prosthetics are almost as fast as natural limbs, and they can hit much, much harder.`);
+					}
+
+					return r.join(' ');
+				}
+			}
+
+			if (hasAnyProstheticLimbs(fighter) && hasAnyQuadrupedLimbs(fighter)) {
+				const r = [];
+
+				r.push(`The pit lights gleam on ${his} prosthetic limbs. They have the advantage of being quadrupedal, keeping ${him} low to the ground and providing better mobility.`);
+				return r.join(' ');
+			}
+		}
+
+		/**
+		 * @param {DocumentFragment} parent
+		 */
+		function fight(parent) {
+			const r = [];
+
+			const winnerDeadliness = deadliness(winner).value;
+			const loserDeadliness = deadliness(loser).value;
+
+			const {he, his, him, himself, girl, He} = getPronouns(winner);
+			const {
+				he: he2,
+				his: his2,
+				him: him2,
+				himself: himself2,
+				girl: girl2,
+				He: He2,
+				His: His2,
+			} = getPronouns(loser);
+
+			if (!canSee(winner) && !canSee(loser)) {
+				r.push(`${winner.slaveName} and ${loser.slaveName} are both blind, making the fight a stare-down. Neither slave wants to make the first move, especially with the drowning cacophony coming from the jeering crowd. Slowly, ${winner.slaveName} moves forward, waving feeling for ${his} opponent before ${he} ${himself} gets found. ${loser.slaveName}'s hand meets ${winner.slaveName}'s and the two move to grab each other in a headlock. The two slaves violently thrash against each other, suffering more and more strikes as the struggle goes on. Eventually, ${loser.slaveName} can take no more and releases ${his2} grip on ${winner.slaveName} neck. It takes a moment for ${winner.slaveName} to stop wrestling the submitting ${loser.slaveName} and accept ${his} victory.`);
+
+				success = 0.25;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `surprised`, ["reputation", "inc"]),
+						` by the impromptu wrestling match.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is surprised by the sudden wrestling match, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is modest.`);
+				}
+			} else if (winnerDeadliness > (loserDeadliness + 1) && getArmCount(winner, 6) > 1) {
+				r.push(`Upon your word the two combatants approach each other. ${winner.slaveName} keeps ${his} advanced cybernetic limbs up in a protective position. ${loser.slaveName} probes ${him} with some light blows, puzzled by this ironclad defense. Gradually, ${he2} hits harder and harder, ${his2} opponent grunting under the impacts but holding steady. Finally, ${loser.slaveName} tires, gets off balance, and ${winner.slaveName} manages to grab ${his2} forearm. ${winner.slaveName}'s limbs emit an electric shock that temporarily incapacitates ${his} opponent. ${winner.slaveName} uses ${his} grip to pull ${his} stunned opponent in and grab ${his2} neck with the other hand, using it to exert just the right amount of pressure to choke ${him2} out harmlessly. Though the fight was short,`);
+
+				success = 0.5;
+
+				if (V.pit.audience === "free") {
+					r.push(`the audience is `,
+						App.UI.DOM.makeElement("span", `very impressed`, ["reputation", "inc"]),
+						` by the display.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`the audience is quite impressed by the display, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is quite good.`);
+				}
+			} else if (winnerDeadliness > (loserDeadliness + 1) && getArmCount(winner, 5) > 1) {
+				r.push(`Upon your word the two combatants approach each other. ${winner.slaveName} keeps ${his} artificial limbs up in a protective position. ${loser.slaveName} probes ${him} with some light blows, puzzled by this ironclad defense. Gradually, ${he2} hits harder and harder, ${his2} opponent grunting under the impacts but holding steady. Finally, ${loser.slaveName} overcommits to a body blow, and ${winner.slaveName} grips ${his2} forearm. That is the end. The augmented grip is effectively unbreakable, and ${winner.slaveName} uses it to pull ${his} opponent in and grab ${his2} neck with the other hand, using it to exert just the right amount of pressure to choke ${him2} out harmlessly. Though the fight was short,`);
+
+				success = 0.5;
+
+				if (V.pit.audience === "free") {
+					r.push(`the audience is `,
+						App.UI.DOM.makeElement("span", `very impressed`, ["reputation", "inc"]),
+						` by the display.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`the audience is quite impressed by the display, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is quite good.`);
+				}
+			} else if (!canSee(winner)) {
+				r.push(`${winner.slaveName} centers ${himself} and hones in on ${loser.slaveName}'s rapid breath. ${He} readies ${himself}, knowing ${he} has a single chance to win. With heavy steps, ${loser.slaveName} rushes ${him}, fully prepared to tackle the helpless combatant. ${winner.slaveName} gambles everything on a single high punch, a strike that slams ${loser.slaveName}'s undefended neck. ${loser.slaveName} falls to the ground before the panicking ${winner.slaveName}, who quickly pins the coughing loser.`);
+
+				healthDamage(winner, 80);
+				success = 1;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `awestruck`, ["reputation", "inc"]),
+						` by the blind ${girl}'s triumph.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is awestruck by the blind ${girl}'s triumph, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is enormous.`);
+				}
+			} else if (!canSee(loser)) {
+				r.push(`${winner.slaveName} grins at ${loser.slaveName}'s random swings and poor form. ${He} centers in on ${his} favorite part of ${loser.slaveName}'s body before rushing between ${his2} strikes and tackling ${him2} to the ground. ${loser.slaveName} lays there, helpless to stop ${winner.slaveName} from molesting ${him2}.`);
+
+				success = -0.1;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `annoyed`, ["reputation", "dec"]),
+						` by this lack of a fight.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience found the fight embarrassing, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "dec"]),
+						` is pitiful.`);
+				}
+			} else if (winnerDeadliness > (loserDeadliness + 3)) {
+				if (winner.skill.combat > 30) {
+					r.push(`${winner.slaveName} wants to win, and ${he} opens the fight with a furious attack. ${loser.slaveName} manages to get ${his2} ${hasBothArms(loser) ? `forearms` : `forearm`} up, blocking a few blows, but by doing so leaves ${his2} abdomen open and obscures ${his2} vision enough that ${he2} is unprepared for the following kidney strike, which brings ${him2} gasping to one knee. ${winner.slaveName} lets ${him2} rise just a little before delivering a calculated hard right that sends ${loser.slaveName} to the mat.`);
+
+					success = 0.125;
+
+					if (V.pit.audience === "free") {
+						r.push(`The audience is `,
+							App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]),
+							` by this execution.`);
+					} else if (V.pit.audience === "paid") {
+						r.push(`The audience is not very impressed by this execution, and your `,
+							App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+							` is unimpressive.`);
+					}
+				} else {
+					r.push(`${winner.slaveName} wants to win and is confident ${he} will, but ${he} isn't particularly sure about how to do so. ${He} fights cautiously, mostly hitting ${loser.slaveName} from afar. Slowly, the rain of blows begins to tell, opening ${loser.slaveName}'s lip, giving ${him2} a bloody nose, and bruising ${his2} face. Realizing ${he2} has to do something, ${loser.slaveName} makes a desperate counterattack, `, App.UI.DOM.makeElement("span", `dripping blood`, ["health",
+						"dec"]), ` as ${he2} goes. As ${he2} does ${he2} manages to get ${his2} face in the way of another of ${winner.slaveName}'s inexpert strikes and goes down hard. ${He2} makes to rise, but ${winner.slaveName} decides the fight by the simple expedient of kicking ${him2} in the crotch.`);
+
+					healthDamage(winner, 20);
+					success = 0.25;
+
+					if (V.pit.audience === "free") {
+						r.push(`The audience is `,
+							App.UI.DOM.makeElement("span", `reasonably impressed`, ["reputation", "inc"]),
+							` by the beating.`);
+					} else if (V.pit.audience === "paid") {
+						r.push(`The audience is reasonably impressed by the beating, and your `,
+							App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+							` is reasonable.`);
+					}
+				}
+			} else if (winner.belly > 60000 && loser.belly > 60000) {
+				r.push(`${winner.slaveName} and ${loser.slaveName} stare each other down and both come to a realization. Neither can reach the other around their massive bellies. Instead, they choose to ram their bulk into each other in hopes of toppling the weaker. After a drawn out struggle, both slaves' middles are `,
+					App.UI.DOM.makeElement("span", `dark red and shuddering,`, ["health", "dec"]),
+					` ready to burst open. Rather than continue, ${loser.slaveName} lets the next strike down ${him2} hoping that the outcome of this fight isn't fatal.`);
+
+				success = 0.375;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `very impressed`, ["reputation", "dec"]),
+						` by the showdown.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is very impressed by the showdown, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is good.`);
+				}
+			} else if (winner.belly > 60000 && loser.belly < 30000) {
+				r.push(`${loser.slaveName} spies an easy win against ${his2} massively bloated opponent and rushes in to topple ${winner.slaveName}. In an effort to defend ${himself}, ${winner.slaveName} hoists ${his} belly and turns suddenly, accidentally impacting ${loser.slaveName} with ${his} massive middle and knocking ${him2} to the ground. Seeing an opportunity, ${winner.slaveName} releases ${his} grip and slams ${his} weighty womb down on ${loser.slaveName}, bashing the wind out of ${him2}. ${loser.slaveName} struggles to slip out from under the mass, but the weight is too great and ${he2} passes out.`);
+
+				success = 0.25;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `impressed`, ["reputation", "dec"]),
+						` by this absurd win.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is impressed by this absurd win, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is reasonably.`);
+				}
+			} else if (winner.skill.combat > 30 && loser.skill.combat > 30) {
+				const healthSpans = [App.UI.DOM.makeElement("span", `broken nose`, ["health", "dec"]),
+					App.UI.DOM.makeElement("span", `to the point of damage`, ["health", "dec"])];
+
+				r.push(`Upon your word the two combatants approach each other warily, both knowing the other is reasonably competent. Before long they are trading expert blows. ${winner.slaveName} is getting the worst of it, so ${he} decides to change the nature of the fight. After three tries ${he} manages to bring ${loser.slaveName} to the ground, suffering a `, healthSpans[0], ` as ${he} does. ${loser.slaveName} tries to break the imperfect hold but only earns ${himself2} an elbow to the face. ${He2}'s furious and ${winner.slaveName} is obliged to wrench ${his2} arm `, healthSpans[1], ` before ${he2} allows ${himself2} to go limp.`);
+
+				success = 0.5;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `very impressed`, ["reputation", "inc"]),
+						` by the expert fight.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is quite impressed by the expert fight, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is quite good.`);
+				}
+			} else if (winner.height - loser.height < -10) {
+				r.push(`${winner.slaveName} realizes that ${loser.slaveName}'s wingspan gives ${him2} a huge reach advantage. ${He} bores straight in, taking a hit or two but coming on regardless. ${loser.slaveName} understands ${his2} opponent's intention and backs off, but the pit is small and there isn't much room to retreat. When ${his2} back hits a padded wall, ${winner.slaveName} manages to land a light hit to ${his2} stomach that leaves ${loser.slaveName} winded enough that a hard kick to the side of ${his2} knee goes undefended. It causes `, App.UI.DOM.makeElement("span", `considerable damage,`, ["health",
+					"dec"]), ` dropping ${him2} and ending the fight.`);
+
+				success = 0.25;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `reasonably impressed`, ["reputation", "inc"]),
+						` by the take-down.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is reasonably impressed by the take-down, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is reasonable.`);
+				}
+			} else if (loser.piercing.eyebrow.weight > 0) {
+				r.push(`The fight starts slowly, with the two trading jabs. Just as the spectators are getting bored, ${loser.slaveName} takes a glancing blow to the eyebrow. ${His2} piercing catches on ${winner.slaveName}'s glove and tears out. ${loser.slaveName} goes after ${his2} tormentor in fury, streaming blood, the piercing forgotten on the mat. Any tendency ${winner.slaveName} might have had to feel badly about this is extinguished by the assault, and soon ${winner.slaveName} is even willing to follow up on the success by targeting pierced body parts. The fight ends with poor ${loser.slaveName} writhing in pain on the mat, `, App.UI.DOM.makeElement("span", `leaking blood`, ["health",
+					"dec"]), ` from several terribly shredded areas.`);
+
+				success = 0.25;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `reasonably impressed`, ["reputation", "inc"]),
+						` by the gory spectacle.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is reasonably impressed by the gory spectacle, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is reasonable.`);
+				}
+			} else if (winner.muscles > 30) {
+				r.push(`${winner.slaveName} is so massively muscular that ${he}'s actually impeded by ${his} size. ${loser.slaveName} is properly afraid of ${his} strength, though, so ${he2} tries to stay away as much as ${he2} can. The pit isn't large, however, and eventually ${winner.slaveName} manages to lay a hand on ${him2}. ${He} pulls ${him2} down, and then it's all over but the beating. ${loser.slaveName} rains blows on ${his2} huge oppressor, but all ${winner.slaveName} has to do is hold on with one arm and deliver damage with the other. By the time ${he2} gives up and goes limp, ${loser.slaveName} has collected `, App.UI.DOM.makeElement("span", `many minor injuries.`, ["health",
+					"dec"]));
+
+				success = 0.25;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `reasonably impressed`, ["reputation", "inc"]),
+						` by the show of strength.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is reasonably impressed by the show of strength, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is reasonable.`);
+				}
+			} else if (loser.belly > 300000) {
+				r.push(`${winner.slaveName} wants to win badly enough that ${he} takes an extremely brutal shortcut to victory. The instant the fight starts, ${he} quickly knees ${loser.slaveName} in the stomach. The massively swollen ${loser.slaveName} goes down with a loud thud and plenty of jiggling. ${winner.slaveName} gloats over the struggling ${loser.slaveName} watching as ${he2} is unable to pull ${his2} bloated form off the ground.`);
+
+				success = 0.25;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]),
+						` by this easy win.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is not very impressed by this easy win, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is unimpressive.`);
+				}
+			} else if (loser.boobs > 1200) {
+				r.push(`${winner.slaveName} wants to win badly enough that ${he} takes an extremely simple shortcut to victory. The instant the fight starts, ${he} hits ${loser.slaveName} right in ${his2} huge tits, as hard as ${he} can. This is a sucker punch of the worst kind; ${loser.slaveName}'s boobs are so big that ${he2} has no real chance of defending them. ${He2} gasps with pain${hasAnyArms(loser) ? ` and wraps ${his2} ${hasBothArms(loser) ? `arms` : `arm`} around ${his2} aching bosom` : ``}, giving ${winner.slaveName} a clear opening to deliver a free and easy blow to the jaw that sends the poor top-heavy slave to the mat. Any chance of ${loser.slaveName} rising is extinguished by ${his2} breasts; it takes ${him2} so long to muster an attempt to get up that ${winner.slaveName} can rain hits on ${him2} while ${he2} does.`);
+
+				success = 0.125;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]),
+						` by this easy win.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is not very impressed by this easy win, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is unimpressive.`);
+				}
+			} else if (loser.dick > 0) {
+				r.push(`${winner.slaveName} wants to win badly enough that ${he} takes an extremely unpleasant shortcut to victory. The instant the fight starts, ${he} furiously goes for ${loser.slaveName}'s eyes${hasBothArms(winner) ? `, hands forming claws` : hasAnyArms(winner) ? `, ${his} hand forming a claw` : ``}. ${loser.slaveName} ${hasAnyArms(loser) ? `defends ${himself2} with ${his2} ${hasBothArms(loser) ? `arms` : `arm`}` : `tries to defend ${himself} as best ${he} can`}, at which point ${winner.slaveName} delivers a mighty cunt punt. ${loser.slaveName} goes straight down, ${his2} mouth soundlessly opening and closing and tears leaking from ${his2} closed eyes${hasAnyArms(loser)
+					? ` while ${his} ${hasBothArms(loser)
+						? `hands desperately shield`
+						: `hand desperately shields`} ${his2} outraged pussy`
+					: ``}. ${winner.slaveName} follows ${him2} down and puts the unresisting ${girl2}'s head in a simple lock.`);
+
+				success = 0.125;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]),
+						` by this easy win.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is not very impressed by this easy win, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is unimpressive.`);
+				}
+			} else if (loser.vagina > 0) {
+				r.push(`${winner.slaveName} wants to win badly enough that ${he} takes an extremely unpleasant shortcut to victory. The instant the fight starts, ${he} furiously goes for ${loser.slaveName}'s eyes${hasBothArms(winner) ? `, hands forming claws` : hasAnyArms(winner) ? `, ${his} hand forming a claw` : ``}. ${loser.slaveName} ${hasAnyArms(loser) ? `defends ${himself2} with ${his2} ${hasBothArms(loser) ? `arms` : `arm`}` : `tries to defend ${himself} as best ${he} can`}, at which point ${winner.slaveName} delivers a mighty cunt punt. ${loser.slaveName} goes straight down, ${his2} mouth soundlessly opening and closing and tears leaking from ${his2} closed eyes${hasAnyArms(loser) ? ` while ${his} ${hasBothArms(loser) ? `hands` : `hand`} desperately shield${!hasBothArms(loser) ? `s` : ``} ${his2} outraged pussy` : ``}. ${winner.slaveName} follows ${him2} down and puts the unresisting ${girl2}'s head in a simple lock.`);
+
+				success = 0.125;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]),
+						` by this easy win.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is not very impressed by this easy win, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is unimpressive.`);
+				}
+			} else {
+				r.push(`${winner.slaveName} wants to win badly enough that ${he} takes an extremely unpleasant shortcut to victory. The instant the fight starts, ${he} furiously goes for ${loser.slaveName}'s eyes, hands forming claws. ${loser.slaveName} defends ${himself2} with ${his2} arms, at which point ${winner.slaveName} delivers a clenched fist to ${loser.slaveName}'s throat. ${loser.slaveName} staggers back, wheezing for breath with tears leaking from ${his2} closed eyes. ${winner.slaveName} takes advantage of ${loser.slaveName}'s vulnerability to quickly trip and pin the coughing loser.`);
+
+				success = 0.125;
+
+				if (V.pit.audience === "free") {
+					r.push(`The audience is `,
+						App.UI.DOM.makeElement("span", `not very impressed`, ["reputation", "inc"]),
+						` by this easy win.`);
+				} else if (V.pit.audience === "paid") {
+					r.push(`The audience is not very impressed by this easy win, and your `,
+						App.UI.DOM.makeElement("span", `cut of the betting`, ["cash", "inc"]),
+						` is unimpressive.`);
+				}
+			}
+
+			App.Events.addParagraph(parent, r);
+		}
+
+		/** @param {DocumentFragment} parent */
+		function postFight(parent) {
+			let r = [];
+
+			const anus = "anus";
+			const cunt = "cunt";
+			const oral = "oral";
+			const vaginal = "vaginal";
+			const anal = "anal";
+
+
+			const {he, his, him, He} = getPronouns(winner);
+			const {his: his2, him: him2} = getPronouns(loser);
+
+			const facefuck = `${He} considers ${his} options briefly, then hauls the loser to ${his2} knees for a facefuck.`;
+			const winnerPenetrates = orifice => `${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`}, and penetrates the loser's ${orifice}.`;
+			const loserProtest = `${canTalk(loser)
+				? `${loser.slaveName} starts to scream a protest to stop ${winner.slaveName} raping ${him2} pregnant, but ${winner.slaveName} grinds ${his2} face into the mat to shut ${him2} up`
+				: `${loser.slaveName} tries to gesture a protest before ${winner.slaveName} fills ${his2} fertile ${loser.mpreg && that.params.virginities !== anal ? `asspussy` : `pussy`} with cum, but ${winner.slaveName} grabs ${his2} ${hasBothArms(loser) ? `hands and pins them` : hasAnyArms(loser) ? `hand and pins it` : `neck firmly`} to keep ${him2} from complaining`}.`;
+
+			const virginitySpan = App.UI.DOM.makeElement("span", ``, ["virginity", "loss"]);
+
+			r.push(`You throw the victor's strap-on down to ${winner.slaveName}.`);
+
+			if (canPenetrate(winner)) {
+				r.push(`${He} has no need of it, only taking a moment to pump ${his} dick a few times to get it to rock hardness.`);
+			} else if (winner.clit > 4) {
+				r.push(`${He} has no need of it, since ${his} clit is big enough to use instead.`);
+			} else if (winner.dick > 6 && !canAchieveErection(winner)) {
+				r.push(`${He} needs it, since ${his} enormous dick can't get hard any longer (not like it would fit in ${loser.slaveName} anyway).`);
+			} else if (winner.dick > 0) {
+				r.push(`${He} needs it, since ${his} soft dick won't be raping anything.`);
+			}
+
+			if (V.pit.virginities === "all") {
+				if (loser.vagina === 0 && canDoVaginal(loser) && loser.anus === 0 && canDoAnal(loser)) {
+					r.push(`${He} respects ${loser.slaveName}'s virgin holes, and hauls the loser to ${his2} knees for a facefuck.`);
+
+					actX(loser, oral);
+				} else if (loser.vagina === 0 && canDoVaginal(loser) && canDoAnal(loser)) {
+					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
+
+					if (winner.fetish === "pregnancy") {
+						r.push(`and, after ${canSee(winner) ? `eyeing` : `feeling up`} ${his2} virgin vagina with desire, penetrates the loser's anus.`);
+					} else {
+						r.push(`and respects the rules by penetrating the loser's anus.`);
+					}
+
+					if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 1, winner.ID);
+					}
+
+					actX(loser, anal);
+				} else if (loser.anus === 0 && canDoVaginal(loser) && canDoAnal(loser)) {
+					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
+
+					if (winner.fetish === "buttslut" || (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg && winner.fetish === "pregnancy")) {
+						r.push(`and, after ${canSee(winner) ? `eyeing` : `feeling up`} ${his2} virgin anus with desire, penetrates the loser's cunt.`);
+					} else {
+						r.push(`and respects the rules by penetrating the loser's cunt.`);
+					}
+
+					if (canPenetrate(winner) && canImpreg(loser, winner)) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 0, winner.ID);
+					}
+
+					actX(loser, vaginal);
+				} else if (canDoVaginal(loser)) {
+					r.push(winnerPenetrates(cunt));
+
+					if (canPenetrate(winner) && canImpreg(loser, winner)) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 0, winner.ID);
+					}
+
+					actX(loser, vaginal);
+				} else if (canDoAnal(loser)) {
+					r.push(winnerPenetrates(anus));
+
+					if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 1, winner.ID);
+					}
+
+					actX(loser, anal);
+				} else {
+					r.push(facefuck);
+
+					actX(loser, oral);
+				}
+			} else if (V.pit.virginities === "anal") {
+				if (loser.vagina === 0 && canDoVaginal(loser)) {
+					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
+
+					if (winner.fetish === "pregnancy") {
+						virginitySpan.append(`take ${his2} virginity.`);
+						r.push(`and gleefully takes advantage of your rules to `, virginitySpan);
+					} else {
+						virginitySpan.append(`breaks in ${his2} virgin vagina.`);
+						r.push(`and `, virginitySpan);
+					}
+
+					if (canPenetrate(winner) && canImpreg(loser, winner)) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 0, winner.ID);
+					}
+
+					loser.vagina++;
+					actX(loser, vaginal);
+				} else if (loser.anus === 0 && canDoAnal(loser)) {
+					r.push(`${canTalk(loser)
+						? `${loser.slaveName} starts to scream a protest to stop ${winner.slaveName} raping ${him2} pregnant, but ${winner.slaveName} grinds ${his2} face into the mat to shut ${him2} up`
+						: `${loser.slaveName} tries to gesture a protest before ${winner.slaveName} fills ${his2} fertile pussy with cum, but ${winner.slaveName} grabs ${his2} ${hasBothArms(loser) ? `hands and pins them` : hasAnyArms(loser) ? `hand and pins it` : `neck firmly`} to keep ${him2} from complaining`}.`);
+
+					if (winner.fetish === "buttslut" || (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg && winner.fetish === "pregnancy")) {
+						if (canDoVaginal(loser)) {
+							r.push(`and penetrates the loser's cunt.`);
+
+							if (canPenetrate(winner) && canImpreg(loser, winner)) {
+								r.push(loserProtest);
+
+								knockMeUp(loser, 50, 0, winner.ID);
+							}
+
+							loser.counter.vaginal++;
+							V.vaginalTotal++;
+						} else {
+							r.push(`and finds only a pristine butthole waiting for ${him}. Respecting ${his2} anal virginity, ${he} hauls the loser onto ${his2} knees for a facefuck.`);
+
+							actX(loser, oral);
+						}
+					}
+				} else if (canDoVaginal(loser)) {
+					r.push(winnerPenetrates(cunt));
+
+					if (canPenetrate(winner) && canImpreg(loser, winner)) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 0, winner.ID);
+					}
+
+					actX(loser, vaginal);
+				} else if (canDoAnal(loser)) {
+					r.push(winnerPenetrates(anus));
+
+					if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 1, winner.ID);
+					}
+
+					actX(loser, anal);
+				} else {
+					r.push(facefuck);
+
+					actX(loser, oral);
+				}
+			} else if (V.pit.virginities === "vaginal") {
+				if (loser.vagina === 0 && canDoVaginal(loser)) {
+					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
+
+					if (winner.fetish === "pregnancy") {
+						if (canDoAnal(loser)) {
+							r.push(`and hungrily eyes ${his2} pristine vagina before penetrating the loser's ass.`);
+
+							if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
+								r.push(loserProtest);
+
+								knockMeUp(loser, 50, 1, winner.ID);
+							}
+
+							actX(loser, anal);
+						} else {
+							r.push(`and hungrily eyes ${his2} pristine vagina before hauling the loser onto ${his2} knees for a facefuck.`);
+
+							actX(loser, oral);
+						}
+					} else {
+						if (canDoAnal(loser)) {
+							r.push(`and penetrates the loser's ass.`);
+
+							if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
+								r.push(loserProtest);
+
+								knockMeUp(loser, 50, 1, winner.ID);
+							}
+
+							actX(loser, anal);
+						} else {
+							r.push(`and finds only a pristine butthole waiting for ${him}. Respecting ${his2} anal virginity, ${he} hauls the loser onto ${his2} knees for a facefuck.`);
+
+							actX(loser, oral);
+						}
+					}
+				} else if (loser.anus === 0 && canDoAnal(loser)) {
+					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
+
+					if (winner.fetish === "buttslut" || (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg && winner.fetish === "pregnancy")) {
+						virginitySpan.append(`take ${his2} anal virginity.`);
+						r.push(`and gleefully takes advantage of your rules to `, virginitySpan);
+					} else {
+						virginitySpan.append(`breaks in ${his2} virgin anus.`);
+						r.push(`and `, virginitySpan);
+					}
+
+					if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 1, winner.ID);
+					}
+
+					loser.anus++;
+					actX(loser, anal);
+				} else if (canDoVaginal(loser)) {
+					r.push(winnerPenetrates(cunt));
+
+					if (canPenetrate(winner) && canImpreg(loser, winner)) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 0, winner.ID);
+					}
+
+					actX(loser, vaginal);
+				} else if (canDoAnal(loser)) {
+					r.push(winnerPenetrates(anus));
+
+					if (canPenetrate(winner) && canImpreg(loser, winner)) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 0, winner.ID);
+					}
+
+					actX(loser, anal);
+				} else {
+					r.push(facefuck);
+
+					actX(loser, oral);
+				}
+			} else {
+				if (loser.vagina === 0 && canDoVaginal(loser)) {
+					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
+
+					if (winner.fetish === "pregnancy") {
+						virginitySpan.append(`take ${his2} virginity.`);
+						r.push(`and gleefully takes advantage of your rules to `, virginitySpan);
+					} else {
+						virginitySpan.append(`breaks in ${his2} virgin vagina.`);
+						r.push(`and `, virginitySpan);
+					}
+
+					if (canPenetrate(winner) && canImpreg(loser, winner)) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 0, winner.ID);
+					}
+
+					loser.vagina++;
+					actX(loser, vaginal);
+				} else if (loser.anus === 0 && canDoAnal(loser)) {
+					r.push(`${He} pushes ${loser.slaveName}'s back down onto the mat, forces ${his2} ${hasBothLegs(loser) ? `legs apart` : !hasAnyLegs(loser) ? `hips steady` : `leg aside`},`);
+
+					if (winner.fetish === "buttslut" || (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg && winner.fetish === "pregnancy")) {
+						virginitySpan.append(`take ${his2} anal virginity.`);
+						r.push(`and gleefully takes advantage of your rules to `, virginitySpan);
+					} else {
+						virginitySpan.append(`breaks in ${his2} virgin anus.`);
+						r.push(`and `, virginitySpan);
+					}
+
+					if (canPenetrate(winner) && canImpreg(loser, winner) && loser.mpreg) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 1, winner.ID);
+					}
+
+					loser.anus++;
+					actX(loser, anal);
+				} else if (canDoVaginal(loser)) {
+					r.push(winnerPenetrates(cunt));
+
+					if (canPenetrate(winner) && canImpreg(loser, winner)) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 0, winner.ID);
+					}
+
+					actX(loser, vaginal);
+				} else if (canDoAnal(loser)) {
+					r.push(winnerPenetrates(anus));
+
+					if (canPenetrate(winner) && canImpreg(loser, winner)) {
+						r.push(loserProtest);
+
+						knockMeUp(loser, 50, 1, winner.ID);
+					}
+
+					actX(loser, anal);
+				} else {
+					r.push(facefuck);
+
+					actX(loser, oral);
+				}
+			}
+
+			App.Events.addParagraph(parent, r);
+
+			App.Events.addParagraph(parent, [...rape(), ...rapeEffects()]);
+
+			r = [];
+			if (winner.skill.combat < 60) {
+				const experienceSpan = App.UI.DOM.makeElement("span", `improved ${his} combat skills.`, ["improvement"]);
+
+				winner.skill.combat += 5 + Math.floor(0.5 * (winner.intelligence + winner.intelligenceImplant) / 32);
+				r.push(`With experience in ${V.pit.name}, ${winner.slaveName} has `, experienceSpan);
+			}
+
+			loser.counter.pitLosses++;
+			actX(winner, "penetrative");
+
+			winner.counter.pitWins++;
+
+
+			V.pitFightsTotal++;
+
+			App.Events.addParagraph(parent, r);
+
+			function rape() {
+				const repSpan = App.UI.DOM.makeElement("span", ``, ["reputation", "inc"]);
+
+				const r = [];
+
+				const {he, his, He} = getPronouns(winner);
+				const {he: he2, his: his2, him: him2, girl: girl2} = getPronouns(loser);
+
+				if (winner.sexualFlaw === "malicious") {
+					r.push(`${winner.slaveName} lives to torment and violate slaves. ${He} uses ${loser.slaveName} for ${his} `, App.UI.DOM.makeElement("span", `pleasure`, ["devotion",
+						"inc"]), ` slapping ${him2} viciously, pinching ${him2} until ${he} draws blood, and showing off for the spectators.`);
+
+					if (V.pit.audience !== "none") {
+						repSpan.append(`greatly enjoys`);
+						r.push(`The audience `, repSpan, ` the depraved spectacle.`);
+
+						repX(50, "pit", winner);
+					}
+
+					winner.devotion++;
+				} else if (winner.sexualFlaw === "abusive") {
+					r.push(`${winner.slaveName} lives to abuse and violate slaves. ${He} uses ${loser.slaveName} for ${his} `, App.UI.DOM.makeElement("span", `pleasure`, ["devotion",
+						"inc"]), ` raping ${him2} mercilessly, striking ${him2} until ${he2} turns a deep reddish-purple, and showing off for the spectators.`);
+
+					if (V.pit.audience !== "none") {
+						repSpan.append(`greatly enjoys`);
+						r.push(`The audience `, repSpan, ` the depraved spectacle.`);
+
+						repX(50, "pit", winner);
+					}
+
+					winner.devotion++;
+				} else if (winner.energy > 95) {
+					r.push(`${winner.slaveName} doesn't have to feign willingness to rape a slave ${girl2}. ${He} uses ${loser.slaveName} for ${his} `, App.UI.DOM.makeElement("span", `pleasure,`, ["devotion",
+						"inc"]), ` groping ${him2}, kissing ${his2} unwilling mouth, and showing off for the spectators.`);
+
+					if (V.pit.audience !== "none") {
+						repSpan.append(`greatly enjoys`);
+						r.push(`The audience `, repSpan, ` the depraved spectacle.`);
+
+						repX(50, "pit", winner);
+					}
+
+					winner.devotion++;
+				} else if (winner.fetish === "sadist" && winner.fetishStrength > 60) {
+					r.push(`${winner.slaveName} doesn't have to feign willingness abuse and violate a slave ${girl2}. ${He} uses ${loser.slaveName} for ${his} `, App.UI.DOM.makeElement("span", `pleasure`, ["devotion",
+						"inc"]), ` slapping ${him2} cruelly, pinching ${him2} until ${he} draws blood, and showing off for the spectators.`);
+
+					if (V.pit.audience !== "none") {
+						repSpan.append(`greatly enjoys`);
+						r.push(`The audience `, repSpan, ` the depraved spectacle.`);
+
+						repX(50, "pit", winner);
+					}
+
+					winner.devotion++;
+				} else if (winner.devotion > 75) {
+					r.push(`${winner.slaveName} is so broken to slavery that ${he} `, App.UI.DOM.makeElement("span", `enjoys`, ["devotion",
+						"inc"]), ` winning the fight and raping ${loser.slaveName}.`);
+
+					if (V.pit.audience !== "none") {
+						repSpan.append(`greatly enjoys`);
+						r.push(`The audience `, repSpan, ` the depraved spectacle.`);
+
+						repX(50, "pit", winner);
+					}
+
+					winner.devotion++;
+				} else if (winner.devotion > 20) {
+					r.push(`${winner.slaveName} understands ${his} role and thoroughly rapes ${loser.slaveName}.`);
+
+					if (V.pit.audience !== "none") {
+						repSpan.append(`enjoys`);
+						r.push(`The audience `, repSpan, ` the spectacle.`);
+
+						repX(25, "pit", winner);
+					}
+				} else {
+					r.push(`${winner.slaveName} is unenthusiastic and just thrusts mechanically, to avoid being punished. ${He} `, App.UI.DOM.makeElement("span", `resents`, ["devotion",
+						"dec"]), ` having to fight and fuck.`);
+
+					if (V.pit.audience !== "none") {
+						r.push(`The audience barely pays attention.`);
+					}
+
+					winner.devotion -= 2;
+				}
+
+				return r;
+			}
+
+			function rapeEffects() {
+				const r = [];
+
+				const {he, his, him, himself, He} = getPronouns(winner);
+				const {he: he2, him: him2, He: He2} = getPronouns(loser);
+
+				r.push(...winnerEffects(), ...loserEffects());
+
+				if (loser.fetish !== "masochist" && loser.fetish !== "humiliation" && loser.sexualFlaw !== "self hating" && loser.relationship && loser.relationship < 5 && winner.ID === loser.relationshipTarget) {
+					r.push(`Fighting and rape have `, App.UI.DOM.makeElement("span", `damaged`, ["relationship",
+						"dec"]), ` the relationship between the slaves.`);
+				}
+
+				return r;
+
+				function winnerEffects() {
+					const r = [];
+
+					if (winner.rivalry && loser.ID === winner.rivalryTarget) {
+						r.push(`${He} `, App.UI.DOM.makeElement("span", `relishes`, ["devotion",
+							"inc"]), ` the chance to abuse ${loser.slaveName}, whom ${he} dislikes.`);
+
+						winner.devotion += 5;
+					} else if (winner.relationship && loser.ID === winner.relationshipTarget) {
+						if (winner.devotion > 20) {
+							r.push(`${He} accepts having to abuse ${loser.slaveName}, and plans to make it up to ${him2} later.`);
+						} else {
+							r.push(`${He} `, App.UI.DOM.makeElement("span", `hates`, ["devotion",
+								"dec"]), ` having to abuse ${loser.slaveName}.`);
+
+							winner.devotion -= 10;
+						}
+					} else if (areRelated(winner, loser)) {
+						if (winner.devotion > 20) {
+							r.push(`${He} accepts having to abuse ${his} ${relativeTerm(winner, loser)}, ${loser.slaveName}, and plans to make it up to ${him2} later.`);
+						} else {
+							r.push(`${He} `, App.UI.DOM.makeElement("span", `hates`, ["devotion",
+								"dec"]), ` having to abuse ${his} ${relativeTerm(winner, loser)}, ${loser.slaveName}.`);
+
+							winner.devotion -= 10;
+						}
+					}
+
+					if (winner.fetish === "sadist" && winner.fetishStrength > 90 && winner.sexualFlaw !== "malicious" && winner.devotion > 20) {
+						r.push(`${He} noticed something while ${he} was raping ${loser.slaveName}; watching the way ${he2} writhed in pain was strangely satisfying, as ${he} was making ${him2} suffer. ${winner.slaveName} cums powerfully at the mere thought; ${he} has become `, App.UI.DOM.makeElement("span", `sexually addicted to inflicting pain and anguish.`, ["noteworthy"]));
+
+						winner.sexualFlaw = "malicious";
+					} else if (winner.fetish === "masochist" && winner.fetishStrength > 90 && winner.sexualFlaw !== "self hating" && winner.devotion < 20) {
+						r.push(`${He} feels horrible after forcing ${himself} on ${loser.slaveName}; ${he} is the one that should suffer, not ${him2}. ${winner.slaveName} has `, App.UI.DOM.makeElement("span", `descended into true self hatred.`, ["noteworthy"]));
+
+						winner.sexualFlaw = "self hating";
+					} else if (winner.fetish === "dom" && winner.fetishStrength > 90 && winner.sexualFlaw !== "abusive" && winner.devotion > 20) {
+						r.push(`${He} noticed something while ${he} was raping ${loser.slaveName}; watching the way ${he2} cowered before ${hasAnyArms(winner) ? `${his} raised palm` : `${him}`} was strangely satisfying, as were the painful moans that accompanied every forceful thrust. ${winner.slaveName} cums powerfully at the mere thought; ${he} has become `, App.UI.DOM.makeElement("span", `sexually abusive, getting off on the thrill of forcing ${himself} on other slaves.`, ["noteworthy"]));
+
+						winner.sexualFlaw = "abusive";
+					} else if (winner.behavioralFlaw === "none" && random(1, 100) < 5 && winner.devotion < 20) {
+						r.push(`${He} begins to act `, App.UI.DOM.makeElement("span", `oddly`, ["flaw",
+							"gain"]), ` after the fight; having to beat down and rape another slave may have affected ${him} mentally.`);
+
+						winner.behavioralFlaw = "odd";
+					}
+
+					return r;
+				}
+
+				function loserEffects() {
+					const trustSpan = App.UI.DOM.makeElement("span", `fears`, ["trust", "dec"]);
+
+					const r = [];
+
+					if (loser.sexualFlaw === "self hating") {
+						r.push(`${loser.slaveName} feels ${he2} `, App.UI.DOM.makeElement("span", `deserved this.`, ["devotion",
+							"inc"]));
+
+						loser.devotion += 5;
+					} else if (loser.fetish === "masochist" && loser.fetishStrength > 60 && loser.fetishKnown) {
+						r.push(`${loser.slaveName} `, App.UI.DOM.makeElement("span", `gets off`, ["devotion",
+							"inc"]), ` on being beaten and molested.`);
+
+						loser.devotion += 5;
+					} else if (loser.fetish === "humiliation" && loser.fetishStrength > 60 && loser.fetishKnown) {
+						r.push(`${loser.slaveName} `, App.UI.DOM.makeElement("span", `enjoys`, ["devotion",
+							"inc"]), ` the humiliation of being openly beaten and raped.`);
+
+						loser.devotion += 5;
+					} else if (loser.devotion < 50) {
+						r.push(`${loser.slaveName} `, App.UI.DOM.makeElement("span", `resents`, ["devotion",
+							"dec"]), ` being beaten and molested and `, trustSpan, ` that it will happen again.`);
+
+						loser.devotion -= 10;
+						loser.trust -= 10;
+					}
+
+					if (loser.rivalry && winner.ID === loser.rivalryTarget) {
+						r.push(`${He2} is `, App.UI.DOM.makeElement("span", `embarrassed`, ["devotion",
+							"dec"]), ` by losing to and being raped by ${winner.slaveName}, whom ${he2} dislikes, and `, trustSpan, ` that it will happen again.`);
+
+						loser.devotion -= 10;
+						loser.trust -= 10;
+					} else if (loser.relationship && winner.ID === loser.relationshipTarget) {
+						if (loser.devotion > 20) {
+							r.push(`${He2} accepts ${winner.slaveName} having to rape ${him2}.`);
+						} else {
+							r.push(`${He2} `, App.UI.DOM.makeElement("span", `hates`, ["devotion",
+								"dec"]), ` having to accept rape from ${winner.slaveName}, and `, trustSpan, ` that it will happen again.`);
+
+							loser.devotion -= 10;
+							loser.trust -= 10;
+						}
+					} else if (areRelated(loser, winner)) {
+						if (loser.devotion > 20) {
+							r.push(`${He2} accepts ${his} ${relativeTerm(loser, winner)}, ${winner.slaveName}, having to rape ${him2}, but ${he2} `, trustSpan, ` that it will happen again.`);
+
+							loser.trust -= 10;
+						} else {
+							r.push(`${He2} `, App.UI.DOM.makeElement("span", `hates`, ["devotion",
+								"dec"]), ` having to accept rape from ${his} ${relativeTerm(loser, winner)}, ${winner.slaveName}, and `, trustSpan, ` that it will happen again.`);
+
+							loser.devotion -= 10;
+							loser.trust -= 10;
+						}
+					}
+
+					if (loser.fetish === "masochist" && loser.fetishStrength > 90 && loser.sexualFlaw !== "self hating") {
+						r.push(`${He2} feels strangely content after being abused and violated; ${he2} is the one that should suffer, after all. ${loser.slaveName} has `, App.UI.DOM.makeElement("span", `descended into true self hatred.`, ["flaw",
+							"gain"]));
+						loser.sexualFlaw = "self hating";
+					} else if (loser.behavioralFlaw === "none" && random(1, 100) < 5 && loser.devotion < 20) {
+						r.push(`${He2} begins to act `, App.UI.DOM.makeElement("span", `oddly`, ["flaw",
+							"gain"]), ` after the fight; losing and getting raped may have affected ${him2} mentally.`);
+
+						loser.behavioralFlaw = "odd";
+					}
+
+					return r;
+				}
+			}
+		}
+
+		// Helper Functions
+		/** @returns {boolean} Returns true if slave1 won */
+		function getWinner() {
+			if (deadliness(slave1).value > deadliness(slave2).value) {
+				return random(1, 100) > 20;	// 80% chance of winning
+			} else if (deadliness(slave1).value < deadliness(slave2).value) {
+				return random(1, 100) > 80;	// 20% chance of winning
+			} else if (random(1, 100) > 50) { // 50/50
+				return true;
+			}
+
+			return false;
+		}
+	}
+
+	introCombatants(slave1, slave2) {
+		return [`This fight is between`, App.UI.DOM.slaveDescriptionDialog(slave1), `and`,
+			App.UI.DOM.combineNodes(contextualIntro(slave1, slave2, true), ".")];
+	}
+};
diff --git a/src/facilities/pit/fights/1_lethalBodyguard.js b/src/facilities/pit/fights/1_lethalBodyguard.js
new file mode 100644
index 0000000000000000000000000000000000000000..a1eba8b9225e9d4dc0880cd20150e619c67f8d56
--- /dev/null
+++ b/src/facilities/pit/fights/1_lethalBodyguard.js
@@ -0,0 +1,34 @@
+/** Lethal 1v1 between the BG and a random slave. */
+App.Facilities.Pit.Fights.LBg1v1 = class extends App.Facilities.Pit.Fights.LR1v1 {
+	fightDescription() {
+		const f = new DocumentFragment();
+		f.append("1-vs-1 fight between your bodyguard ", App.UI.DOM.slaveDescriptionDialog(getSlave(this.actors[0])), ` and `,
+			contextualIntro(getSlave(this.actors[0]), getSlave(this.actors[1]), true), ".");
+		return f;
+	}
+
+	get impact() {
+		return super.impact * 1.1;
+	}
+
+	fightPrerequisites() {
+		return [...super.fightPrerequisites(), () => !!S.Bodyguard];
+	}
+
+	forcedActors() {
+		return [S.Bodyguard.ID];
+	}
+
+	actorPrerequisites() {
+		return [
+			[]
+		];
+	}
+
+	introCombatants(slave1, slave2) {
+		const {his1} = getPronouns(slave1).appendSuffix("1");
+		return [`In this fight your bodyguard`, App.UI.DOM.slaveDescriptionDialog(slave1),
+			`will demonstrate ${his1} combat prowess on`,
+			App.UI.DOM.combineNodes(contextualIntro(slave1, slave2, true), ".")];
+	}
+};
diff --git a/src/facilities/pit/fights/1_lethalScheduled.js b/src/facilities/pit/fights/1_lethalScheduled.js
new file mode 100644
index 0000000000000000000000000000000000000000..aece15f06fc6b3cbeef425253c7c4265ed037402
--- /dev/null
+++ b/src/facilities/pit/fights/1_lethalScheduled.js
@@ -0,0 +1,26 @@
+/** Lethal 1v1 between the BG and a random slave. */
+App.Facilities.Pit.Fights.LSch1v1 = class extends App.Facilities.Pit.Fights.LR1v1 {
+	fightDescription() {
+		const f = new DocumentFragment();
+		f.append("Scheduled: 1-vs-1 fight between ", App.UI.DOM.slaveDescriptionDialog(getSlave(this.actors[0])), ` and `,
+			contextualIntro(getSlave(this.actors[0]), getSlave(this.actors[1]), true), ".");
+		return f;
+	}
+
+	fightPrerequisites() {
+		return [...super.fightPrerequisites(), () => V.pit.slavesFighting !== null];
+	}
+
+	forcedActors() {
+		return [V.pit.slavesFighting[0], V.pit.slavesFighting[1]];
+	}
+
+	actorPrerequisites() {
+		return [];
+	}
+
+	execute(node) {
+		V.pit.slavesFighting = null;
+		return super.execute(node);
+	}
+};
diff --git a/src/facilities/pit/fights/1_nonLethalBodyguard.js b/src/facilities/pit/fights/1_nonLethalBodyguard.js
new file mode 100644
index 0000000000000000000000000000000000000000..f6cc33d05456974a3d379de32b50532c3cdc52df
--- /dev/null
+++ b/src/facilities/pit/fights/1_nonLethalBodyguard.js
@@ -0,0 +1,34 @@
+/** Nonlethal 1v1 between the BG and a random slave. */
+App.Facilities.Pit.Fights.NlBg1v1 = class extends App.Facilities.Pit.Fights.NlR1v1 {
+	fightDescription() {
+		const f = new DocumentFragment();
+		f.append("1-vs-1 fight between your bodyguard ", App.UI.DOM.slaveDescriptionDialog(getSlave(this.actors[0])), ` and `,
+			contextualIntro(getSlave(this.actors[0]), getSlave(this.actors[1]), true), ".");
+		return f;
+	}
+
+	get impact() {
+		return super.impact * 1.1;
+	}
+
+	fightPrerequisites() {
+		return [...super.fightPrerequisites(), () => !!S.Bodyguard];
+	}
+
+	forcedActors() {
+		return [S.Bodyguard.ID];
+	}
+
+	actorPrerequisites() {
+		return [
+			[]
+		];
+	}
+
+	introCombatants(slave1, slave2) {
+		const {his1} = getPronouns(slave1).appendSuffix("1");
+		return [`In this fight your bodyguard`, App.UI.DOM.slaveDescriptionDialog(slave1),
+			`will demonstrate ${his1} combat prowess on`,
+			App.UI.DOM.combineNodes(contextualIntro(slave1, slave2, true), ".")];
+	}
+};
diff --git a/src/facilities/pit/fights/1_nonLethalScheduled.js b/src/facilities/pit/fights/1_nonLethalScheduled.js
new file mode 100644
index 0000000000000000000000000000000000000000..dc53667286d8cd97f824b7670bb13f8a31c6c217
--- /dev/null
+++ b/src/facilities/pit/fights/1_nonLethalScheduled.js
@@ -0,0 +1,25 @@
+/** Nonlethal 1v1 between the BG and a random slave. */
+App.Facilities.Pit.Fights.NlSch1v1 = class extends App.Facilities.Pit.Fights.NlR1v1 {
+	fightDescription() {
+		const f = new DocumentFragment();
+		f.append("Scheduled: 1-vs-1 fight between ", App.UI.DOM.slaveDescriptionDialog(getSlave(this.actors[0])), ` and `,
+			contextualIntro(getSlave(this.actors[0]), getSlave(this.actors[1]), true), ".");
+		return f;
+	}
+
+	fightPrerequisites() {
+		return [...super.fightPrerequisites(), () => V.pit.slavesFighting !== null];
+	}
+
+	forcedActors() {
+		return [V.pit.slavesFighting[0], V.pit.slavesFighting[1]];
+	}
+
+	actorPrerequisites() {
+		return [];
+	}
+	execute(node) {
+		V.pit.slavesFighting = null;
+		return super.execute(node);
+	}
+};
diff --git a/src/facilities/pit/fights/2_lethalScheduledBG.js b/src/facilities/pit/fights/2_lethalScheduledBG.js
new file mode 100644
index 0000000000000000000000000000000000000000..514589c5563e7fc6980459a84bff9efabfa6581b
--- /dev/null
+++ b/src/facilities/pit/fights/2_lethalScheduledBG.js
@@ -0,0 +1,33 @@
+/** Lethal 1v1 between the BG and a random slave. */
+App.Facilities.Pit.Fights.LSchBg1v1 = class extends App.Facilities.Pit.Fights.LBg1v1 {
+	fightDescription() {
+		const f = new DocumentFragment();
+		f.append("Scheduled: 1-vs-1 fight between your bodyguard ", App.UI.DOM.slaveDescriptionDialog(getSlave(this.actors[0])), ` and `,
+			contextualIntro(getSlave(this.actors[0]), getSlave(this.actors[1]), true), ".");
+		return f;
+	}
+
+	fightPrerequisites() {
+		return [() => V.pit.slaveFightingBodyguard !== null, ...super.fightPrerequisites()];
+	}
+
+	forcedActors() {
+		return [...super.forcedActors(), V.pit.slaveFightingBodyguard];
+	}
+
+	actorPrerequisites() {
+		return [];
+	}
+
+	execute(node) {
+		V.pit.slaveFightingBodyguard = null;
+		return super.execute(node);
+	}
+
+	introCombatants(slave1, slave2) {
+		const {his1} = getPronouns(slave1).appendSuffix("1");
+		return [`In this scheduled fight your bodyguard`, App.UI.DOM.slaveDescriptionDialog(slave1),
+			`will demonstrate ${his1} combat prowess on`,
+			App.UI.DOM.combineNodes(contextualIntro(slave1, slave2, true), ".")];
+	}
+};
diff --git a/src/facilities/pit/pit.js b/src/facilities/pit/pit.js
index 74d2f0e284441e69a9f8e22966c10eea3d210e4c..4b377f034145e3b5eb4e5029b2d91d2c384f21e1 100644
--- a/src/facilities/pit/pit.js
+++ b/src/facilities/pit/pit.js
@@ -5,11 +5,6 @@ App.Facilities.Pit.pit = function() {
 
 	const pit = App.Entity.facilities.pit;
 
-	if (V.pit.slavesFighting.length !== 2) {
-		V.pit.slavesFighting = [];
-		V.pit.fighters = V.pit.fighters !== 4 ? V.pit.fighters : 0;
-	}
-
 	const container = document.createElement("div");
 	container.append(assemble());
 	return container;
@@ -30,10 +25,15 @@ App.Facilities.Pit.pit = function() {
 
 		const fightsFrag = new DocumentFragment();
 		App.UI.DOM.appendNewElement("div", fightsFrag, pitDescription(), ['margin-bottom']);
-		App.UI.DOM.appendNewElement("div", fightsFrag, pitRules(), ['margin-bottom']);
-		App.UI.DOM.appendNewElement("div", fightsFrag, pitScheduled(), ['margin-bottom']);
 		App.UI.DOM.appendNewElement("div", fightsFrag, pitSlaves(), ['margin-bottom']);
-		tabs.addTab("Fights", "fights", fightsFrag);
+		tabs.addTab("Fighters", "fights", fightsFrag);
+
+		const endWeekFrag = new DocumentFragment();
+		App.UI.DOM.appendNewElement("div", endWeekFrag, arenaUpgrades(), ['margin-bottom']);
+		App.UI.DOM.appendNewElement("div", endWeekFrag, arenaRules(), ['margin-bottom']);
+		App.UI.DOM.appendNewElement("div", endWeekFrag, arenaScheduledBG(), ['margin-bottom']);
+		App.UI.DOM.appendNewElement("div", endWeekFrag, arenaScheduledFight(), ['margin-bottom']);
+		tabs.addTab("Fights", "ew_fights", endWeekFrag);
 
 		frag.append(tabs.render());
 
@@ -45,6 +45,46 @@ App.Facilities.Pit.pit = function() {
 		App.UI.DOM.replace(container, assemble());
 	}
 
+
+	function arenaScheduledBG() {
+		const el = document.createDocumentFragment();
+
+		if (V.pit.slaveFightingBodyguard !== null) {
+			const bodyguard = V.pit.slaveFightingBodyguard;
+
+			el.append(`You have scheduled ${getSlave(bodyguard).slaveName} to fight your bodyguard to the death this week.`);
+
+			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.link(`Cancel it`, () => {
+				V.pit.slaveFightingBodyguard = null;
+
+				App.UI.reload();
+			}), ['indent']);
+		}
+		return el;
+	}
+
+	function arenaScheduledFight() {
+		const el = document.createDocumentFragment();
+
+		if (V.pit.slavesFighting !== null) {
+			const [slave1, slave2] = V.pit.slavesFighting;
+
+			el.append(`You have scheduled `, App.UI.DOM.slaveDescriptionDialog(getSlave(slave1)), ` and `,
+				contextualIntro(getSlave(slave1), getSlave(slave2), true), " to fight this week.");
+
+			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.link(`Cancel it`, () => {
+				V.pit.slavesFighting = null;
+
+				App.UI.reload();
+			}), ['indent']);
+		} else {
+			el.append(App.UI.DOM.passageLink("Schedule two slaves to fight each other.", "Pit Workaround"));
+		}
+
+		return el;
+	}
+
+
 	function intro() {
 		const el = document.createDocumentFragment();
 
@@ -188,176 +228,84 @@ App.Facilities.Pit.pit = function() {
 		return el;
 	}
 
-	function pitRules() {
+	function arenaRules() {
 		const el = document.createDocumentFragment();
 
-		const animal = V.active.canine || V.active.hooved || V.active.feline;
-		/** @type {FC.Facilities.Rule[]} */
-		const rules = !V.pit.slaveFightingAnimal && !V.pit.slaveFightingBodyguard// only display if a fight has not been scheduled
-			? [{
-				property: "audience", prereqs: [], options: [{
-					get text() {
-						return `Fights here are strictly private.`;
-					}, link: `Closed`, value: 'none',
-				}, {
-					get text() {
-						return `Fights here are free and open to the public.`;
-					}, link: `Free`, value: 'free',
-				}, {
-					get text() {
-						return `Admission is charged to the fights here.`;
-					}, link: `Paid`, value: 'paid',
-				}, ], object: V.pit,
-			}, {
-				property: "fighters", prereqs: [], options: [{
-					get text() {
-						return `Two fighters will be selected from the pool at random.`;
-					}, link: `Slaves`, value: 0,
-				}, {
-					get text() {
-						return `Your bodyguard ${S.Bodyguard.slaveName} will fight a slave selected from the pool at random.`;
-					}, link: `Bodyguard`, value: 1, prereqs: [!!S.Bodyguard, ],
-				}, {
-					get text() {
-						return `A random slave will fight an animal.`;
-					}, link: `Animal`, value: 2, prereqs: [!!animal, ], handler: () => {
-						if (!V.pit.animal) {
-							V.pit.animal = animal;
-						}
-					},
-				}, {
-					get text() {
-						return `A random slave will fight another slave${S.Bodyguard && !animal ? ` or your bodyguard` : S.Bodyguard ? `, your bodyguard` : ``}${animal ? ` or an animal` : ``}.`;
-					}, link: `Random`, value: 3, prereqs: [!!S.Bodyguard || !!animal, ],
-				}, {
-					get text() {
-						return `${V.pit.slavesFighting.length > 1 ? `${SlaveFullName(getSlave(V.pit.slavesFighting[0]))} will fight ${SlaveFullName(getSlave(V.pit.slavesFighting[1]))} this week.` : `Two chosen slaves will fight.`}`;
-					}, link: `Choose slaves`, value: 4, handler: () => {
-						Engine.play("Pit Workaround");
-
-						V.pit.slavesFighting = [];
-					},
-				}, ], object: V.pit,
-			}, {
-				property: "animal", prereqs: [V.pit.fighters === 2 || V.pit.fighters === 3, !!animal, ], options: [{
-					get text() {
-						return `Your slave will fight ${getAnimal(V.active.canine).articleAn} ${V.active.canine}.`;
-					},
-					get link() {
-						return capFirstChar(V.active.canine);
-					},
-					value: V.active.canine,
-					prereqs: [!!V.active.canine,
-						!["beagle", "French bulldog", "poodle", "Yorkshire terrier"].includes(V.active.canine), ],
-				}, {
-					get text() {
-						return `Your slave will fight ${getAnimal(V.active.hooved).articleAn} ${V.active.hooved}.`;
-					}, get link() {
-						return capFirstChar(V.active.hooved);
-					}, value: V.active.hooved, prereqs: [!!V.active.hooved, ],
-				}, {
-					get text() {
-						return `Your slave will fight ${getAnimal(V.active.feline).articleAn} ${V.active.feline}.`;
-					},
-					get link() {
-						return capFirstChar(V.active.feline);
-					},
-					value: V.active.feline,
-					prereqs: [!!V.active.feline, getAnimal(V.active.feline)?.species !== "cat", ],
-				}, {
-					get text() {
-						return `Your slave will fight one of your animals at random.`;
-					},
-					link: `Random`,
-					value: 'random',
-					prereqs: [(!!V.active.canine && !!V.active.hooved) || (!!V.active.canine && !!V.active.feline) || (!!V.active.hooved && !!V.active.feline), ],
-				}, ], object: V.pit,
-			}, {
-				property: "lethal", prereqs: [], options: [{
-					get text() {
-						return V.pit.fighters === 2 ? `The fighter will be armed with a sword and will fight to the death.` : `Fighters will be armed with swords, and fights will be to the death.`;
-					}, link: `Lethal`, value: true,
-				}, {
-					get text() {
-						return V.pit.fighters === 2 ? `The slave will be restrained and will try to avoid becoming the animal's plaything.` : `Fighters will use their fists and feet, and fights will be to submission.`;
-					}, link: `Nonlethal`, value: false,
-				}, ], object: V.pit,
-			}, {
-				property: "virginities", prereqs: [V.pit.fighters !== 2, !V.pit.lethal, ], options: [{
-					get text() {
-						return `No virginities of the loser will be respected.`;
-					}, link: `Neither`, value: 'neither',
-				}, {
-					get text() {
-						return `Vaginal virginity of the loser will be respected.`;
-					}, link: `Vaginal`, value: 'vaginal',
-				}, {
-					get text() {
-						return `Anal virginity of the loser will be respected.`;
-					}, link: `Anal`, value: 'anal',
-				}, {
-					get text() {
-						return `All virginities of the loser will be respected.`;
-					}, link: `All`, value: 'all',
-				}, ], object: V.pit,
-			}, ] : [];
-
-		if (rules.length > 0 && rules.some(rule => rule.prereqs.every(prereq => prereq === true))) {
-			App.UI.DOM.appendNewElement("h2", el, `Rules`);
-
-			rules.forEach(rule => {
-				if (rule.prereqs.every(prereq => prereq === true)) {
-					const options = new App.UI.OptionsGroup();
-					const option = options.addOption(null, rule.property, rule.object || V);
-
-					rule.options.forEach(o => {
-						if (!o.prereqs || o.prereqs.every(prereq => prereq === true)) {
-							option.addValue(o.link, o.value);
-							if (o.handler) {
-								option.addCallback(o.handler);
-							}
-							if (o.note) {
-								option.addComment(o.note);
-							}
-
-							if ((rule.object && _.isEqual(rule.object[rule.property], o.value)) || _.isEqual(V[rule.property], o.value)) {
-								App.UI.DOM.appendNewElement("div", el, o.text);
-							}
-						}
-					});
-
-					App.UI.DOM.appendNewElement("div", el, options.render(), ['margin-bottom']);
-				}
-
-				if (rule.nodes) {
-					App.Events.addNode(el, rule.nodes);
-				}
-			});
+		const options = new App.UI.OptionsGroup();
+
+		options.addOption("Host fights once a week", "active", V.pit)
+			.addValue("Yes", true).on()
+			.addValue("No", false).off();
+
+		let option = options.addOption("Audience", "audience", V.pit)
+			.addValue("Closed", "none")
+			.addValue("Free", "free")
+			.addValue("Paid", "paid");
+		if (V.pit.audience === "none") {
+			option.addComment(`Fights here are strictly private.`);
+		} else if (V.pit.audience === "free") {
+			option.addComment(`Fights here are free and open to the public.`);
+		} else if (V.pit.audience === "paid") {
+			option.addComment(`Admission is charged to the fights here.`);
 		}
 
-		return el;
-	}
-
-	function pitScheduled() {
-		const el = document.createDocumentFragment();
-
-		if (V.pit.slaveFightingAnimal || V.pit.slaveFightingBodyguard) {
-			const animal = V.pit.slaveFightingAnimal;
-			const bodyguard = V.pit.slaveFightingBodyguard;
-
-			el.append(`You have scheduled ${getSlave(animal || bodyguard).slaveName} to fight ${V.pit.slaveFightingAnimal ? `an animal` : `your bodyguard`} to the death this week.`);
+		options.addOption("Lethal fights", "lethal", V.pit)
+			.addValue("Forbidden", 0).addValue("Allowed", 1).addValue("Always", 2);
 
-			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.link(`Cancel it`, () => {
-				V.pit.slaveFightingAnimal = null;
-				V.pit.slaveFightingBodyguard = null;
+		options.addOption("Respect virginities", "virginities", V.pit)
+			.addValue("All", "all").addValue("Vaginal", "vaginal")
+			.addValue("Anal", "anal").addValue("None", "none");
 
-				App.UI.reload();
-			}), ['indent']);
-		}
+		App.UI.DOM.appendNewElement("div", el, options.render(), ['margin-bottom']);
 
 		return el;
 	}
 
+	function arenaUpgrades() {
+		const f = new DocumentFragment();
+		f.append((new App.Upgrade("seats", [
+			{
+				value: 0,
+				upgraded: 1,
+				text: "Around the pit is an small space to watch the fights from.",
+				link: "Add some proper stands.",
+				cost: 5000 * V.upgradeMultiplierArcology
+			},
+			{
+				value: 1,
+				upgraded: 2,
+				text: "Surrounding the pit are small stands to watch the fights from.",
+				link: "Replace the stands with big, permanent ones.",
+				cost: 20000 * V.upgradeMultiplierArcology
+			},
+			{
+				value: 2,
+				text: "The pit is encased by large stands offering a large space to watch the fights from.",
+			}
+		], V.pit)).render());
+		f.append((new App.Upgrade("fightsBase", [
+			{
+				value: 0,
+				upgraded: 1,
+				text: "Next to the pit is a small room for your slaves to store their equipment in.",
+				link: "Add a room for the slaves to wait in between fights.",
+				cost: 5000 * V.upgradeMultiplierArcology
+			},
+			{
+				value: 1,
+				upgraded: 2,
+				text: "Around the arena are some rooms for your slaves to wait and store their equipment in between fights",
+				link: "Improve the equipment and add spaces for the slaves to prepare for their fights.",
+				cost: 20000 * V.upgradeMultiplierArcology
+			},
+			{
+				value: 2,
+				text: "Around the pit are various facilities for your slaves to rest and prepare in between fights. High quality equipment is available in multiple store rooms",
+			}
+		], V.pit)).render());
+		return f;
+	}
+
 	function arenaSlaves() {
 		const el = document.createDocumentFragment();
 
diff --git a/src/facilities/pit/pitFightList.js b/src/facilities/pit/pitFightList.js
new file mode 100644
index 0000000000000000000000000000000000000000..32d2acb4e78576b3238a695c1aaaea1467500731
--- /dev/null
+++ b/src/facilities/pit/pitFightList.js
@@ -0,0 +1,27 @@
+/**
+ * Gives all pit fights
+ * @returns {Array<App.Facilities.Pit.Fights.BaseFight>}
+ */
+App.Facilities.Pit.getFights = function() {
+	return [
+		// new App.Facilities.Pit.Fights.TestFight(),
+		new App.Facilities.Pit.Fights.NlR1v1(),
+		new App.Facilities.Pit.Fights.NlBg1v1(),
+		new App.Facilities.Pit.Fights.LR1v1(),
+		new App.Facilities.Pit.Fights.LBg1v1(),
+		new App.Facilities.Pit.Fights.LSchBg1v1(),
+		new App.Facilities.Pit.Fights.LSch1v1(),
+		new App.Facilities.Pit.Fights.NlSch1v1(),
+	];
+};
+/**
+ * Gives all pit fights as a Mmap
+ * @returns {Map<string, App.Facilities.Pit.Fights.BaseFight>}
+ */
+App.Facilities.Pit.getFightsMap = function() {
+	const m = new Map();
+	for (const f of App.Facilities.Pit.getFights()) {
+		m.set(f.key, f);
+	}
+	return m;
+};
diff --git a/src/facilities/pit/pitUtils.js b/src/facilities/pit/pitUtils.js
index fc3fe4d9d4707abb2423c300a23a7921781ae0c7..b42689e232e204aa180958fb371b2a441044d719 100644
--- a/src/facilities/pit/pitUtils.js
+++ b/src/facilities/pit/pitUtils.js
@@ -6,17 +6,17 @@ App.Facilities.Pit.init = function() {
 		trainingIDs: [],
 
 		// Pit section
-		animal: null,
+		active:false,
 		audience: "free",
-		bodyguardFights: false,
 		decoration: "standard",
-		fighters: 0,
 		fighterIDs: [],
 		fought: false,
-		lethal: false,
-		slaveFightingAnimal: null,
+		fightsBase: 0,
+		seats: 0,
+		lethal: 0,
+		virginities: "all",
+		minimumHealth: true,
 		slaveFightingBodyguard: null,
-		slavesFighting: [],
-		virginities: "neither",
+		slavesFighting: null
 	};
 };
diff --git a/src/facilities/pit/pitWorkaround.js b/src/facilities/pit/pitWorkaround.js
index f50a29b5f2ade0979473dba1abfa4cc9e9af5445..f0a40dcb0a08232190beb1e9967bc8f2239dbecd 100644
--- a/src/facilities/pit/pitWorkaround.js
+++ b/src/facilities/pit/pitWorkaround.js
@@ -1,32 +1,51 @@
 App.Facilities.Pit.workaround = function() {
-	const frag = new DocumentFragment();
+	const f = new DocumentFragment();
 
-	const slaveOne = getSlave(V.pit.slavesFighting[0]);
-	const slaveTwo = getSlave(V.pit.slavesFighting[1]);
+	// Warning:
+	// In this passage the V.pit.slavesFighting array is constructed. This means that during this passage the length of
+	// the array cannot be assumed to be 2. Once leaving this passage it has to be ensured that V.pit.slavesFighting is
+	// in a valid state first.
+	if (V.pit.slavesFighting === null) {
+		// @ts-ignore
+		V.pit.slavesFighting = [];
+	}
+
+	V.passageSwitchHandler = passageHandler;
+
+	const slave1 = getSlave(V.pit.slavesFighting[0]);
+	const slave2 = getSlave(V.pit.slavesFighting[1]);
 
-	frag.append(
+	f.append(
 		App.UI.DOM.makeElement("h1", `Slaves Fighting`),
 		App.UI.DOM.makeElement("div", V.pit.slavesFighting.length > 1
-			? `${slaveOne.slaveName} is fighting ${slaveTwo.slaveName} this week.`
+			? `${slave1.slaveName} is fighting ${slave2.slaveName} this week.`
 			: `Choose two slaves to fight.`),
 		App.UI.DOM.makeElement("h2", `Choose slaves`, ['margin-top']),
 	);
 
-	for (const slave of V.pit.fighterIDs) {
-		if (V.pit.slavesFighting.includes(slave)) {
-			App.UI.DOM.appendNewElement("div", frag, SlaveFullName(getSlave(slave)), ['indent']);
+	for (const slave of V.slaves) {
+		if (V.pit.slavesFighting.includes(slave.ID)) {
+			App.UI.DOM.appendNewElement("div", f, SlaveFullName(slave), ['indent']);
 		} else {
-			App.UI.DOM.appendNewElement("div", frag, App.UI.DOM.link(SlaveFullName(getSlave(slave)), () => {
+			App.UI.DOM.appendNewElement("div", f, App.UI.DOM.link(SlaveFullName(slave), () => {
 				if (V.pit.slavesFighting.length > 1) {
 					V.pit.slavesFighting.shift();
 				}
 
-				V.pit.slavesFighting.push(slave);
+				V.pit.slavesFighting.push(slave.ID);
 
+				V.passageSwitchHandler = () => { };
 				App.UI.reload();
+				V.passageSwitchHandler = passageHandler;
 			}), ['indent']);
 		}
 	}
 
-	return frag;
+	function passageHandler() {
+		if (V.pit.slavesFighting.length !== 2) {
+			V.pit.slavesFighting = null;
+		}
+	}
+
+	return f;
 };
diff --git a/src/facilities/salon/salonPassage.js b/src/facilities/salon/salonPassage.js
index 0e73768577eea7e04a69458f8c8d7a5310db09b9..b9ca05d00c7fbfa9bb9608adc584afd45c4b6d48 100644
--- a/src/facilities/salon/salonPassage.js
+++ b/src/facilities/salon/salonPassage.js
@@ -517,7 +517,7 @@ App.UI.salon = function(slave, cheat = false, startingGirls = false) {
 				option.addValue("Match the hair", slave.hColor);
 			}
 			option.addValueList(makeAList(App.Medicine.Modification.Color.Primary.map(color => color.value)));
-			option.addCallbackToEach(billMod);
+			option.addGlobalCallback(billMod);
 			option.pulldown();
 
 			// Style
@@ -567,7 +567,7 @@ App.UI.salon = function(slave, cheat = false, startingGirls = false) {
 				option.addValue("Match the curtains", slave.hColor);
 			}
 			option.addValueList(makeAList(App.Medicine.Modification.Color.Primary.map(color => color.value)))
-				.addCallbackToEach(billMod)
+				.addGlobalCallback(billMod)
 				.pulldown();
 		}
 		if (hasPubes || cheat) {
@@ -606,7 +606,7 @@ App.UI.salon = function(slave, cheat = false, startingGirls = false) {
 				option.addValue("Match the hair", slave.hColor);
 			}
 			option.addValueList(makeAList(App.Medicine.Modification.Color.Primary.map(color => color.value)))
-				.addCallbackToEach(billMod)
+				.addGlobalCallback(billMod)
 				.pulldown();
 		}
 		if (hasPitHair || cheat) {
diff --git a/src/facilities/surgery/analyzePregnancy.js b/src/facilities/surgery/analyzePregnancy.js
index d8ca35ebedbe1f7a3ccf56111499bbd30ac3d809..5f25ca40354f5d78474c2a69712cb0d818013704 100644
--- a/src/facilities/surgery/analyzePregnancy.js
+++ b/src/facilities/surgery/analyzePregnancy.js
@@ -62,6 +62,10 @@ globalThis.analyzePregnancies = function(mother, cheat) {
 				if (cheat) {
 					option.showTextBox();
 				}
+				option = options.addOption(`Expected adult height: ${heightToEitherUnit(genes.adultHeight)}`, "adultHeight", genes);
+				if (cheat) {
+					option.showTextBox();
+				}
 				option = options.addOption(`Eye Color: ${capFirstChar(genes.eyeColor)}`, "eyeColor", genes);
 				if (cheat) {
 					option.showTextBox().pulldown();
diff --git a/src/facilities/surgery/geneticQuirks.js b/src/facilities/surgery/geneticQuirks.js
index 62966baa269fd62a8c24b15bbe8a2c8ea7533f0d..cbb3e25451eb6e1adb46138cbef5b8873d7c6b63 100644
--- a/src/facilities/surgery/geneticQuirks.js
+++ b/src/facilities/surgery/geneticQuirks.js
@@ -35,7 +35,7 @@ App.UI.SlaveInteract.geneticQuirks = function(slave, allInactive, filter) {
 				}
 			}
 			if (key === "albinism" && "albinismOverride" in slave) {
-				option.addCallbackToEach((val) => induceAlbinism(slave, val));
+				option.addGlobalCallback((val) => induceAlbinism(slave, val));
 			}
 		}
 	}
diff --git a/src/futureSocieties/fsDecoration.js b/src/futureSocieties/fsDecoration.js
index 323cb9744ebbb137af4ccefb6b911a211c5eeb68..e1d3df46d0d3160b664ea23c37a33bae719ed828 100644
--- a/src/futureSocieties/fsDecoration.js
+++ b/src/futureSocieties/fsDecoration.js
@@ -24,7 +24,7 @@ App.UI.facilityRedecoration = function() {
 			option.addValue("Distribute Evenly", "even");
 		}
 	}
-	option.addCallbackToEach(value => {
+	option.addGlobalCallback(value => {
 		console.log(value);
 		let totalCost = 0;
 		if (value === "even") { // Cycles through the list of available FS decorations, and distributes them to facilities round robin style.
@@ -56,7 +56,7 @@ App.UI.facilityRedecoration = function() {
 		options.addOption(`The decoration style of ${facility.name} is`, "decoration", facility)
 			.addValue("Standard", "standard")
 			.addValueList(decorationNames)
-			.addCallbackToEach(value => {
+			.addGlobalCallback(value => {
 				if (value !== "standard") {
 					cashX(-5000, "capEx");
 				}
diff --git a/src/futureSocieties/fsPassage.js b/src/futureSocieties/fsPassage.js
index 55e369a7fc57f524931961b5aa8e04a413020dbf..99771ff7badddfa9e05a4f4dc88cb5fc22e0343d 100644
--- a/src/futureSocieties/fsPassage.js
+++ b/src/futureSocieties/fsPassage.js
@@ -1103,7 +1103,7 @@ App.UI.fsPassage = function() {
 					}
 					if (FSCredits > 0) {
 						if (arc.FSNull < V.FSLockinLevel) {
-							r.push(advanceRel(25));
+							r.push("/", advanceRel(25));
 						}
 					}
 				} else {
@@ -1120,7 +1120,7 @@ App.UI.fsPassage = function() {
 					}
 					if (FSCredits > 0) {
 						if (arc.FSNull < V.FSLockinLevel) {
-							r.push(advanceRel(17));
+							r.push("/", advanceRel(17));
 						}
 					}
 				} else {
@@ -1137,7 +1137,7 @@ App.UI.fsPassage = function() {
 					}
 					if (FSCredits > 0) {
 						if (arc.FSNull < V.FSLockinLevel) {
-							r.push(advanceRel(15));
+							r.push("/", advanceRel(15));
 						}
 					}
 				} else {
@@ -1154,7 +1154,7 @@ App.UI.fsPassage = function() {
 					}
 					if (FSCredits > 0) {
 						if (arc.FSNull < V.FSLockinLevel) {
-							r.push(advanceRel(20));
+							r.push("/", advanceRel(20));
 						}
 					}
 				} else {
@@ -1190,36 +1190,25 @@ App.UI.fsPassage = function() {
 		}
 
 		function advanceRel(num) {
-			return App.UI.DOM.link(
-				"Advance",
-				() => {
-					if (arc.FSNull !== "unset") {
-						arc.FSNull += num;
-					}
-					App.UI.reload();
-				},
-				[],
-				"",
-				"a further commitment to allow your arcology's citizens cultural freedom"
-			);
+			const f = new DocumentFragment();
+			f.append(App.UI.DOM.link("Advance", () => {
+				if (arc.FSNull !== "unset") {
+					arc.FSNull += num;
+				}
+				App.UI.reload();
+			}));
+			App.UI.DOM.appendNewElement("span", f, " Further your commitment to allow your arcology's citizens cultural freedom.", ["note"]);
+			return f;
 		}
 
 		function MulticulturalismRel(num) {
-			const multicultural = App.UI.DOM.makeElement(
-				"span",
-				App.UI.DOM.link(
-					"Multiculturalism",
-					() => {
-						arc.FSNull = num;
-						App.UI.reload();
-					},
-					[],
-					"",
-					"a commitment to allow your arcology's citizens cultural freedom."
-				)
-			);
-			multicultural.append(` is an alternative to societal advancement, and will not advance naturally.`);
-			return multicultural;
+			const f = new DocumentFragment();
+			f.append(App.UI.DOM.link("Multiculturalism", () => {
+				arc.FSNull = num;
+				App.UI.reload();
+			}));
+			f.append(` is a commitment to allow your arcology's citizens cultural freedom. It is an alternative to societal advancement, and will not advance naturally.`);
+			return f;
 		}
 
 		/* Revival section */
diff --git a/src/gui/Encyclopedia/encyclopedia.js b/src/gui/Encyclopedia/encyclopedia.js
index f46c242bea316ddc81671d534d32c9f8ecb3128f..11b23a3c5765834f1f2a5d2d9be1ebb966fd54de 100644
--- a/src/gui/Encyclopedia/encyclopedia.js
+++ b/src/gui/Encyclopedia/encyclopedia.js
@@ -1,6 +1,5 @@
 App.Encyclopedia.ui = function() {
 	const f = document.createElement("div");
-	const topLinks = [];
 	if (V.encyclopedia !== "Table of Contents") {
 		App.UI.DOM.appendNewElement("div", f, App.Encyclopedia.link("Table of Contents"), ["center"]);
 	}
@@ -29,35 +28,35 @@ App.Encyclopedia.ui = function() {
 	return f;
 };
 
-	/** Create a link to an encyclopedia dialog for a given article with the given text
-	 * @param {string} text Text for link
-	 * @param {string} [article] Encyclopedia article to link to (if not supplied than text is capitalized.)
-	 * @param {string} [classNames] CSS Class to add to the link
-	 * @returns {HTMLElement} DOM link element
-	 */
-	App.Encyclopedia.link = function(text, article = capFirstChar(text), classNames) {
-		const link = App.UI.DOM.link(text, () => showArticleInDialog(article));
-		if (!classNames) {
-			return link;
-		}
-		// Wrap in a span for coloring, more reliable when hovering over the link
-		const span = document.createElement("span");
-		span.className += classNames;
-		span.append(link);
-		return span;
+/** Create a link to an encyclopedia dialog for a given article with the given text
+ * @param {string} text Text for link
+ * @param {string} [article] Encyclopedia article to link to (if not supplied than text is capitalized.)
+ * @param {string} [classNames] CSS Class to add to the link
+ * @returns {HTMLElement} DOM link element
+ */
+App.Encyclopedia.link = function(text, article = capFirstChar(text), classNames) {
+	const link = App.UI.DOM.link(text, () => showArticleInDialog(article));
+	if (!classNames) {
+		return link;
+	}
+	// Wrap in a span for coloring, more reliable when hovering over the link
+	const span = document.createElement("span");
+	span.className += classNames;
+	span.append(link);
+	return span;
 
 	/** Show a given encyclopedia article in the encyclopedia dialog
 	 * @param {string} article
 	 */
-		function showArticleInDialog(article) {
-			const origEncyclopedia = V.encyclopedia;
-			if (Dialog.isOpen()) {
-				Dialog.close();
-			}
-			Dialog.setup("Encyclopedia", "encyclopedia");
-			V.encyclopedia = article;
-			Dialog.append(App.Encyclopedia.ui());
-			Dialog.open();
-			V.encyclopedia = origEncyclopedia;
+	function showArticleInDialog(article) {
+		const origEncyclopedia = V.encyclopedia;
+		if (Dialog.isOpen()) {
+			Dialog.close();
 		}
-	};
+		Dialog.setup("Encyclopedia", "encyclopedia");
+		V.encyclopedia = article;
+		Dialog.append(App.Encyclopedia.ui());
+		Dialog.open();
+		V.encyclopedia = origEncyclopedia;
+	}
+};
diff --git a/src/gui/Encyclopedia/encyclopediaFacilites.js b/src/gui/Encyclopedia/encyclopediaFacilites.js
index 73d51f16dcdaa80ae59813c1a0e78d352e542bef..88d750202a7fd7a97cc64f8b35cda075ae8fb881 100644
--- a/src/gui/Encyclopedia/encyclopediaFacilites.js
+++ b/src/gui/Encyclopedia/encyclopediaFacilites.js
@@ -169,7 +169,8 @@ App.Encyclopedia.addArticle("Nursery", function() {
 	return f;
 }, "facilities");
 
-App.Encyclopedia.addArticle("Farmyard", function() {// TODO: this will need more information
+App.Encyclopedia.addArticle("Farmyard", function() {
+	// TODO: this will need more information
 	const f = new DocumentFragment();
 	const r = new SpacedTextAccumulator(f);
 	r.push("The", App.UI.DOM.makeElement("span", "Farmyard", ["bold"]), "is where the majority of the", App.Encyclopedia.link("food"), `in your arcology is grown, once it is built. It also allows you to house animals${V.seeBestiality === 1 ? ', which you can have interact with your slaves' : ''}. The Farmyard can be furnished according to`, App.Encyclopedia.link("future society", "Future Societies"), "styles, and doing so can add a slight", App.Encyclopedia.link("devotion", "From Rebellious to Devoted", "hotpink"), "boost to slaves working there."); // TODO: this may need to be changed
@@ -239,7 +240,6 @@ App.Encyclopedia.addCategory("facilities", function() {
 
 function noteFacilityName(...text) {
 	const f = new DocumentFragment();
-	const r = new SpacedTextAccumulator(f);
 	App.Events.addNode(f, text, "span", ["note"]);
 	return f;
 }
diff --git a/src/gui/Encyclopedia/encyclopediaFutureSocities.js b/src/gui/Encyclopedia/encyclopediaFutureSocities.js
index 16b2fadd28e28b80781c7d9cccba8e10606fd177..89403a02407c93e16f1333240146af2b49f90451 100644
--- a/src/gui/Encyclopedia/encyclopediaFutureSocities.js
+++ b/src/gui/Encyclopedia/encyclopediaFutureSocities.js
@@ -1,451 +1,500 @@
 App.Encyclopedia.addArticle("Future Societies", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		"The evolution of society has never been linear.",
+	App.Events.addNode(t, ["The evolution of society has never been linear.",
 		"Times of unrest and upheaval produce rapid change, followed by long periods of stasis in the absence of the necessary ingredients for further change.",
-		"The world is undoubtedly in the midst of a time of great change: society is certainly evolving. But into what?"
-	], "div", ["note"]);
+		"The world is undoubtedly in the midst of a time of great change: society is certainly evolving. But into what?"], "div", ["note"]);
 
-	App.Events.addNode(t, [
-		"Not since antiquity have single persons held as much practical power over the direction of society as Free Cities arcology owners now have.",
+	App.Events.addNode(t, ["Not since antiquity have single persons held as much practical power over the direction of society as Free Cities arcology owners now have.",
 		"Naturally, different Free Cities notables are going different ways with their great power.",
-		"Many are building new societies as different from each other as they are from the old world."
-], "div", ["note"]);
+		"Many are building new societies as different from each other as they are from the old world."], "div", ["note"]);
 
-App.Events.addNode(t, [
-	"One arcology might hold a society that is moving towards a fundamentalist interpretation of an old slaveholding religious tradition.",
-	"Another might pay homage to historical racially segregated societies.",
-	"A third might see intentional manipulation of gender roles that have held since the start of recorded history.",
-	"And these three arcologies might well be each other's neighbors."
-], "div", ["note"]);
+	App.Events.addNode(t, ["One arcology might hold a society that is moving towards a fundamentalist interpretation of an old slaveholding religious tradition.",
+		"Another might pay homage to historical racially segregated societies.",
+		"A third might see intentional manipulation of gender roles that have held since the start of recorded history.",
+		"And these three arcologies might well be each other's neighbors."], "div", ["note"]);
 
 	App.Encyclopedia.addArticleSource(t, "Guide to Modern Slavery, Online Edition. Accessed April 2, 2032", "Lawrence, W. G.");
 
 	App.Events.addNode(t, [
 		App.UI.DOM.makeElement("span", "Future Society Models", ["bold"]), `are societal goals the player can select and pursue for the arcology.",
 		"It is possible to maintain four future society goals at once.",
-		"The first is unlocked after week 5 for players with greater than rumored/${num(3000)}`, App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "or at game start with the Social Engineering character option; the rest unlock as the player achieves higher", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "levels."
-	], "p");
+		"The first is unlocked after week 5 for players with greater than rumored/${num(3000)}`,
+		App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"),
+		"or at game start with the Social Engineering character option; the rest unlock as the player achieves higher",
+		App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "levels."], "p");
 
-	App.Events.addNode(t, [
-		"All societies approve of specific things, usually slaves with specific characteristics; some societies also have dislikes.",
-		"All societies are advanced by the things they approve of and slowed by the things they disapprove of, and all societies give and take", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "when approving and disapproving.",
-		"All societies unlock unique events, arcology upgrades, and slave behaviors; some even unlock special clothing."
-], "p");
+	App.Events.addNode(t, ["All societies approve of specific things, usually slaves with specific characteristics; some societies also have dislikes.",
+		"All societies are advanced by the things they approve of and slowed by the things they disapprove of, and all societies give and take",
+		App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "when approving and disapproving.",
+		"All societies unlock unique events, arcology upgrades, and slave behaviors; some even unlock special clothing."], "p");
 
-App.Events.addNode(t, [
-	App.Encyclopedia.link("Money", "Money", "yellowgreen"), "can be expended to directly advance future societies; the spending level can be set from the future society submenu of the arcology management menu.",
-	"These funds are automatically spent each week.",
-	"Once a future society is fully adopted (as noted on the future society submenu), this spending does not advance the society further.",
-	"However, it can provide a guarantee against loss of progress should the player do something the society strongly disapproves of.",
-	"Also, the spending is applied equally to all active future society models, meaning that there is no loss of efficiency in spending if the player has two maximized models and one still under development."
-], "p");
+	App.Events.addNode(t, [App.Encyclopedia.link("Money", "Money", "yellowgreen"),
+		"can be expended to directly advance future societies; the spending level can be set from the future society submenu of the arcology management menu.",
+		"These funds are automatically spent each week.",
+		"Once a future society is fully adopted (as noted on the future society submenu), this spending does not advance the society further.",
+		"However, it can provide a guarantee against loss of progress should the player do something the society strongly disapproves of.",
+		"Also, the spending is applied equally to all active future society models, meaning that there is no loss of efficiency in spending if the player has two maximized models and one still under development."], "p");
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Ethnic Supremacy", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Ethnic Supremacy", ["bold"]), "is a future society model which approves of",
-		"slaves not of the chosen race and disapproves of slaves of the chosen race."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Ethnic Supremacy", ["bold"]),
+		"is a future society model which approves of",
+		"slaves not of the chosen race and disapproves of slaves of the chosen race."], "div");
 	App.Events.addNode(t, ["Improves the perceived beauty of racially superior slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Drastically lowers the desire of racially superior slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to affect the ethnic balance and economics seen in the slave market."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for slaves of inferior races from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for slaves of inferior races from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Ethnic Subjugationism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Ethnic Subjugationism", ["bold"]), "is a future society model which approves of slaves of the chosen race."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Ethnic Subjugationism", ["bold"]),
+		"is a future society model which approves of slaves of the chosen race."], "div");
 	App.Events.addNode(t, ["Reduces the perceived beauty of racially inferior slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Drastically increases the desire to use racially inferior slaves."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for slaves of the disfavored race from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for slaves of the disfavored race from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Gender Radicalism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Gender Radicalism", ["bold"]), "is a future society model which approves of",
-		"hormonal and surgical feminization and slaves with dicks."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Gender Radicalism", ["bold"]),
+		"is a future society model which approves of",
+		"hormonal and surgical feminization and slaves with dicks."], "div");
 	App.Events.addNode(t, ["Improves the value of slaves with dicks and slaves with balls."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to affect the biology seen in the slave market, and subtly influence arcology society."], "div", ["indent"]);
-	App.Events.addNode(t, [`Provides demand for; slaves with dicks, hormonally treated slaves and futanari${V.seeDicks !== 0 ? ' and ballsless bitches' : ''} from`, App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Gender Fundamentalism"), ".")]);
+	App.Events.addNode(t, [`Provides demand for; slaves with dicks, hormonally treated slaves and futanari${V.seeDicks !== 0 ? ' and ballsless bitches' : ''} from`,
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Gender Fundamentalism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Gender Fundamentalism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Gender Fundamentalism", ["bold"]), "is a future society model which approves of",
-		"pregnancy and fertility and disapproves of slaves who retain testicles."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Gender Fundamentalism", ["bold"]),
+		"is a future society model which approves of",
+		"pregnancy and fertility and disapproves of slaves who retain testicles."], "div");
 	App.Events.addNode(t, ["Reduces the slave value penalty due to pregnancy and reduces the beauty of slaves with dicks, though gelding can ameliorate this."], "div", ["indent"]);
 	App.Events.addNode(t, ["Like Gender Radicalism, can be developed to affect the biology seen in the slave market, and subtly influence arcology society."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for naturally female slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Gender Radicalism"), ".")]);
+	App.Events.addNode(t, ["Provides demand for naturally female slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Gender Radicalism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Paternalism", function() {
 	const t = new DocumentFragment();
-	const r = new SpacedTextAccumulator(t);
-	const devotion = (text = "devotion", colour="hotpink") => App.Encyclopedia.link(text, "From Rebellious to Devoted", colour);
-	const PaternalismApproval = [devotion(), "slaves choosing their own assignments", "good education", "mental health treatment", App.Encyclopedia.link("high health", "Health")];
-
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Paternalism", ["bold"]), "is a future society model which approves of",
-		App.UI.DOM.toSentence(PaternalismApproval), "while stupidity and undereducation is disapproved."
-	], "div");
-	App.Events.addNode(t, ["Applies a small", devotion(), "boost to all slaves and increases fines paid by citizens who injure whores and public servants."], "div", ["indent"]);
-	App.Events.addNode(t, ["Increases the", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "penalty for operating an arcade."], "div", ["indent"]);
+	const devotion = (text = "devotion", colour = "hotpink") => App.Encyclopedia.link(text, "From Rebellious to Devoted", colour);
+	const PaternalismApproval = [devotion(), "slaves choosing their own assignments", "good education",
+		"mental health treatment", App.Encyclopedia.link("high health", "Health")];
+
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Paternalism", ["bold"]),
+		"is a future society model which approves of", App.UI.DOM.toSentence(PaternalismApproval),
+		"while stupidity and undereducation is disapproved."], "div");
+	App.Events.addNode(t, ["Applies a small", devotion(),
+		"boost to all slaves and increases fines paid by citizens who injure whores and public servants."], "div", ["indent"]);
+	App.Events.addNode(t, ["Increases the", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"),
+		"penalty for operating an arcade."], "div", ["indent"]);
 	App.Events.addNode(t, ["Slows increases in the ratio of slaves to citizens."], "div", ["indent"]);
-	App.Events.addNode(t, ["Can be developed to build a", App.Encyclopedia.link("trusting", "Trust", "mediumaquamarine"), "society that welcomes new slaves."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for careful slave breaking and gentle cosmetic surgeries from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Degradationism"), ".")]);
+	App.Events.addNode(t, ["Can be developed to build a",
+		App.Encyclopedia.link("trusting", "Trust", "mediumaquamarine"),
+		"society that welcomes new slaves."], "div", ["indent"]);
+	App.Events.addNode(t, ["Provides demand for careful slave breaking and gentle cosmetic surgeries from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Degradationism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Degradationism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Degradationism", ["bold"]), "is a future society model which approves of",
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Degradationism", ["bold"]),
+		"is a future society model which approves of",
 		"frightened or mindbroken slaves, glory holes, the arcade, and heavy tattoos and piercings;",
-		"it disapproves of", App.Encyclopedia.link("trusting", "Trust", "mediumaquamarine"), "(except for the Head Girl and Recruiter) and slaves choosing their own assignments."
-	], "div");
+		"it disapproves of", App.Encyclopedia.link("trusting", "Trust", "mediumaquamarine"),
+		"(except for the Head Girl and Recruiter) and slaves choosing their own assignments."], "div");
 	App.Events.addNode(t, ["Makes intelligent slaves less attractive and stupid slaves more attractive."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can apply unique names to slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Drives an increase in the ratio of slaves to citizens."], "div", ["indent"]);
-	App.Events.addNode(t, ["Eliminates the", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "penalty for operating an arcade along with fining citizens who injure whores and public servants."], "div", ["indent"]);
+	App.Events.addNode(t, ["Eliminates the", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"),
+		"penalty for operating an arcade along with fining citizens who injure whores and public servants."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to increase demand for glory holes and arcades."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for: brutal slave breaking, stupid slaves and cruelly altered slaves from the", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Paternalism"), ".")]);
+	App.Events.addNode(t, ["Provides demand for: brutal slave breaking, stupid slaves and cruelly altered slaves from the",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Paternalism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Body Purism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Body Purism", ["bold"]), "is a future society model which approves of",
-		"unimplanted slaves and no heavy tattoos or piercings; disapproves of implants."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Body Purism", ["bold"]),
+		"is a future society model which approves of",
+		"unimplanted slaves and no heavy tattoos or piercings; disapproves of implants."], "div");
 	App.Events.addNode(t, ["Improves value of slaves without implants."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to affect goods seen in the slave market and work towards a solution to the long term effects of drug use."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for slaves without implants from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Transformation Fetishism"), ".")]);
+	App.Events.addNode(t, ["Provides demand for slaves without implants from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Transformation Fetishism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Transformation Fetishism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Transformation Fetishism", ["bold"]), "is a future society model which approves of",
-		"implants and extreme surgery; disapproves of slaves without implants."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Transformation Fetishism", ["bold"]),
+		"is a future society model which approves of",
+		"implants and extreme surgery; disapproves of slaves without implants."], "div");
 	App.Events.addNode(t, ["Reduces value of slaves without implants."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to radically affect goods seen in the slave market."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for slaves with implants from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Body Purism"), ".")]);
+	App.Events.addNode(t, ["Provides demand for slaves with implants from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Body Purism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Maturity Preferentialism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Maturity Preferentialism", ["bold"]), "is a future society model which approves of older slaves."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Maturity Preferentialism", ["bold"]),
+		"is a future society model which approves of older slaves."], "div");
 	App.Events.addNode(t, ["Improves value of older slaves, but reduces value of young slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Will not entirely eliminate the usual preference for younger slaves."], "div", ["indent"]);
-	App.Events.addNode(t, ["Can be developed to make it easier for older player characters to maintain", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "and advance the arcology's prosperity."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for older slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Youth Preferentialism"), ".")]);
+	App.Events.addNode(t, ["Can be developed to make it easier for older player characters to maintain",
+		App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"),
+		"and advance the arcology's prosperity."], "div", ["indent"]);
+	App.Events.addNode(t, ["Provides demand for older slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Youth Preferentialism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Youth Preferentialism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Youth Preferentialism", ["bold"]), "is a future society model which approves of younger slaves."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Youth Preferentialism", ["bold"]),
+		"is a future society model which approves of younger slaves."], "div");
 	App.Events.addNode(t, ["Improves value of younger slaves, but reduces value of old slaves."], "div", ["indent"]);
-	App.Events.addNode(t, ["Can be developed to make it easier for younger player characters to maintain", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "and advance the arcology's prosperity."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for young slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Maturity Preferentialism"), ".")]);
+	App.Events.addNode(t, ["Can be developed to make it easier for younger player characters to maintain",
+		App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"),
+		"and advance the arcology's prosperity."], "div", ["indent"]);
+	App.Events.addNode(t, ["Provides demand for young slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Maturity Preferentialism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Slimness Enthusiasm", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Slimness Enthusiasm", ["bold"]), "is a future society model which approves of",
-		"slaves with girlish figures; disapproves of slaves with stacked figures."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Slimness Enthusiasm", ["bold"]),
+		"is a future society model which approves of",
+		"slaves with girlish figures; disapproves of slaves with stacked figures."], "div");
 	App.Events.addNode(t, ["Improves value of slim slaves, but reduces value of stacked slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to affect goods seen in the slave market and improve slave health."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for unexpanded slaves at a healthy weight from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Asset Expansionism"), ".")]);
+	App.Events.addNode(t, ["Provides demand for unexpanded slaves at a healthy weight from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Asset Expansionism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Asset Expansionism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Asset Expansionism", ["bold"]), "is a future society model which approves of slaves with very large body parts."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Asset Expansionism", ["bold"]),
+		"is a future society model which approves of slaves with very large body parts."], "div");
 	App.Events.addNode(t, ["Improves value of stacked slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to radically affect goods seen in the slave market."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for asset expansion from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Slimness Enthusiasm"), ".")]);
+	App.Events.addNode(t, ["Provides demand for asset expansion from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Slimness Enthusiasm"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Pastoralism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Pastoralism", ["bold"]), "is a future society model which approves of lactation, cockmilking, and the dairy."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Pastoralism", ["bold"]),
+		"is a future society model which approves of lactation, cockmilking, and the dairy."], "div");
 	App.Events.addNode(t, ["Improves value of milk and semen."], "div", ["indent"]);
 	App.Events.addNode(t, ["Drives an increase in the ratio of slaves to citizens."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to massively improve value of milk and semen."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for production focused asset expansion from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for production focused asset expansion from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Physical Idealism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Physical Idealism", ["bold"]), "is a future society model which approves of musculature, height, and health."
-	], "div");
-	App.Events.addNode(t, ["Improves value of slaves with", App.UI.DOM.combineNodes(App.Encyclopedia.link("muscles", "Musculature"), ".")]);
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Physical Idealism", ["bold"]),
+		"is a future society model which approves of musculature, height, and health."], "div");
+	App.Events.addNode(t, ["Improves value of slaves with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("muscles", "Musculature"), ".")]);
 	App.Events.addNode(t, ["Can be developed to affect goods seen in the slave market."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for muscular slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Hedonistic Decadence"), ".")]);
+	App.Events.addNode(t, ["Provides demand for muscular slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Hedonistic Decadence"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Chattel Religionism", function() {
 	const t = new DocumentFragment();
 	const devotion = (text = "devotion") => App.Encyclopedia.link(text, "From Rebellious to Devoted", "hotpink");
-	const chattelReligionism = ["appropriate clothing", devotion("high devotion"), App.Encyclopedia.link("slave marriages", "Slave marriages")];
-
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Chattel Religionism", ["bold"]), "is a future society model which approves of",
-		App.UI.DOM.toSentence(chattelReligionism), "while disapproving of slutty clothing."
-	], "div");
-	App.Events.addNode(t, ["Applies a small", devotion(), "boost to all slaves, and can remove the weekly", devotion(), "gain cap."], "div", ["indent"]);
+	const chattelReligionism = ["appropriate clothing", devotion("high devotion"),
+		App.Encyclopedia.link("slave marriages", "Slave marriages")];
+
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Chattel Religionism", ["bold"]),
+		"is a future society model which approves of", App.UI.DOM.toSentence(chattelReligionism),
+		"while disapproving of slutty clothing."], "div");
+	App.Events.addNode(t, ["Applies a small", devotion(), "boost to all slaves, and can remove the weekly", devotion(),
+		"gain cap."], "div", ["indent"]);
 	App.Events.addNode(t, ["Drives an increase in the ratio of slaves to citizens."], "div", ["indent"]);
-	App.Events.addNode(t, ["Can be developed to permanently boost", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "and quicken slaves' mental conditioning."], "div", ["indent"]);
+	App.Events.addNode(t, ["Can be developed to permanently boost",
+		App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"),
+		"and quicken slaves' mental conditioning."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to prefer nudity over conservative clothing."]);
-	App.Events.addNode(t, ["Provides demand for sexual training from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Multiculturalism"), ".")]);
+	App.Events.addNode(t, ["Provides demand for sexual training from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Multiculturalism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Multiculturalism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Multiculturalism", ["bold"]), "is a future society model which approves of",
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Multiculturalism", ["bold"]),
+		"is a future society model which approves of",
 		"is a future society model which advances differently than other models: it is improved by the investment of more future society model slots, which can be withdrawn individually if desired.",
-		"No other advancement occurs and all benefits at each level are available instantly."
-	], "div");
-	App.Events.addNode(t, ["Each week provides free", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "and increases arcology prosperity."], "div", ["indent"]);
+		"No other advancement occurs and all benefits at each level are available instantly."], "div");
+	App.Events.addNode(t, ["Each week provides free",
+		App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"),
+		"and increases arcology prosperity."], "div", ["indent"]);
 	App.Events.addNode(t, ["Helps prevent citizens from falling into slavery, slowing population drift towards slaves."], "div", ["indent"]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Chattel Religionism"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Chattel Religionism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Roman Revivalism", function() {
 	const t = new DocumentFragment();
-	const r = new SpacedTextAccumulator(t);
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Roman Revivalism", ["bold"]), "is a future society model which approves of",
-		"good leadership qualities like wealth and strong defense; disapproves of debt."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Roman Revivalism", ["bold"]),
+		"is a future society model which approves of",
+		"good leadership qualities like wealth and strong defense; disapproves of debt."], "div");
 	App.Events.addNode(t, ["Improves rate of prosperity gain and at high levels will drive down all slave prices."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can apply unique names to slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Slows increases in the ratio of slaves to citizens."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to greatly improve the arcology's resistance to insurrection."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for basic educations from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for basic educations from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	App.Events.addNode(t, ["Mutually exclusive with the other Revivalist models."], "div", ["indent"]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Egyptian Revivalism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Egyptian Revivalism", ["bold"]), "is a future society model which approves of",
-		"keeping a large harem, slave incest, and having a wide racial variety of public slaves."
-	], "div");
-	App.Events.addNode(t, ["Improves value of slaves in incestuous relationships and efficiency of fucktoys in improving", App.Encyclopedia.link("reputation.", "Arcologies and Reputation", "green")]);
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Egyptian Revivalism", ["bold"]),
+		"is a future society model which approves of",
+		"keeping a large harem, slave incest, and having a wide racial variety of public slaves."], "div");
+	App.Events.addNode(t, ["Improves value of slaves in incestuous relationships and efficiency of fucktoys in improving",
+		App.Encyclopedia.link("reputation.", "Arcologies and Reputation", "green")]);
 	App.Events.addNode(t, ["Can apply unique names to slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Slows increases in the ratio of slaves to citizens."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to improve the Head Girl position, with an additional bonus for Head Girls married to the Concubine, and a massive bonus if the Head Girl is also related to the Concubine."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for exotic accents from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for exotic accents from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	App.Events.addNode(t, ["Mutually exclusive with the other Revivalist models."], "div", ["indent"]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Edo Revivalism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Edo Revivalism", ["bold"]), "is a future society model which approves of",
-		"provision for the arcology's cultural development by providing a large number of public servants or club girls, which increases with", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "and disapproves of failure to do so."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Edo Revivalism", ["bold"]),
+		"is a future society model which approves of",
+		"provision for the arcology's cultural development by providing a large number of public servants or club girls, which increases with",
+		App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"),
+		"and disapproves of failure to do so."], "div");
 	App.Events.addNode(t, ["Improves efficiency of public servants and club girls."], "div", ["indent"]);
 	App.Events.addNode(t, ["Greatly improves beauty of Japanese slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to greatly improve the efficiency of direct spending on future societies."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for unaccented slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for unaccented slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	App.Events.addNode(t, ["Mutually exclusive with the other Revivalist models."], "div", ["indent"]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Arabian Revivalism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Arabian Revivalism", ["bold"]), "is a future society model which approves of",
-		"keeping a large number of fucktoys and slaves in the master suite, which increases with", App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"), "and disapproves of failure to do so."
-], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Arabian Revivalism", ["bold"]),
+		"is a future society model which approves of",
+		"keeping a large number of fucktoys and slaves in the master suite, which increases with",
+		App.Encyclopedia.link("reputation", "Arcologies and Reputation", "green"),
+		"and disapproves of failure to do so."], "div");
 	App.Events.addNode(t, ["Grants a bonus to the price received when selling slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to improve the efficiency of direct spending on future societies and moderately increase rents."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for more", App.Encyclopedia.link("devoted", "From Rebellious to Devoted", "hotpink"), "slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for more",
+		App.Encyclopedia.link("devoted", "From Rebellious to Devoted", "hotpink"), "slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	App.Events.addNode(t, ["Mutually exclusive with the other Revivalist models."], "div", ["indent"]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Chinese Revivalism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Chinese Revivalism", ["bold"]), "is a future society model which approves of",
-		"maintaining a solid imperial administration by keeping a Head Girl, a Recruiter, and a Bodyguard; disapproves of failure to do so."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Chinese Revivalism", ["bold"]),
+		"is a future society model which approves of",
+		"maintaining a solid imperial administration by keeping a Head Girl, a Recruiter, and a Bodyguard; disapproves of failure to do so."], "div");
 	App.Events.addNode(t, ["Increases prosperity growth when all three of these positions are staffed."], "div", ["indent"]);
 	App.Events.addNode(t, ["Greatly improves beauty of Chinese slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to permit the Head Girl to see to an additional slave each week."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for", App.UI.DOM.makeElement("span", "intelligence", ["cyan"]), "from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for", App.UI.DOM.makeElement("span", "intelligence", ["cyan"]), "from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	App.Events.addNode(t, ["Mutually exclusive with the other Revivalist models."], "div", ["indent"]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Repopulationism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Repopulation Focus", ["bold"]), "is a future society model. It:"], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Repopulation Focus", ["bold"]),
+		"is a future society model. It:"], "div");
 	App.Events.addNode(t, ["Approves of pregnant slaves and slaves that have given birth."], "div", ["indent"]);
 	App.Events.addNode(t, ["Improves value and beauty of pregnant slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to radically affect goods seen in the slave market."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for lactating slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for lactating slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	App.Events.addNode(t, ["Provides demand for young slaves from the corporation."], "div", ["indent"]);
-	App.Events.addNode(t, ["Is mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Eugenics", "Eugenics Focus"), ".")]);
-	App.Events.addNode(t, [
-		"Repopulationism is a difficult Future Society and not recommended for beginners.",
-		"Try to keep as many slaves as possible visibly pregnant; if they're pregnant but not showing yet, Pregnancy Biometrics Collars can help."
-	], "p", ["note", "yellow"]);
+	App.Events.addNode(t, ["Is mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Eugenics", "Eugenics Focus"), ".")]);
+	App.Events.addNode(t, ["Repopulationism is a difficult Future Society and not recommended for beginners.",
+		"Try to keep as many slaves as possible visibly pregnant; if they're pregnant but not showing yet, Pregnancy Biometrics Collars can help."], "p", ["note",
+		"yellow"]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Eugenics Focus", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Eugenics", ["bold"]), "is a future society model. It:"], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Eugenics", ["bold"]),
+		"is a future society model. It:"], "div");
 	App.Events.addNode(t, ["Disapproves of slave reproduction."], "div", ["indent"]);
 	App.Events.addNode(t, ["Drastically reduces value and beauty of pregnant slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Opens benefits exclusive to the connections made by the powerful individuals attracted to the arcology."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for; gelded, skilled and smart slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Is mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Repopulation Focus", "Repopulationism"), ".")]);
+	App.Events.addNode(t, ["Provides demand for; gelded, skilled and smart slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Is mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Repopulation Focus", "Repopulationism"), ".")]);
 	App.Events.addNode(t, ["It is made up of four to five social classes: Slaves, low class citizens, chosen slaves, elite citizens, and the Societal Elite: a group of individuals with vast connections and wealth attracted by the promises of a society built around them. Low class citizens are encouraged to face testing and join the ranks of the elite, though the cost of failing the test is sterilization; a detail that is not revealed until after the test is complete."], "div", ["indent"]);
-	App.Events.addNode(t, [
-			"Eugenics is a difficult Future Society and not recommended for beginners.",
-			"For a more complete guide to playing with a Eugenics arcology, see the", App.UI.DOM.combineNodes(App.Encyclopedia.link("Guide to Eugenics"), ".")
-	], "p", ["note", "yellow"]);
+	App.Events.addNode(t, ["Eugenics is a difficult Future Society and not recommended for beginners.",
+		"For a more complete guide to playing with a Eugenics arcology, see the",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Guide to Eugenics"), ".")], "p", ["note", "yellow"]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Slave Professionalism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Slave Professionalism", ["bold"]), "is a future society model. It:"], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Slave Professionalism", ["bold"]),
+		"is a future society model. It:"], "div");
 	App.Events.addNode(t, ["Approves of intelligent, well-trained slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Improves value and beauty of smart slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Dislikes slaves ruled by their libido."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to radically affect goods seen in the slave market"], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for; smart, educated and trained", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Is mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Intellectual Dependency"), ".")]);
+	App.Events.addNode(t, ["Provides demand for; smart, educated and trained",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Is mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Intellectual Dependency"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Intellectual Dependency", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Intellectual Dependency", ["bold"]), "is a future society model. It:"], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Intellectual Dependency", ["bold"]),
+		"is a future society model. It:"], "div");
 	App.Events.addNode(t, ["Approves of horny, vapid slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Improves value and beauty of moronic slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to adore bimbo bodies or radically affect goods seen in the slave market."], "div", ["indent"]);
-	App.Events.addNode(t, ["Allows for", App.Encyclopedia.link("the Schoolroom", "Schoolroom"), "to be radically redesigned."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for; idiotic, young and uneducated slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Is mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Slave Professionalism"), ".")]);
+	App.Events.addNode(t, ["Allows for", App.Encyclopedia.link("the Schoolroom", "Schoolroom"),
+		"to be radically redesigned."], "div", ["indent"]);
+	App.Events.addNode(t, ["Provides demand for; idiotic, young and uneducated slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Is mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Slave Professionalism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Petite Admiration", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Petite Admiration", ["bold"]), "is a future society model. It:"], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Petite Admiration", ["bold"]),
+		"is a future society model. It:"], "div");
 	App.Events.addNode(t, [`Approves of slaves shorter than ${lengthToEitherUnit(160)}.`]);
 	App.Events.addNode(t, ["Improves value and beauty of sufficiently short slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to accept relative shortness or radically affect goods seen in the slave market."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for shorter slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Is mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Statuesque Glorification"), ".")]);
+	App.Events.addNode(t, ["Provides demand for shorter slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Is mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Statuesque Glorification"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Statuesque Glorification", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Statuesque Glorification", ["bold"]), "is a future society model. It:"], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Statuesque Glorification", ["bold"]),
+		"is a future society model. It:"], "div");
 	App.Events.addNode(t, [`Approves of slaves taller than ${lengthToEitherUnit(170)}.`]);
 	App.Events.addNode(t, ["Improves value and beauty of sufficiently tall slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to accept relative tallness or radically affect goods seen in the slave market."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for taller slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Is mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Petite Admiration"), ".")]);
+	App.Events.addNode(t, ["Provides demand for taller slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Is mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Petite Admiration"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Hedonistic Decadence", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Hedonistic Decadence", ["bold"]), "is a future society model. It:"], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Hedonistic Decadence", ["bold"]),
+		"is a future society model. It:"], "div");
 	App.Events.addNode(t, ["Approves of overindulgence and luxury."], "div", ["indent"]);
 	App.Events.addNode(t, ["Improves value and beauty of heavyset slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to radically affect goods seen in the slave market."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for pampered and skilled slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
-	App.Events.addNode(t, ["Mutually exclusive with", App.UI.DOM.combineNodes(App.Encyclopedia.link("Physical Idealism"), ".")]);
+	App.Events.addNode(t, ["Provides demand for pampered and skilled slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Mutually exclusive with",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("Physical Idealism"), ".")]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Aztec Revivalism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Aztec Revivalism", ["bold"]), "is a future society model which approves of",
-		"qualities like good military education and an older leader."
-	], "div");
-	App.Events.addNode(t, ["Improves all military acquisitions of slaves and allows for the sacrifice of slaves for", App.Encyclopedia.link("reputation.", "Arcologies and Reputation", "green")]);
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Aztec Revivalism", ["bold"]),
+		"is a future society model which approves of",
+		"qualities like good military education and an older leader."], "div");
+	App.Events.addNode(t, ["Improves all military acquisitions of slaves and allows for the sacrifice of slaves for",
+		App.Encyclopedia.link("reputation.", "Arcologies and Reputation", "green")]);
 	App.Events.addNode(t, ["Can apply unique names to slaves."], "div", ["indent"]);
 	App.Events.addNode(t, ["Slows increases in the ratio of slaves to citizens."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to greatly rely on the Head Girl position as an advisor and assistant."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for menial slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for menial slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	App.Events.addNode(t, ["Mutually exclusive with the other Revivalist models."], "div", ["indent"]);
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Neo-Imperialism", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		App.UI.DOM.makeElement("span", "Neo-Imperialism", ["bold"]), "is a future society model which approves of",
-		"high wealth, prosperity, and personal combat skills and disapproves of weakness and poverty in leaders."
-	], "div");
+	App.Events.addNode(t, [App.UI.DOM.makeElement("span", "Neo-Imperialism", ["bold"]),
+		"is a future society model which approves of",
+		"high wealth, prosperity, and personal combat skills and disapproves of weakness and poverty in leaders."], "div");
 	App.Events.addNode(t, ["Improves rate of prosperity gain and can be developed to increase rents via Imperial Barons."], "div", ["indent"]);
 	App.Events.addNode(t, ["Slows increases in the ratio of slaves to citizens."], "div", ["indent"]);
 	App.Events.addNode(t, ["Can be developed to improve the Arcology's combat prowess and resistance to insurrection via Imperial Knights."], "div", ["indent"]);
-	App.Events.addNode(t, ["Provides demand for healthy slaves from", App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
+	App.Events.addNode(t, ["Provides demand for healthy slaves from",
+		App.UI.DOM.combineNodes(App.Encyclopedia.link("The Corporation"), ".")]);
 	App.Events.addNode(t, ["Mutually exclusive with all Revivalist models."], "div", ["indent"]);
 	return t;
 }, "FutureSocities");
@@ -466,9 +515,7 @@ App.Encyclopedia.addArticle("Antebellum Revivalism", function() {
 
 App.Encyclopedia.addArticle("Gender Radicalism Research", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		"Advanced Gender Radicalist societies can fund research to produce modified uteri and ovaries designed to be implanted into male slaves to grant them the ability to become pregnant, thus leaving no gender specific traits remaining."
-	], "div");
+	App.Events.addNode(t, ["Advanced Gender Radicalist societies can fund research to produce modified uteri and ovaries designed to be implanted into male slaves to grant them the ability to become pregnant, thus leaving no gender specific traits remaining."], "div");
 	return t;
 }, "FutureSocities");
 
@@ -486,11 +533,9 @@ App.Encyclopedia.addArticle("Transformation Fetishism Research", function() {
 
 App.Encyclopedia.addArticle("Asset Expansionist Research", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		"Advanced Asset Expansionist societies can fund research to produce extremely powerful growth drugs capable of growing body parts to previously undocumented sizes.",
+	App.Events.addNode(t, ["Advanced Asset Expansionist societies can fund research to produce extremely powerful growth drugs capable of growing body parts to previously undocumented sizes.",
 		"Drugs are also standardized in slave diets to prevent loss of asset size.",
-	 "Due to the rapid growth in said assets, and the strength of the drug cocktails, slaves are more likely to develop side effects of excessive drug use."
-	], "div");
+		"Due to the rapid growth in said assets, and the strength of the drug cocktails, slaves are more likely to develop side effects of excessive drug use."], "div");
 	return t;
 }, "FutureSocities");
 
@@ -506,23 +551,21 @@ App.Encyclopedia.addArticle("Slimness Enthusiast Research", function() {
 
 App.Encyclopedia.addArticle("Youth Preferentialism Research", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		"Specialized creams built off of stem cells and several ingredients known for reducing the ravages of age.",
-		"Steady use leaves a slave looking younger, though the effects are literally skin deep; several gossip pieces have run about celebrities bedding youthful slaves just to accidentally find their efforts resulting in a broken hip."
-	], "div");
+	App.Events.addNode(t, ["Specialized creams built off of stem cells and several ingredients known for reducing the ravages of age.",
+		"Steady use leaves a slave looking younger, though the effects are literally skin deep; several gossip pieces have run about celebrities bedding youthful slaves just to accidentally find their efforts resulting in a broken hip."], "div");
 	return t;
 }, "FutureSocities");
 
 App.Encyclopedia.addArticle("Hedonistic Decadence Research", function() {
 	const t = new DocumentFragment();
-	App.Events.addNode(t, [
-		"Advanced Hedonistic Decadence societies can purchase plans for specialized slave food.",
-	 "Said food is shaped to resemble actual food and flavored accordingly, however, its texture can only be described as gooey or gummy.",
+	App.Events.addNode(t, ["Advanced Hedonistic Decadence societies can purchase plans for specialized slave food.",
+		"Said food is shaped to resemble actual food and flavored accordingly, however, its texture can only be described as gooey or gummy.",
 		"A plus if that is how the food should be, but a shocker otherwise, given how tantalizing that steak looks after nothing but liquid slave food for so long.",
-		"Since the food is essentially compacted liquid slave food, it is highly addictive thanks to the, typically, low presence of aphrodisiacs and can easily lead to excessive", App.Encyclopedia.link("weight gain", "Weight"), "as slaves are driven to gorge themselves on it.",
+		"Since the food is essentially compacted liquid slave food, it is highly addictive thanks to the, typically, low presence of aphrodisiacs and can easily lead to excessive",
+		App.Encyclopedia.link("weight gain", "Weight"), "as slaves are driven to gorge themselves on it.",
 		"They'll be happy, at least, as they steadily outgrow their clothes.",
-		"Alterations to the recipe exist to prevent", App.Encyclopedia.link("weight gain", "Weight"), "for Slimness Enthusiast societies and to cause gastric distress in Degradationist societies."
-	], "div");
+		"Alterations to the recipe exist to prevent", App.Encyclopedia.link("weight gain", "Weight"),
+		"for Slimness Enthusiast societies and to cause gastric distress in Degradationist societies."], "div");
 	return t;
 }, "FutureSocities");
 
diff --git a/src/gui/Encyclopedia/encyclopediaParaphilias.js b/src/gui/Encyclopedia/encyclopediaParaphilias.js
index 71a17ef38161ce4f0fdc67af4075058954115cca..5a4a1f2ed0802b9d9b65dad7c5338ce583d5eb1d 100644
--- a/src/gui/Encyclopedia/encyclopediaParaphilias.js
+++ b/src/gui/Encyclopedia/encyclopediaParaphilias.js
@@ -95,7 +95,7 @@ App.Encyclopedia.addArticle("Maliciousness", function() {
 App.Encyclopedia.addArticle("Self Hatred", function() {
 	const f = new DocumentFragment();
 	const r = new SpacedTextAccumulator(f);
-	r.push(App.UI.DOM.makeElement("span","self hatred", ["bold"]), "is a paraphilia, an intense form of sexual", App.Encyclopedia.link("flaws"), "that cannot be softened.");
+	r.push(App.UI.DOM.makeElement("span", "self hatred", ["bold"]), "is a paraphilia, an intense form of sexual", App.Encyclopedia.link("flaws"), "that cannot be softened.");
 	r.toParagraph();
 
 	r.push("Self hating slaves can be satisfied by work in an industrialized dairy, in an arcade, or in a glory hole, and will not suffer negative mental effects for doing so.");
diff --git a/src/gui/Encyclopedia/encyclopediaRAActivationEditor.js b/src/gui/Encyclopedia/encyclopediaRAActivationEditor.js
index 6347e8031d5b2a1d93336bb8f52cdd6c80913738..c1c0f27e0671298c3b51f7d9f49f834160f06e09 100644
--- a/src/gui/Encyclopedia/encyclopediaRAActivationEditor.js
+++ b/src/gui/Encyclopedia/encyclopediaRAActivationEditor.js
@@ -80,6 +80,9 @@ App.Encyclopedia.addArticle("RA Condition Editor", function() {
 
 	const acc = new SpacedTextAccumulator();
 
+	acc.push("<span class='bold'>Note:</span> For the simple mode only the section <span class='bold'>Data getters</span> is relevant.");
+	acc.toParagraph();
+
 	acc.push("Rule conditions consist of two types of elements, data getters and data transformers. Data getters can " +
 		"read out values from various places, which can then be used to base conditions on. Data transformers " +
 		"take one or more elements as input and transform the input values into a single new value. Together they " +
@@ -128,16 +131,20 @@ App.Encyclopedia.addArticle("RA Condition Editor", function() {
 
 	App.UI.DOM.appendNewElement("h3", c, "Custom getters");
 	acc.push("If greater freedom is required for the conditions needed, a custom data getter can be used.",
-		"It operates on a context object with the following properties: slave: The slave currently tested against.",
-		"It is required to explicitly set the return type. If the set type does not match the actual return type, " +
-		"the condition evaluation will fail!");
+		"It operates on a context object with the following properties:",
+		"<ul>",
+		"<li>slave: The slave currently tested against.</li>",
+		"</ul>",
+		"It is required to explicitly set the return type. If the set type does not match the actual return type, the condition evaluation will fail!");
 	acc.toParagraph();
 	acc.push("For example to get the slave name you can use");
 	acc.push(App.UI.DOM.makeElement("span", "context => context.slave.slaveName", ["monospace"]));
 	acc.push("and set the getter type to string.");
 	acc.toParagraph();
-	acc.push("Documentation for slave attributes can be found " +
-		"<a target='_blank' class='link-external' href='https://gitgud.io/pregmodfan/fc-pregmod/-/raw/pregmod-master/devNotes/legacy files/slave%20variables%20documentation.md'>here.</a>");
+	acc.push("Documentation for slave attributes can be found",
+		"<a target='_blank' class='link-external' href='https://gitgud.io/pregmodfan/fc-pregmod/-/raw/pregmod-master/devNotes/legacy files/slave%20variables%20documentation.md'>here.</a>",
+		"Alternatively you can look up the properties needed in the", "" +
+		"<a target='_blank' class='link-external' href='https://gitgud.io/pregmodfan/fc-pregmod/-/blob/pregmod-master/src/js/SlaveState.js'>actual definitions.</a>");
 	acc.toParagraph();
 
 	return acc.container();
diff --git a/src/gui/options/options.js b/src/gui/options/options.js
index ca41733314be7bb548750bfb45369f58a95c9b18..9e5acf93d9c12c9837dc971ab130284cfb0c985b 100644
--- a/src/gui/options/options.js
+++ b/src/gui/options/options.js
@@ -107,25 +107,6 @@ App.UI.optionsPassage = function() {
 			);
 		}
 
-		if (V.releaseID === 1057) {
-			links.push(
-				App.UI.DOM.link(
-					`Free male anatomy removal due to accidentally flawed updater`,
-					() => {
-						V.PC.dick = 0;
-						V.PC.balls = 0;
-						V.PC.prostate = 0;
-						V.PC.scrotum = 0;
-						V.PC.ballsImplant = 0;
-						jQuery(results).empty().append(`Cash reset to ${V.cash}`);
-					},
-					[],
-					"Options",
-					"Use this if your female PC picked up a few extra parts during the conversion process.",
-				)
-			);
-		}
-
 		App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links));
 
 		if ((V.releaseID >= 1000) || V.ver.startsWith("0.9") || V.ver.startsWith("0.8") || V.ver.startsWith("0.7") || V.ver.startsWith("0.6")) {
@@ -856,7 +837,7 @@ App.Intro.display = function(isIntro) {
 	options.addOption("Help tooltips are", "tooltipsEnabled")
 		.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
 		.addComment(`This is mostly for new players. <span class='exampleTooltip noteworthy'>Colored text</span> can have tooltips.`)
-		.addCallbackToEach(App.UI.GlobalTooltips.update);
+		.addGlobalCallback(App.UI.GlobalTooltips.update);
 
 	options.addOption("Main menu slave tabs are", "useSlaveSummaryTabs")
 		.addValue("Enabled", 1).on().addValue("CardStyle", 2).on().addValue("Disabled", 0).off();
diff --git a/src/gui/options/optionsGroup.js b/src/gui/options/optionsGroup.js
index d51a9902e19397a6605f46e1d3a14c040bc32ce9..b1220f9b164e04542afb34704cbcf662775a3ff1 100644
--- a/src/gui/options/optionsGroup.js
+++ b/src/gui/options/optionsGroup.js
@@ -35,6 +35,11 @@ App.UI.OptionsGroup = (function() {
 			 * @type {Array<value>}
 			 */
 			this.valuePairs = [];
+			/**
+			 * @type {function(any):void}
+			 * @private
+			 */
+			this._globalCallback = undefined;
 		}
 
 		/**
@@ -157,12 +162,11 @@ App.UI.OptionsGroup = (function() {
 		}
 
 		/**
-		 * TODO: Replace with a global callback
-		 *
+		 * Only executed if no specific callback for this option exists.
 		 * @param {function(any):void} callback gets executed on every button click. Selected value is given as argument.
 		 */
-		addCallbackToEach(callback) {
-			this.valuePairs.forEach(pair => pair.callback = callback);
+		addGlobalCallback(callback) {
+			this._globalCallback = callback;
 			return this;
 		}
 
@@ -261,6 +265,8 @@ App.UI.OptionsGroup = (function() {
 							this.object[this.property] = value.value;
 							if (value.callback) {
 								value.callback(value.value);
+							} else if (this._globalCallback) {
+								this._globalCallback(value.value);
 							}
 							refresh();
 						};
@@ -280,6 +286,8 @@ App.UI.OptionsGroup = (function() {
 					const originalObj = this.valuePairs.find(obj => obj.value === value);
 					if (originalObj && typeof originalObj.callback === "function") {
 						originalObj.callback(originalObj.value);
+					} else if (this._globalCallback) {
+						this._globalCallback(originalObj.value);
 					}
 					refresh();
 				}));
@@ -529,8 +537,7 @@ App.UI.OptionsGroup = (function() {
 		 * @returns {Comment}
 		 */
 		addComment(comment) {
-			const c = new Comment(comment);
-			return this._addRow(c);
+			return this._addRow(new Comment(comment));
 		}
 
 		/**
diff --git a/src/gui/storyCaption.js b/src/gui/storyCaption.js
index 44219b7640a4133c1b451e77eea7e43e2ad0c242..60b633c15646395dfb9bee25c57533898e45196f 100644
--- a/src/gui/storyCaption.js
+++ b/src/gui/storyCaption.js
@@ -504,24 +504,38 @@ App.UI.storyCaption = function() {
 	}
 
 	function startingGirls() {
+		const f = new DocumentFragment();
+
 		// @ts-ignore // In starting girls we know that there is always an active slave
 		let cost = startingSlaveCost(V.activeSlave);
-		const p = document.createElement("p");
-
+		let p = document.createElement("p");
 		if (cost > V.cash) {
 			const div = document.createElement("div");
 			div.classList.add("cash", "dec");
 			div.append("This slave will cost ",
-				App.UI.DOM.makeElement("span", cashFormat(cost), ["bold"]), ".",
-				App.UI.DOM.makeElement("div", `You only have: ${cashFormat(V.cash)}.`));
+				App.UI.DOM.makeElement("span", cashFormat(cost), ["bold"]), ".");
 			p.append(div);
+
+			App.UI.DOM.appendNewElement("div", p, `You only have: ${cashFormat(V.cash)}.`);
 		} else {
 			const div = document.createElement("div");
 			div.append("This slave will cost ",
-				App.UI.DOM.makeElement("span", cashFormat(cost), ["cash"]), ".",
-				App.UI.DOM.makeElement("div", `You have ${cashFormat(V.cash)}.`));
+				App.UI.DOM.makeElement("span", cashFormat(cost), ["cash"]), ".");
 			p.append(div);
+
+			App.UI.DOM.appendNewElement("div", p, `You have ${cashFormat(V.cash)}.`);
 		}
-		return p;
+		f.append(p);
+
+		if (V.limitedCheatStart) {
+			p = document.createElement("p");
+			p.append("Edit cash: ", App.UI.DOM.makeTextBox(V.cash, cash => {
+				cashX(cash - V.cash, "cheating");
+				App.UI.reload();
+			}, true));
+			f.append(p);
+		}
+
+		return f;
 	}
 };
diff --git a/src/interaction/prostheticLabPassage.js b/src/interaction/prostheticLabPassage.js
index c8d3aa27e4abb8c9162903261a34c25fef2deba5..3c1a67b18d2b07e351a64649b5c185f313222c8b 100644
--- a/src/interaction/prostheticLabPassage.js
+++ b/src/interaction/prostheticLabPassage.js
@@ -28,19 +28,20 @@ App.UI.prostheticLab = function() {
 		App.UI.DOM.appendNewElement("h3", node, "Personnel");
 
 		if (V.researchLab.aiModule === 1) {
-			App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
-				"Buy and install research module",
-				() => {
-					cashX(forceNeg(35000 * V.upgradeMultiplierArcology), "capEx");
-					V.researchLab.aiModule = 2;
-					App.UI.reload();
-				},
-				[], '',
-				`This module enables your personal assistant to assist staff and direct menials assigned to your research facility, increasing efficiency. It costs ${cashFormat(35000 * V.upgradeMultiplierArcology)}`
-			));
+			const div = document.createElement("div");
+			div.append(App.UI.DOM.link("Buy and install research module", () => {
+				cashX(forceNeg(35000 * V.upgradeMultiplierArcology), "capEx");
+				V.researchLab.aiModule = 2;
+				App.UI.reload();
+			}));
+			App.Events.addNode(div, [` Costs ${cashFormatColor(35000 * V.upgradeMultiplierArcology)}`]);
+			node.append(div);
+			App.UI.DOM.appendNewElement("div", node,
+				`This module enables your personal assistant to assist staff and direct menials assigned to your research facility, increasing efficiency.`,
+				["note", "indent"]);
 		}
 		if ((staff) === 0) {
-			App.UI.DOM.appendNewElement("div", node, "Facility is currently unstaffed.", "note");
+			App.UI.DOM.appendNewElement("div", node, "Facility is currently unstaffed.");
 		} else {
 			r.push(`You have`);
 			if (V.researchLab.hired === 1) {
@@ -63,27 +64,24 @@ App.UI.prostheticLab = function() {
 			if (V.researchLab.aiModule > 1) {
 				r.push(`Occasionally you hear the voice of your assistant as ${heA} helps direct and organize work.`);
 			}
-			App.Events.addNode(node, r, "div", "note");
+			App.Events.addNode(node, r, "div");
 			r = [];
 		}
 
-		let div = App.UI.DOM.appendNewElement("div", node, null, "indent");
-		div.append(`Currently, this facility can employ ${V.researchLab.maxSpace} people.`);
+		App.UI.DOM.appendNewElement("div", node, `Currently, this facility can employ ${V.researchLab.maxSpace} people.`, ["indent",
+			"note"]);
 		if (V.researchLab.maxSpace >= 5) { // Exists
 			if (V.researchLab.maxSpace < 50) { // Can upgrade
 				const maxSpace = [5, 10, 20, 30, 40, 50];
 				const upgrade = maxSpace[maxSpace.indexOf(V.researchLab.maxSpace) + 1];
-				App.UI.DOM.appendNewElement("div", div, App.UI.DOM.link(
+				App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
 					"Expand facility",
 					() => {
 						cashX(forceNeg(Math.trunc(500 * upgrade * V.upgradeMultiplierArcology)), "capEx");
 						V.researchLab.maxSpace = upgrade;
 						App.UI.reload();
-					}
-				));
-			} else {
-				App.Events.addNode(div, r, "div", "note");
-				r = [];
+					}), ["indent"]
+				);
 			}
 		}
 
@@ -106,7 +104,8 @@ App.UI.prostheticLab = function() {
 				}
 			}
 			App.Events.addNode(node, ["Hire", App.UI.DOM.generateLinksStrip(linkArray), "scientists."]);
-			App.UI.DOM.appendNewElement("div", node, `Each scientist will require an initial fee of ${cashFormat(2000)} and incur ${cashFormat(300)} weekly.`, ["indent", "note"]);
+			App.Events.addNode(node, [`Each scientist will require an initial fee of ${cashFormatColor(2000)} and incur ${cashFormatColor(300)} weekly.`], "div", ["indent",
+				"note"]);
 
 			if (V.menials > 0) {
 				const space = (V.researchLab.maxSpace - (staff));
@@ -129,7 +128,8 @@ App.UI.prostheticLab = function() {
 			} else {
 				App.UI.DOM.appendNewElement("div", node, `You do not own any unassigned menial slaves.`);
 			}
-			App.UI.DOM.appendNewElement("div", node, `Using menial slaves is much cheaper than hiring scientists, but they are less effective. ${cashFormat(100)} per slave each week.`, ["indent", "note"]);
+			App.Events.addNode(node, [`Using menial slaves is much cheaper than hiring scientists, but they are less effective. Costs ${cashFormatColor(100)} per slave each week.`],
+				"div", ["indent", "note"]);
 		} else {
 			App.UI.DOM.appendNewElement("div", node, "Facility is fully staffed.", ["indent", "note"]);
 		}
@@ -180,8 +180,11 @@ App.UI.prostheticLab = function() {
 				App.UI.DOM.appendNewElement("div", node, `You have projects planned but without researchers you won't be able to work on them:`);
 			}
 
+			const taskDiv = document.createElement("div");
+			taskDiv.classList.add("grid-3columns-auto");
+
 			for (let i = 0; i < V.researchLab.tasks.length; i++) {
-				const r = [];
+				let r = [];
 				switch (V.researchLab.tasks[i].type) {
 					case "research":
 						r.push(`You`);
@@ -212,9 +215,13 @@ App.UI.prostheticLab = function() {
 				}
 				j += V.researchLab.tasks[i].workLeft;
 				r.push(`<span class="noteworthy">${capFirstChar(App.Data.prosthetics[V.researchLab.tasks[i].id].name)}.</span>`);
+				App.Events.addNode(taskDiv, r, "div", "indent");
+				r = [];
 				if (V.researchLab.speed > 0) {
 					r.push(`Finished in approximately ${(Math.floor(j / V.researchLab.speed) + 1)} week(s).`);
 				}
+				App.Events.addNode(taskDiv, r, "div");
+				r = [];
 
 				r.push(App.UI.DOM.link(
 					(V.researchLab.tasks[i].type === "research") ? "Cancel: Will not return investments." : "Cancel",
@@ -226,8 +233,10 @@ App.UI.prostheticLab = function() {
 						App.UI.reload();
 					}
 				));
-				App.Events.addNode(node, r, "div", "indent");
+				App.Events.addNode(taskDiv, r, "div");
 			}
+
+			node.append(taskDiv);
 		} else {
 			App.UI.DOM.appendNewElement("div", node, `Currently the research lab has no tasks planned.`, "note");
 		}
@@ -235,25 +244,31 @@ App.UI.prostheticLab = function() {
 		App.UI.DOM.appendNewElement("h3", node, "Research");
 
 		App.UI.DOM.appendNewElement("div", node, `Available research projects:`);
+		const researchDiv = document.createElement("div");
+		researchDiv.classList.add("grid-2columns-auto");
 		for (let p of App.Data.prostheticIDs) {
 			if (V.prosthetics[p].research === 0) {
-				// <div class="indent">
 				if (App.Data.prosthetics[p].level <= V.prostheticsUpgrade) {
-					App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
-						`Reverse engineer ${addA(App.Data.prosthetics[p].name)}`,
+					App.UI.DOM.appendNewElement("div", researchDiv, App.UI.DOM.link(`Reverse engineer ${addA(App.Data.prosthetics[p].name)}`,
 						() => {
 							cashX(forceNeg(App.Data.prosthetics[p].costs), "labResearch");
 							V.prosthetics[p].research = -1;
-							V.researchLab.tasks.push({type: "research", id: p, workLeft: App.Data.prosthetics[p].research});
+							V.researchLab.tasks.push({
+								type: "research",
+								id: p,
+								workLeft: App.Data.prosthetics[p].research
+							});
 							App.UI.reload();
-						}, [], "",
-						`Costs ${cashFormat(App.Data.prosthetics[p].costs)} of initial investment.`
-					), "indent");
+						}
+					), ["indent"]);
+					App.Events.addNode(researchDiv, [` Costs ${cashFormatColor(App.Data.prosthetics[p].costs)} of initial investment.`], "div");
 				} else {
-					App.UI.DOM.appendNewElement("div", node, `You need better contracts to get the required research material for reverse engineering ${addA(App.Data.prosthetics[p].name)}.`, "note");
+					App.UI.DOM.appendNewElement("div", researchDiv, `You need better contracts to get the required research material for reverse engineering ${addA(App.Data.prosthetics[p].name)}.`, ["note",
+						"grid-all-columns"]);
 				}
 			}
 		}
+		node.append(researchDiv);
 
 		App.UI.DOM.appendNewElement("h3", node, "Manufacture");
 
diff --git a/src/interaction/siCustom.js b/src/interaction/siCustom.js
index 634b301ee31f66d8cbdc2daa7adb05b0b3052789..793b3720a035bde6689ad854f767d44b7f04a0ea 100644
--- a/src/interaction/siCustom.js
+++ b/src/interaction/siCustom.js
@@ -16,7 +16,8 @@ App.UI.SlaveInteract.custom = function(slave, refresh) {
 	App.UI.DOM.appendNewElement("h3", el, `Art`);
 	el.append(
 		customSlaveImage(),
-		customHairImage()
+		customHairImage(),
+		artSeed()
 	);
 
 	App.UI.DOM.appendNewElement("h3", el, `Names`);
@@ -33,6 +34,7 @@ App.UI.SlaveInteract.custom = function(slave, refresh) {
 		customTattoo(),
 		customOriginStory(),
 		customDescription(),
+		customSlaveTitle(),
 		customLabel()
 	);
 
@@ -86,10 +88,8 @@ App.UI.SlaveInteract.custom = function(slave, refresh) {
 						"",
 						v => {
 							slave.custom.title = v;
-							jQuery('#result').empty().append(
-								document.createTextNode(`${He}'ll try ${his} best to call you ${slave.custom.title}.`)
-							);
 							slave.custom.titleLisp = lispReplace(slave.custom.title);
+							refresh();
 						}
 					)
 				);
@@ -100,10 +100,8 @@ App.UI.SlaveInteract.custom = function(slave, refresh) {
 						slave.custom.title,
 						v => {
 							slave.custom.title = v;
-							jQuery('#result').empty().append(
-								document.createTextNode(`${He}'ll try ${his} best to call you ${slave.custom.title}.`)
-							);
 							slave.custom.titleLisp = lispReplace(slave.custom.title);
+							refresh();
 						}
 					)
 				);
@@ -111,11 +109,9 @@ App.UI.SlaveInteract.custom = function(slave, refresh) {
 					App.UI.DOM.link(
 						` Stop using a custom title`,
 						() => {
-							jQuery('#result').empty().append(
-								document.createTextNode(`${He} will no longer refer to you with a special title.`)
-							);
 							slave.custom.title = "";
 							slave.custom.titleLisp = "";
+							refresh();
 						}
 					)
 				);
@@ -652,6 +648,26 @@ App.UI.SlaveInteract.custom = function(slave, refresh) {
 		return el;
 	}
 
+	function customSlaveTitle() {
+		let el = document.createElement('p');
+		el.append(`Change ${his} custom slave title: `);
+		el.appendChild(
+			App.UI.DOM.makeTextBox(slave.custom.name,
+				v => {
+					slave.custom.name = v;
+					refresh();
+				}
+			)
+		);
+
+		let choices = document.createElement('div');
+		choices.className = "choices";
+		choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, should fit into a sentence like: '${SlaveFullName(slave)} is a "slave title"'`, 'note'));
+		el.appendChild(choices);
+
+		return el;
+	}
+
 	function customLabel() {
 		let el = document.createElement('p');
 		el.append(`Change ${his} custom label: `);
@@ -670,6 +686,30 @@ App.UI.SlaveInteract.custom = function(slave, refresh) {
 		return el;
 	}
 
+	function artSeed() {
+		const frag = new DocumentFragment();
+		if (V.imageChoice === 4) { // webGL only right now
+			App.UI.DOM.appendNewElement("p", frag, `WebGL rendering uses a "seed value" to make small changes to the appearance of your slaves. If you're dissatisfied with this slave's appearance and correcting ${his} physical parameters doesn't seem to help, you can try replacing the seed value. Slaves with identical seeds will look identical; the game carefully preserves this value for clones and identical twins, but if you change it here it becomes your responsibility.`);
+
+			const setArtSeed = (/** @type {number} */ num) => {
+				slave.natural.artSeed = num;
+				refresh();
+				App.Events.refreshEventArt(slave);
+			};
+			const button = App.UI.DOM.makeElement("button", "Randomize");
+			button.onclick = () => setArtSeed(jsRandom(0, 10 ** 14));
+			const textbox = App.UI.DOM.makeTextBox(slave.natural.artSeed, (num) => setArtSeed(num), true);
+			textbox.style.maxWidth = "12em";
+			textbox.style.minWidth = "12em";
+			App.UI.DOM.appendNewElement("p", frag, App.UI.DOM.combineNodes(
+				"Art seed: ",
+				textbox,
+				button
+			));
+		}
+		return frag;
+	}
+
 	function customSlaveImage() {
 		let el = document.createElement('p');
 		el.append(`Assign ${him} a custom image: `);
diff --git a/src/interaction/siWardrobe.js b/src/interaction/siWardrobe.js
index 59e81ea3c8a644f3ee184e4bdfab9f33dfd63ddf..e4d54164b52e2a84cccf59e14ab9ca188d1fe4dd 100644
--- a/src/interaction/siWardrobe.js
+++ b/src/interaction/siWardrobe.js
@@ -60,21 +60,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 			[false, "Nice"],
 			[true, "Harsh"],
 		]);
-		let span = document.createElement("span");
-		span.classList.add("button-group");
-		for (const [bool, string] of niceFilters) {
-			const button = App.UI.DOM.makeElement("button", string);
-			if (T.filters.harsh === bool) {
-				button.classList.add("selected", "disabled");
-			} else {
-				button.onclick = () => {
-					T.filters.harsh = bool;
-					refresh();
-				};
-			}
-			span.append(button);
-		}
-		el.append(span);
+		el.append(filterButtons(niceFilters, "harsh"));
 
 		const exposureFilters = new Map([
 			[0, "Modest"],
@@ -83,21 +69,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 			[3, "Humiliating"],
 			[4, "Practically nude"],
 		]);
-		span = document.createElement("span");
-		span.classList.add("button-group");
-		for (const [num, string] of exposureFilters) {
-			const button = App.UI.DOM.makeElement("button", string);
-			if (T.filters.exposure === num) {
-				button.classList.add("selected", "disabled");
-			} else {
-				button.onclick = () => {
-					T.filters.exposure = num;
-					refresh();
-				};
-			}
-			span.append(button);
-		}
-		el.append(span);
+		el.append(filterButtons(exposureFilters, "exposure"));
 
 		const FSFilters = new Map([]);
 		for (const FS of App.Data.FutureSociety.fsNames) {
@@ -105,30 +77,39 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 				FSFilters.set(FS, App.Data.FutureSociety.records[FS].noun);
 			}
 		}
-		span = document.createElement("span");
+		el.append(filterButtons(FSFilters, "FSLoves"));
+
+		// clear filters
+		const resetButton = App.UI.DOM.makeElement("button", "Reset Filters");
+		resetButton.onclick = () => {
+			T.filters = {};
+			refresh();
+		};
+		App.UI.DOM.appendNewElement("span", el, resetButton, "button-group");
+		return el;
+	}
+
+	/**
+	 * @param {Map<number|boolean, string>} filters
+	 * @param {string} filterKey
+	 * @returns {HTMLSpanElement}
+	 */
+	function filterButtons(filters, filterKey) {
+		let span = document.createElement("span");
 		span.classList.add("button-group");
-		for (const [num, string] of FSFilters) {
+		for (const [num, string] of filters) {
 			const button = App.UI.DOM.makeElement("button", string);
-			if (T.filters.FSLoves === num) {
+			if (T.filters[filterKey] === num) {
 				button.classList.add("selected", "disabled");
 			} else {
 				button.onclick = () => {
-					T.filters.FSLoves = num;
+					T.filters[filterKey] = num;
 					refresh();
 				};
 			}
 			span.append(button);
 		}
-		el.append(span);
-
-		// clear filters
-		const resetButton = App.UI.DOM.makeElement("button", "Reset Filters");
-		resetButton.onclick = () => {
-			T.filters = {};
-			refresh();
-		};
-		App.UI.DOM.appendNewElement("span", el, resetButton, "button-group");
-		return el;
+		return span;
 	}
 
 	function chooseHerOwn() {
@@ -193,7 +174,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 		label.append(`Collar: `, App.UI.DOM.spanWithTooltip(slave.collar, itemTooltip(slave.collar, "collar"), ["bold"]));
 		// Choose her own
 		if (slave.collar !== `none`) {
-			label.append(noneLink("collar"));
+			label.append(" ", noneLink("collar"));
 		}
 		clothingDiv.appendChild(label);
 
@@ -273,7 +254,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 
 		// Choose her own
 		if (slave.faceAccessory !== `none`) {
-			label.append(noneLink("faceAccessory"));
+			label.append(" ", noneLink("faceAccessory"));
 		}
 
 		el.appendChild(label);
@@ -316,7 +297,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 
 		// Choose her own
 		if (slave.mouthAccessory !== `none`) {
-			label.append(noneLink("mouthAccessory"));
+			label.append(" ", noneLink("mouthAccessory"));
 		}
 
 		el.appendChild(label);
@@ -347,7 +328,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 
 		// Choose her own
 		if (slave.armAccessory !== "none") {
-			label.append(noneLink("armAccessory"));
+			label.append(" ", noneLink("armAccessory"));
 		}
 
 		el.appendChild(label);
@@ -407,7 +388,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 
 		// Choose her own
 		if (slave.legAccessory !== "none") {
-			label.append(noneLink("legAccessory"));
+			label.append(" ", noneLink("legAccessory"));
 		}
 
 		App.UI.DOM.appendNewElement("div", el, generateRows(App.Data.slaveWear.legAccessory, "legAccessory", false), "choices");
@@ -444,7 +425,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 
 		// Choose her own
 		if (slave.bellyAccessory !== `none`) {
-			label.append(noneLink("bellyAccessory"));
+			label.append(" ", noneLink("bellyAccessory"));
 		}
 
 		// Options
@@ -475,7 +456,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 		label.append(`Anal accessory: `, App.UI.DOM.spanWithTooltip(slave.buttplug, itemTooltip(slave.buttplug, "buttplug"), ["bold"]));
 
 		if (slave.buttplug !== `none`) {
-			label.append(noneLink("buttplug"));
+			label.append(" ", noneLink("buttplug"));
 		}
 		el.appendChild(label);
 
@@ -518,42 +499,20 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 	}
 
 	function buttplugAttachment() {
-		const el = document.createElement('div');
 		if (slave.buttplug === "none") {
-			return el;
+			return new DocumentFragment();
 		}
 
+		const el = document.createElement('div');
+
 		const label = document.createElement('div');
 		label.append(`Anal accessory attachment: `, App.UI.DOM.spanWithTooltip(slave.buttplugAttachment, itemTooltip(slave.buttplugAttachment, "buttplugAttachment"), ["bold"]));
-
 		if (slave.buttplugAttachment !== `none`) {
-			label.append(noneLink("buttplugAttachment"));
+			label.append(" ", noneLink("buttplugAttachment"));
 		}
 		el.appendChild(label);
 
-		let array = [];
-
-		for (const key of App.Data.slaveWear.buttplugAttachment.keys()) {
-			if (key === "none") {
-				// skip none in set, we set the link elsewhere.
-				continue;
-			}
-			array.push(key);
-		}
-
-		// Sort
-		array = array.sort((a, b) => (a > b) ? 1 : -1);
-		const sortedMap = new Map([]);
-		for (const name of array) {
-			sortedMap.set(name, App.Data.slaveWear.buttplugAttachment.get(name));
-		}
-
-		// Options
-		let links = document.createElement('div');
-		links.className = "choices";
-		links.appendChild(generateRows(sortedMap, "buttplugAttachment", true));
-		el.appendChild(links);
-
+		el.append(lowerAttachmentList(App.Data.slaveWear.buttplugAttachment, "buttplugAttachment"));
 		return el;
 	}
 
@@ -564,7 +523,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 		label.append(`Vaginal accessory: `, App.UI.DOM.spanWithTooltip(slave.vaginalAccessory, itemTooltip(slave.vaginalAccessory, "vaginalAccessory"), ["bold"]));
 
 		if (slave.vaginalAccessory !== `none`) {
-			label.append(noneLink("vaginalAccessory"));
+			label.append(" ", noneLink("vaginalAccessory"));
 		}
 		el.appendChild(label);
 
@@ -614,43 +573,22 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 	}
 
 	function vaginalAttachment() {
-		let el = document.createElement('div');
+		// TODO: This check should occur when setting the accessory
 		if (dildoWidth(slave) === 0) {
 			slave.vaginalAttachment = "none";
-			return el;
+			return new DocumentFragment();
 		}
 
-		let label = App.UI.DOM.appendNewElement("div", el, `Vaginal accessory attachment: `);
-
-		label.append(App.UI.DOM.spanWithTooltip(slave.vaginalAttachment, itemTooltip(slave.vaginalAttachment, "vaginalAttachment"), ["bold"]));
+		let el = document.createElement('div');
+		const label = document.createElement('div');
+		label.append(`Vaginal accessory attachment: `, App.UI.DOM.spanWithTooltip(slave.vaginalAttachment, itemTooltip(slave.vaginalAttachment, "vaginalAttachment"), ["bold"]));
 
 		if (slave.vaginalAttachment !== `none`) {
-			label.append(noneLink("vaginalAttachment"));
-		}
-
-		let array = [];
-
-		for (const key of App.Data.slaveWear.vaginalAttachment.keys()) {
-			if (key === "none") {
-				// skip none in set, we set the link elsewhere.
-				continue;
-			}
-			array.push(key);
-		}
-
-		// Sort
-		array = array.sort((a, b) => (a > b) ? 1 : -1);
-		const sortedMap = new Map([]);
-		for (const name of array) {
-			sortedMap.set(name, App.Data.slaveWear.vaginalAttachment.get(name));
+			label.append(" ", noneLink("vaginalAttachment"));
 		}
+		el.append(label);
 
-		// Options
-		let links = document.createElement('div');
-		links.className = "choices";
-		links.appendChild(generateRows(sortedMap, "vaginalAttachment", true));
-		el.appendChild(links);
-
+		el.append(lowerAttachmentList(App.Data.slaveWear.vaginalAttachment, "vaginalAttachment"));
 		return el;
 	}
 
@@ -661,34 +599,41 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 		label.append(`Dick accessory: `, App.UI.DOM.spanWithTooltip(slave.dickAccessory, itemTooltip(slave.dickAccessory, "dickAccessory"), ["bold"]));
 
 		if (slave.dickAccessory !== `none`) {
-			label.append(noneLink("dickAccessory"));
+			label.append(" ", noneLink("dickAccessory"));
 		}
 		el.appendChild(label);
 
-		let array = [];
+		el.append(lowerAttachmentList(App.Data.slaveWear.dickAccessory, "dickAccessory"));
+		return el;
+	}
 
-		for (const key of App.Data.slaveWear.dickAccessory.keys()) {
+	/**
+	 * @param {slaveWearCategory} data
+	 * @param {string} category
+	 * @returns {HTMLDivElement}
+	 */
+	function lowerAttachmentList(data, category) {
+		let keys = [];
+		for (const key of data.keys()) {
 			if (key === "none") {
 				// skip none in set, we set the link elsewhere.
 				continue;
 			}
-			array.push(key);
+			keys.push(key);
 		}
 
 		// Sort
-		// No sort here since we want small -> large. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1);
+		keys = keys.sort((a, b) => (a > b) ? 1 : -1);
 
 		// Options
 		const sortedMap = new Map([]);
-		for (const name of array) {
-			sortedMap.set(name, App.Data.slaveWear.dickAccessory.get(name));
+		for (const name of keys) {
+			sortedMap.set(name, data.get(name));
 		}
-		let links = document.createElement('div');
+		let links = document.createElement("div");
 		links.className = "choices";
-		links.appendChild(generateRows(sortedMap, "dickAccessory", true));
-		el.appendChild(links);
-
-		return el;
+		links.appendChild(generateRows(sortedMap, category, true));
+		return links;
 	}
 
 	function chastity() {
@@ -716,7 +661,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 		} else if (slave.chastityAnus === 1) {
 			chasCho = `anal chastity`;
 		} else if (slave.chastityAnus === 0 && slave.chastityPenis === 0 && slave.chastityVagina === 0) {
-			chasCho = `none `;
+			chasCho = `none`;
 		} else {
 			chasCho = `THERE HAS BEEN AN ERROR `;
 		}
@@ -724,9 +669,9 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 		label.append(App.UI.DOM.spanWithTooltip(chasCho, itemTooltip(chasCho, "chastity"), ["bold"]));
 
 		if (slave.chastityAnus !== 0 || slave.chastityPenis !== 0 || slave.chastityVagina !== 0) {
-			label.append(
+			label.append(" ",
 				App.UI.DOM.link(
-					` None`,
+					`None`,
 					() => {
 						Object.assign(
 							slave,
@@ -830,15 +775,18 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 
 	/**
 	 * Figure out a tooltip text to use based on clothing name.
-	 * Described effects are mainly from saClothes.js some are from saLongTermMentalEffects.js or saLongTermPhysicalEffects.js
-	 * Potential fetish revelations are not mentioned.
-	 * Chastity options could mention that at least fucktoys can appreciate maintaining their virginity but I assume just choosing a hole to focus on has the same effect so it's not really a clothing effect.
-	 * what's the word for below 20 devotion slaves? Disobedient?
-	 * Also accepting is a bit weird for ones above, I think I've seen obedient being used instead.
+	 * - Described effects are mainly from saClothes.js some are from saLongTermMentalEffects.js or saLongTermPhysicalEffects.js
+	 * - Potential fetish revelations are not mentioned.
+	 * - Chastity options could mention that at least fucktoys can appreciate maintaining their virginity, but I assume
+	 *   just choosing a hole to focus on has the same effect, so it's not really a clothing effect.
+	 * - what's the word for below 20 devotion slaves? Disobedient?
+	 * - Also accepting is a bit weird for ones above, I think I've seen obedient being used instead.
 	 * @param {string} itemName
 	 * @param {string} category
+	 * @returns {string|HTMLElement}
 	 */
 	function itemTooltip(itemName, category) {
+		console.log(itemName, category);
 		if (itemName === "none" || ["armAccessory", "legAccessory"].includes(category)) {
 			return "No effect one way or another.";
 		}
@@ -874,10 +822,6 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 						case 0:
 							desc.push("Modest.");
 							break;
-						default:
-							if (!item.harsh) {
-								desc.push("Only nice (meaning non-obedients lose devotion and fear while obedients gain devotion and trust)");
-							}
 					}
 				}
 				break;
@@ -940,6 +884,13 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 					desc.push("Makes it more scary to wear a plug but might give humiliation fetish,");
 				}
 				break;
+			case "dickAccessory":
+				if (item.vibrates >= 2) {
+					desc.push("Increases devotion and affects a specific fetish, attraction or sex drive.");
+				} else if (item.vibrates === 1) {
+					desc.push("Increases devotion but weakens fetish and libido.");
+				}
+				break;
 		}
 
 		if (item) {
@@ -959,13 +910,24 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 							lovers.push(App.Data.FutureSociety.records[FS].noun);
 						}
 						if (lovers.length > 0) {
-							desc.push(`${toSentence(lovers)} will ${value} this look.`); // TODO: Please move tooltip to array when that becomes possible
+							desc.push(`${toSentence(lovers)} will ${value} this look.`);
 						}
 					}
 				}
 			}
 		}
-		return desc.join(" ");
+
+		if (desc.length === 0) {
+			return item;
+		}
+		if (desc.length <= 1) {
+			return desc[0];
+		}
+		const f = document.createElement("ul");
+		for (const line of desc) {
+			App.UI.DOM.appendNewElement("li", f, line);
+		}
+		return f;
 	}
 
 	/** Generate a row of choices
@@ -978,7 +940,8 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 		const linkArray = [];
 		for (const [name, item] of map) {
 			let link;
-			// Some items will never be in App.Data.slaveWear.slaveWear, especially "none" if it falls in between harsh and nice data sets. Trying to look it up would cause an error, which is what access check works around.
+			// Some items will never be in App.Data.slaveWear.slaveWear, especially "none" if it falls in between harsh
+			// and nice data sets. Trying to look it up would cause an error, which is what access check works around.
 			const unlocked = (accessCheck === true) ? isItemAccessible.entry(name, category, slave) : false;
 			if (accessCheck === false || unlocked) {
 				if (typeof unlocked === 'string') { // is it just text?
@@ -986,10 +949,12 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 				} else {
 					link = document.createElement('span');
 
+					console.log(name, category, itemTooltip(name, category));
+
 					// Set up the link
 					link.appendChild(
 						App.UI.DOM.link(
-							`${item.name} `,
+							`${item.name}`,
 							() => {
 								slave[category] = name;
 								if (category === "clothes") {
@@ -1004,7 +969,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 					);
 
 					if (item.fs && item.fs.unlocks) {
-						link.append(App.UI.DOM.spanWithTooltip(`FS`, FutureSocieties.displayAdj(item.fs.unlocks), ["note"]));
+						link.append(" ", App.UI.DOM.spanWithTooltip(`FS`, FutureSocieties.displayAdj(item.fs.unlocks), ["note"]));
 					}
 				}
 				linkArray.push(link);
@@ -1016,7 +981,7 @@ App.UI.SlaveInteract.wardrobe = function(slave, contentRefresh) {
 
 	function noneLink(slaveSlot) {
 		return App.UI.DOM.link(
-			` None`,
+			`None`,
 			() => {
 				slave[slaveSlot] = "none";
 				refresh();
diff --git a/src/js/SlaveState.js b/src/js/SlaveState.js
index 63cc06ef1370bb1b22a6b12823f4b9dd66587861..26b176d0ffd0914d71cabee59546dadb49d7a31b 100644
--- a/src/js/SlaveState.js
+++ b/src/js/SlaveState.js
@@ -358,6 +358,8 @@ App.Entity.SlaveCustomAddonsState = class SlaveCustomAddonsState {
 		this.desc = "";
 		/** What the slave refers to you as. */
 		this.title = "";
+		/** Replaces SlaveTitle() if set. */
+		this.name = "";
 		/** What the slave refers to you as, with a lisp.*/
 		this.titleLisp = "";
 		/**
@@ -599,6 +601,16 @@ App.Entity.EyeState = class EyeState {
 	}
 };
 
+/** Genetic "natural targets" for this individual when full grown, without influence from drugs, surgery, etc */
+App.Entity.GeneticState = class GeneticState {
+	constructor() {
+		// TODO: move origHColor, origSkin, origRace here, as hColor, skin, race?
+		this.height = 170; // new - almost done.  need to rewrite physical development for both player and slave.
+		// this.boobs = 500; // TODO: for pregmodder
+		this.artSeed = jsRandom(0, 10 ** 14);
+	}
+};
+
 App.Entity.SlaveState = class SlaveState {
 	constructor() {
 		/** Slave's current name */
@@ -616,6 +628,8 @@ App.Entity.SlaveState = class SlaveState {
 		this.genes = "XX";
 		/** @type {number} */
 		this.pronoun = App.Data.Pronouns.Kind.female;
+		/** slave's natural genetic properties */
+		this.natural = new App.Entity.GeneticState();
 		/** game week slave was acquired.
 		 *
 		 * _0: Obtained prior to game start / at game start_ */
@@ -2613,9 +2627,9 @@ App.Entity.SlaveState = class SlaveState {
 		 *
 		 * 0: yes; 1+: number of swaps (increases upkeep each time) */
 		this.bodySwap = 0;
-		/** Who, if relevant, the body belonged to. */
+		/** Who, if relevant, this slave's current body belonged to originally. */
 		this.origBodyOwner = "";
-		/** Who, if relevant, the body belonged to. */
+		/** Who, if relevant, this slave's original body currently belongs to (i.e. the exact opposite of the variable above). */
 		this.origBodyOwnerID = 0;
 		/**
 		 * Slave's current hormonal balance, directs saHormones changes
diff --git a/src/js/assignJS.js b/src/js/assignJS.js
index cdacc33cf5a043ac7a422c7d075b6bc16bccea0e..823c3192a4eae32a433dc8087829fb6edcfa66e2 100644
--- a/src/js/assignJS.js
+++ b/src/js/assignJS.js
@@ -387,7 +387,9 @@ globalThis.assignJob = function(slave, job) {
 			if (V.dojo > 1) {
 				slave.rules.living = LivingRule.LUXURIOUS;
 			}
-			if (V.pit && V.pit.bodyguardFights && V.pit.fighterIDs.includes(slave.ID)) { V.pit.fighterIDs.delete(slave.ID); }
+			if (V.pit) {
+				V.pit.fighterIDs.delete(slave.ID);
+			}
 			break;
 
 		case Job.AGENT.toLowerCase():
diff --git a/src/js/makePurchase.js b/src/js/makePurchase.js
index e715a30d18bbf11c1cc5413d2cb1ec1b1b251a03..1a13728e694075b1e0df2586c357de2f627ebf73 100644
--- a/src/js/makePurchase.js
+++ b/src/js/makePurchase.js
@@ -31,8 +31,9 @@ globalThis.makePurchase = function(text, cost, what, {notes, handler, prereqs, r
 		const price = cost !== 0 ? `${cashFormat(Math.trunc(cost))}` : `free`;
 		const button = App.UI.DOM.makeElement("button", capFirstChar(price), ['purchase-button']);
 
-		if (V.cash >= cost &&
-			(!prereqs || prereqs.every(prereq => prereq[0] === true))) {
+		const disabledReasons = isDisabled();
+
+		if (disabledReasons.length === 0) {
 			button.onclick = execute;
 
 			if (notes) {
@@ -59,22 +60,9 @@ globalThis.makePurchase = function(text, cost, what, {notes, handler, prereqs, r
 		} else {
 			const span = document.createElement("span");
 			const ul = document.createElement("ul");
-			const reasons = [];
-
-			if (V.cash < cost) {
-				reasons.push(`You lack the necessary funds to make this purchase`);
-			}
-
-			if (prereqs) {
-				prereqs.forEach(prereq => {
-					if (prereq[0] !== true) {
-						reasons.push(prereq[1]);
-					}
-				});
-			}
 
-			if (reasons.length > 1) {
-				for (const li of reasons.map(reason => {
+			if (disabledReasons.length > 1) {
+				for (const li of disabledReasons.map(reason => {
 					const li = document.createElement("li");
 					li.append(reason);
 					return li;
@@ -84,7 +72,7 @@ globalThis.makePurchase = function(text, cost, what, {notes, handler, prereqs, r
 
 				span.append(ul);
 			} else {
-				span.append(reasons[0]);
+				span.append(disabledReasons[0]);
 			}
 
 			button.classList.add("disabled");
@@ -104,35 +92,37 @@ globalThis.makePurchase = function(text, cost, what, {notes, handler, prereqs, r
 
 	function renderLink() {
 		const span = App.UI.DOM.makeElement("span", null, ['indent']);
-		const price = [`${cost !== 0 ? `Costs ${cashFormat(Math.trunc(cost))}` : `Free`}`];
+		const price = [`${cost !== 0 ? `Costs ${cashFormatColor(Math.trunc(cost), V.cash < cost)}` : `Free`}`];
 
 		if (notes) {
 			price.push(...notes);
 		}
 
-		if (V.cash >= cost &&
-			(!prereqs || prereqs.every(prereq => prereq[0] === true))) {
-			span.append(App.UI.DOM.link(text, execute, [], ''), " ");
-		} else {
-			const reasons = [];
+		const disabledReasons = isDisabled();
 
-			if (V.cash < cost) {
-				reasons.push(`You cannot afford this purchase`);
-			}
-
-			if (prereqs) {
-				prereqs.forEach(prereq => {
-					if (prereq[0] !== true) {
-						reasons.push(prereq[1]);
-					}
-				});
-			}
-
-			span.append(App.UI.DOM.disabledLink(text, reasons), " ");
+		if (disabledReasons.length === 0) {
+			span.append(App.UI.DOM.link(text, execute), " ");
+		} else {
+			span.append(App.UI.DOM.disabledLink(text, disabledReasons), " ");
 		}
 
-		App.UI.DOM.appendNewElement("span", span, toSentence(price), ['note']);
+		App.Events.addNode(span, [toSentence(price)], "span", ["note"]);
 
 		return span;
 	}
+
+	function isDisabled() {
+		const disabledReasons = [];
+		if (V.cash < cost) {
+			disabledReasons.push(`You cannot afford this purchase`);
+		}
+		if (prereqs) {
+			prereqs.forEach(prereq => {
+				if (prereq[0] !== true) {
+					disabledReasons.push(prereq[1]);
+				}
+			});
+		}
+		return disabledReasons;
+	}
 };
diff --git a/src/js/pregJS.js b/src/js/pregJS.js
index e71093a5f81571088b15b5c701943a3d6d21dd88..6b6136b3294cab58f4a7f4362de3f3ba1c1f8e88 100644
--- a/src/js/pregJS.js
+++ b/src/js/pregJS.js
@@ -469,6 +469,87 @@ globalThis.knockMeUp = function(target, chance, hole, fatherID) {
 	return r;
 };
 
+/** Attempt to get an actor pregnant with another actor's child.
+ * Assumes that sperm is at the point of meeting the egg, so check penetrative ability outside of this.
+ * Technically deprecates canImpreg() and canFemImpreg().
+ * @param {App.Entity.SlaveState | App.Entity.PlayerState} mother is the actor attempting to become pregnant.
+ * @param {number} chance is the % chance to conceive.
+ * @param {0|1|2} hole control's the hole involved (0 - vagina, 1 - ass, 2 - both).
+ * @param {App.Entity.SlaveState | App.Entity.PlayerState} father is the actor doing the impregnating.
+ * @returns {string} Returns "${He} has become pregnant." if relevant
+ */
+globalThis.tryKnockMeUp = function(mother, chance, hole, father) {
+	let r = ``;
+	if (V.seePreg !== 0) {
+		if (canBreed(mother, father)) {
+			if (mother.geneMods.progenitor === 1) {
+				chance += 20;
+			}
+			if (father.geneMods.aggressiveSperm === 1) {
+				chance += 75;
+			}
+			if (father.geneticQuirks.potent === 2) {
+				chance *= 1.5;
+			}
+			if (V.reproductionFormula) {
+				if (mother.ID !== -1) {
+					chance += 10;
+				}
+				if (father.ID !== -1) {
+					chance += 10;
+				}
+			}
+			if (!isVirile(father) || !isFertile(mother) || (V.seeIncest === 0 && areRelated(mother, father))) {
+				chance = -10000;
+			}
+			if (mother.preg === -1) {
+				chance -= 350; // Allows making sperm so potent that they can overpower contraceptives. Shouldn't be possible at this value, but why stop a player from tweaking this if it's their thing?
+			}
+			if (mother.eggType !== father.ballType) { // Special case for fantasy races to create half-breeds.
+				chance -= 20;
+			}
+			if (random(0, 99) < chance) {
+				if (mother.mpreg === hole || hole === 2) {
+					if (mother.pregWeek <= 0) {
+						mother.preg = 1;
+						mother.pregSource = father.ID;
+						if (mother.ID !== -1) {
+							mother.pregWeek = 1;
+						}
+					}
+
+					mother.pregType = setPregType(mother);
+					WombImpregnate(mother, mother.pregType, father.ID, 1);
+
+					if (V.menstruation === 1) {
+						//
+					} else {
+						mother.pregKnown = 1;
+						if (mother.ID === -1) {
+							/* r += "<span class="lime">You have gotten pregnant.</span>"; */
+						} else {
+							const {He, him} = getPronouns(mother);
+							if (father.ID === -1) {
+								r += `<span class="lime">${He} has become pregnant.</span>`;
+							} else {
+								r += `<span class="lime">${father.slaveName} has gotten ${him} pregnant.</span>`;
+							}
+						}
+						if (mother.geneticQuirks.superfetation === 2 && mother.womb.length > 0) {
+							if (V.seeHyperPreg === 1) {
+								mother.fertPeak = 1;
+							} else {
+								mother.fertPeak = 4;
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+	return r;
+};
+
 globalThis.getIncubatorReserved = function( /* slaves */ ) {
 	return FetusGlobalReserveCount("incubator");
 };
diff --git a/src/js/sexActsJS.js b/src/js/sexActsJS.js
index 61fb5d1e0c91728fb25d54728a792b838cdd37e0..bc5183d404c853220675e15c5414502aae02878b 100644
--- a/src/js/sexActsJS.js
+++ b/src/js/sexActsJS.js
@@ -29,36 +29,36 @@ globalThis.VCheck = (function() {
 		let r = '';
 		setScopedPronouns(slave);
 
-		if (canDoAnal(slave) && slave.anus === 0) {
-			r += `<span class="lime">This breaks in ${slave.slaveName}'s virgin ass.</span> `;
-			if (slave.devotion > 50 || slave.career === "a slave since birth") {
-				r += `Since it's ${his} first time, you gently ease yourself into ${his} butthole and gradually increase the intensity of your thrusts. Before long ${he}'s moaning loudly as you continue working away at ${his} butthole. `;
-				if (slave.tankBaby === 2) {
-					r += `${He} thinks of losing ${his} anal virginity to ${his} ${getWrittenTitle(slave)} a <span class="hotpink">necessity.</span> ${He} expects ${his} asshole to be seeing a lot more attention now.`;
-				} else {
-					r += `${He} thinks of losing ${his} anal virginity to you as a <span class="hotpink">connection</span> with ${his} beloved ${getWrittenTitle(slave)}. `;
-					if ((slave.fetishKnown && slave.fetish === "buttslut") || (slave.energy > 95) || (slave.attrXX >= 85 && V.PC.dick === 0)) {
-						r += `${He} can't wait to be fucked in the ass by you again.`;
+		if (canDoAnal(slave)) {
+			if (slave.anus === 0) {
+				r += `<span class="lime">This breaks in ${slave.slaveName}'s virgin ass.</span> `;
+				if (slave.devotion > 50 || slave.career === "a slave since birth") {
+					r += `Since it's ${his} first time, you gently ease yourself into ${his} butthole and gradually increase the intensity of your thrusts. Before long ${he}'s moaning loudly as you continue working away at ${his} butthole. `;
+					if (slave.tankBaby === 2) {
+						r += `${He} thinks of losing ${his} anal virginity to ${his} ${getWrittenTitle(slave)} a <span class="hotpink">necessity.</span> ${He} expects ${his} asshole to be seeing a lot more attention now.`;
 					} else {
-						r += `${He} looks forward to having ${his} asshole fucked by you again.`;
+						r += `${He} thinks of losing ${his} anal virginity to you as a <span class="hotpink">connection</span> with ${his} beloved ${getWrittenTitle(slave)}. `;
+						if ((slave.fetishKnown && slave.fetish === "buttslut") || (slave.energy > 95) || (slave.attrXX >= 85 && V.PC.dick === 0)) {
+							r += `${He} can't wait to be fucked in the ass by you again.`;
+						} else {
+							r += `${He} looks forward to having ${his} asshole fucked by you again.`;
+						}
 					}
+					slave.devotion += 4;
+				} else if (slave.devotion > 20) {
+					r += `Since it's ${his} first time, you gently ease yourself into ${his} butthole and gradually increase the intensity of your thrusts. ${His} moans become louder and louder as you continue working away at ${his} butthole. ${He} accepts the pain and humiliation of anal sex as part of ${his} sexual servitude, though ${he} hopes that ${his} next time will be less painful.`;
+				} else if (slave.devotion >= -20) {
+					r += `You force yourself into ${his} butthole. ${He} sobs and cries with disgust while you continue thrusting into ${his} ass. ${He} <span class="gold">fears</span> ${his} next anal sex, remembering the pain of losing ${his} anal virginity. ${He} dreads having ${his} ass violated by you again.`;
+					slave.trust -= 5;
+				} else {
+					r += `You force yourself into ${his} butthole. ${He} sobs and cries with disgust while you continue thrusting into ${his} ass. ${He} <span class="mediumorchid">hates</span> and <span class="gold">fears</span> you for violating ${his} virgin butt. ${He} dreads having ${his} ass fucked by you again.`;
+					slave.trust -= 5;
+					slave.devotion -= 5;
 				}
-				slave.devotion += 4;
-			} else if (slave.devotion > 20) {
-				r += `Since it's ${his} first time, you gently ease yourself into ${his} butthole and gradually increase the intensity of your thrusts. ${His} moans become louder and louder as you continue working away at ${his} butthole. ${He} accepts the pain and humiliation of anal sex as part of ${his} sexual servitude, though ${he} hopes that ${his} next time will be less painful.`;
-			} else if (slave.devotion >= -20) {
-				r += `You force yourself into ${his} butthole. ${He} sobs and cries with disgust while you continue thrusting into ${his} ass. ${He} <span class="gold">fears</span> ${his} next anal sex, remembering the pain of losing ${his} anal virginity. ${He} dreads having ${his} ass violated by you again.`;
-				slave.trust -= 5;
-			} else {
-				r += `You force yourself into ${his} butthole. ${He} sobs and cries with disgust while you continue thrusting into ${his} ass. ${He} <span class="mediumorchid">hates</span> and <span class="gold">fears</span> you for violating ${his} virgin butt. ${He} dreads having ${his} ass fucked by you again.`;
-				slave.trust -= 5;
-				slave.devotion -= 5;
+				slave.anus = 1;
 			}
-			slave.anus = 1;
-		}
-		if (canDoAnal(slave)) {
-			if (canImpreg(slave, V.PC)) {
-				knockMeUp(slave, 10, 1, -1);
+			if (canPenetrate(V.PC)) {
+				tryKnockMeUp(slave, 10, 1, V.PC);
 			}
 			seX(slave, "anal", V.PC, "penetrative", times);
 		}
@@ -74,37 +74,37 @@ globalThis.VCheck = (function() {
 		let r = '';
 		setScopedPronouns(slave);
 
-		if (canDoVaginal(slave) && slave.vagina === 0) {
-			r += `<span class="lime">This breaks in ${slave.slaveName}'s virgin pussy.</span> `;
-			if (slave.devotion > 50 || slave.career === "a slave since birth") {
-				r += `You ease yourself into ${his} pussy, since it's ${his} first time, then gradually speed up your thrusts while ${he} slowly learns to move ${his} hips along with you. ${He} moans loudly. `;
-				if (slave.tankBaby === 2) {
-					r += `${He} thinks of losing ${his} virginity to ${his} ${getWrittenTitle(slave)} a <span class="hotpink">necessity to be happy.</span> ${He} expects ${his} pussy to be seeing a lot more attention in the future.`;
-				} else {
-					r += `<span class="hotpink">${He} enjoys losing ${his} cherry to you,</span> and `;
-					if ((slave.fetishKnown && slave.fetish === "pregnancy") || (slave.energy > 95) || (slave.attrXY >= 85 && V.PC.dick > 0)) {
-						r += `can't wait to have ${his} pussy fucked by you again.`;
+		if (canDoVaginal(slave)) {
+			if (slave.vagina === 0) {
+				r += `<span class="lime">This breaks in ${slave.slaveName}'s virgin pussy.</span> `;
+				if (slave.devotion > 50 || slave.career === "a slave since birth") {
+					r += `You ease yourself into ${his} pussy, since it's ${his} first time, then gradually speed up your thrusts while ${he} slowly learns to move ${his} hips along with you. ${He} moans loudly. `;
+					if (slave.tankBaby === 2) {
+						r += `${He} thinks of losing ${his} virginity to ${his} ${getWrittenTitle(slave)} a <span class="hotpink">necessity to be happy.</span> ${He} expects ${his} pussy to be seeing a lot more attention in the future.`;
 					} else {
-						r += `looks forward to having ${his} pussy fucked by you again.`;
+						r += `<span class="hotpink">${He} enjoys losing ${his} cherry to you,</span> and `;
+						if ((slave.fetishKnown && slave.fetish === "pregnancy") || (slave.energy > 95) || (slave.attrXY >= 85 && canPenetrate(V.PC))) {
+							r += `can't wait to have ${his} pussy fucked by you again.`;
+						} else {
+							r += `looks forward to having ${his} pussy fucked by you again.`;
+						}
 					}
+					slave.devotion += 4;
+				} else if (slave.devotion > 20) {
+					r += `You ease yourself into ${his} pussy, since it's ${his} first time, then gradually speed up your thrusts while ${he} slowly learns to move ${his} hips along with you. ${He} accepts losing ${his} virginity to ${his} owner and ${he} looks forward to having ${his} pussy fucked by you again.`;
+				} else if (slave.devotion >= -20) {
+					r += `You force yourself into ${his} pussy. ${He} sobs and cries with disgust while you continue thrusting into ${his} fuck hole. ${He} <span class="mediumorchid">hates</span> losing ${his} virginity this way and <span class="gold">fears</span> the next time you'll conquer ${him}. ${He} dreads getting violated by you again.`;
+					slave.trust -= 5;
+					slave.devotion -= 5;
+				} else {
+					r += `You force yourself into ${his} pussy. ${He} sobs and cries with disgust while you continue working ${his} fuck hole. ${He} tries to struggle, but you only pound harder. ${He} <span class="mediumorchid">hates</span> and <span class="gold">fears</span> you for robbing ${his} of ${his} virginity. ${He} dreads getting fucked by you again.`;
+					slave.trust -= 10;
+					slave.devotion -= 15;
 				}
-				slave.devotion += 4;
-			} else if (slave.devotion > 20) {
-				r += `You ease yourself into ${his} pussy, since it's ${his} first time, then gradually speed up your thrusts while ${he} slowly learns to move ${his} hips along with you. ${He} accepts losing ${his} virginity to ${his} owner and ${he} looks forward to having ${his} pussy fucked by you again.`;
-			} else if (slave.devotion >= -20) {
-				r += `You force yourself into ${his} pussy. ${He} sobs and cries with disgust while you continue thrusting into ${his} fuck hole. ${He} <span class="mediumorchid">hates</span> losing ${his} virginity this way and <span class="gold">fears</span> the next time you'll conquer ${him}. ${He} dreads getting violated by you again.`;
-				slave.trust -= 5;
-				slave.devotion -= 5;
-			} else {
-				r += `You force yourself into ${his} pussy. ${He} sobs and cries with disgust while you continue working ${his} fuck hole. ${He} tries to struggle, but you only pound harder. ${He} <span class="mediumorchid">hates</span> and <span class="gold">fears</span> you for robbing ${his} of ${his} virginity. ${He} dreads getting fucked by you again.`;
-				slave.trust -= 10;
-				slave.devotion -= 15;
+				slave.vagina = 1;
 			}
-			slave.vagina = 1;
-		}
-		if (canDoVaginal(slave)) {
-			if (canImpreg(slave, V.PC)) {
-				knockMeUp(slave, 10, 0, -1);
+			if (canPenetrate(V.PC)) {
+				tryKnockMeUp(slave, 10, 0, V.PC);
 			}
 			seX(slave, "vaginal", V.PC, "penetrative", times);
 		}
@@ -185,13 +185,13 @@ globalThis.VCheck = (function() {
 			if (canDoAnal(slave)) {
 				seX(slave, "vaginal", V.PC, "penetrative", bothTimes);
 				seX(slave, "anal", V.PC, "penetrative", bothTimes);
-				if (canImpreg(slave, V.PC)) {
-					knockMeUp(slave, 10, 2, -1);
+				if (canPenetrate(V.PC)) {
+					tryKnockMeUp(slave, 10, 2, V.PC);
 				}
 			} else {
 				seX(slave, "vaginal", V.PC, "penetrative", bothTimes);
-				if (canImpreg(slave, V.PC)) {
-					knockMeUp(slave, 10, 0, -1);
+				if (canPenetrate(V.PC)) {
+					tryKnockMeUp(slave, 10, 0, V.PC);
 				}
 			}
 		} else if (canDoAnal(slave)) {
@@ -218,8 +218,8 @@ globalThis.VCheck = (function() {
 				slave.anus = 1;
 			}
 			seX(slave, "anal", V.PC, "penetrative", analTimes);
-			if (canImpreg(slave, V.PC)) {
-				knockMeUp(slave, 10, 1, -1);
+			if (canPenetrate(V.PC)) {
+				tryKnockMeUp(slave, 10, 1, V.PC);
 			}
 		}
 		return r;
@@ -266,13 +266,13 @@ globalThis.VCheck = (function() {
 			if (canDoAnal(partner)) {
 				actX(partner, "vaginal", bothTimes);
 				actX(partner, "anal", bothTimes);
-				if (canImpreg(partner, V.PC)) {
-					r += knockMeUp(partner, 10, 2, -1);
+				if (canPenetrate(V.PC)) {
+					r += tryKnockMeUp(partner, 10, 2, V.PC);
 				}
 			} else {
 				actX(partner, "vaginal", bothTimes);
-				if (canImpreg(partner, V.PC)) {
-					r += knockMeUp(partner, 10, 0, -1);
+				if (canPenetrate(V.PC)) {
+					r += tryKnockMeUp(partner, 10, 0, V.PC);
 				}
 			}
 		} else if (canDoAnal(partner)) {
@@ -281,8 +281,8 @@ globalThis.VCheck = (function() {
 				partner.anus = 1;
 			}
 			actX(partner, "anal", analTimes);
-			if (canImpreg(partner, V.PC)) {
-				r += knockMeUp(partner, 10, 1, -1);
+			if (canPenetrate(V.PC)) {
+				r += tryKnockMeUp(partner, 10, 1, V.PC);
 			}
 		}
 		return r;
@@ -326,48 +326,44 @@ globalThis.SimpleSexAct = (function() {
 
 		for (let i = 0; i < fuckCount; i++) {
 			playerSex = sexArray.random();
-			fuckTarget = jsRandom(1, 100);
+			fuckTarget = random(1, 100);
 			if (V.policies.sexualOpenness === 1 || slave.toyHole === "dick") {
 				if (slave.nipples === "fuckable" && pPenetrates && fuckTarget > 90) {
 					seX(slave, "mammary", V.PC, "penetrative");
 				} else if (sPenetrates && V.PC.vagina > 0 && fuckTarget > 66) {
 					seX(V.PC, "vaginal", slave, "penetrative");
-					if (canImpreg(V.PC, slave)) {
-						knockMeUp(V.PC, 10, 0, slave.ID);
-					}
+					tryKnockMeUp(V.PC, 10, 0, slave);
 				} else if (canDoVaginal(slave) && (slave.vagina > 0 || (slave.vagina >= 0 && playerSex === "vaginal")) && fuckTarget > 33) {
 					seX(slave, "vaginal", V.PC, playerSex);
-					if ((canImpreg(slave, V.PC) && playerSex === "penetrative") || (canFemImpreg(slave, V.PC) && playerSex === "vaginal")) {
-						knockMeUp(slave, 10, 0, -1);
+					if (playerSex === "penetrative" || playerSex === "vaginal") {
+						tryKnockMeUp(slave, 10, 0, V.PC);
 					}
-					if (canFemImpreg(V.PC, slave) && playerSex === "vaginal") {
-						knockMeUp(V.PC, 10, 0, slave.ID);
+					if (playerSex === "vaginal") {
+						tryKnockMeUp(V.PC, 10, 0, slave);
 					}
 				} else if (canDoAnal(slave) && slave.anus > 0 && fuckTarget > 15) {
 					seX(slave, "anal", V.PC, "penetrative");
-					if (canImpreg(slave, V.PC)) {
-						knockMeUp(slave, 10, 1, -1);
+					if (canPenetrate(V.PC)) {
+						tryKnockMeUp(slave, 10, 1, V.PC);
 					}
 				} else if (sPenetrates && V.PC.anus > 0 && fuckTarget > 5) {
 					seX(V.PC, "anal", slave, "penetrative");
-					if (canImpreg(V.PC, slave)) {
-						knockMeUp(V.PC, 10, 1, slave.ID);
-					}
+					tryKnockMeUp(V.PC, 10, 1, slave);
 				} else {
 					seX(slave, "oral", V.PC, playerSex);
 				}
 			} else {
 				if (slave.nipples === "fuckable" && pPenetrates && fuckTarget > 80) {
 					seX(slave, "mammary", V.PC, "penetrative");
-				} else if (canDoVaginal(slave) && slave.vagina > 0 && fuckTarget > 33) {
+				} else if (canDoVaginal(slave) && (slave.vagina > 0 || (slave.vagina >= 0 && playerSex === "vaginal")) && fuckTarget > 33) {
 					seX(slave, "vaginal", V.PC, playerSex);
-					if ((canImpreg(slave, V.PC) && playerSex === "penetrative") || (canFemImpreg(slave, V.PC) && playerSex === "vaginal")) {
-						knockMeUp(slave, 10, 0, -1);
+					if (playerSex === "penetrative" || playerSex === "vaginal") {
+						tryKnockMeUp(slave, 10, 0, V.PC);
 					}
 				} else if (canDoAnal(slave) && slave.anus > 0 && fuckTarget > 10) {
 					seX(slave, "anal", V.PC, "penetrative");
-					if (canImpreg(slave, V.PC)) {
-						knockMeUp(slave, 10, 1, -1);
+					if (canPenetrate(V.PC)) {
+						tryKnockMeUp(slave, 10, 1, V.PC);
 					}
 				} else {
 					seX(slave, "oral", V.PC, playerSex);
@@ -389,7 +385,7 @@ globalThis.SimpleSexAct = (function() {
 		let fuckTarget = 0;
 
 		for (let i = 0; i < fuckCount; i++) {
-			fuckTarget = jsRandom(1, 100);
+			fuckTarget = random(1, 100);
 			if (slave.nipples === "fuckable" && fuckTarget > 80) {
 				actX(slave, "mammary");
 			} else if (canDoVaginal(slave) && slave.vagina > 0 && fuckTarget > 33) {
@@ -421,26 +417,20 @@ globalThis.SimpleSexAct = (function() {
 			let sex;
 			/** @type {FC.SlaveActs} */
 			let sex2 = "penetrative";
-			fuckTarget = jsRandom(1, 100);
+			fuckTarget = random(1, 100);
 			if (subSlave.nipples === "fuckable" && canPenetrate(domSlave) && fuckTarget > 80) {
 				sex = "mammary";
 			} else if (canDoVaginal(subSlave) && canDoVaginal(domSlave) && subSlave.dick === 0 && domSlave.dick === 0 && fuckTarget > 80) {
 				sex = "vaginal";
 				sex2 = "vaginal";
-				if (canFemImpreg(subSlave, domSlave)) {
-					knockMeUp(subSlave, 3, 0, domSlave.ID);
-				}
+				tryKnockMeUp(subSlave, 3, 0, domSlave);
+				tryKnockMeUp(domSlave, 3, 0, subSlave);
 			} else if (canDoVaginal(subSlave) && subSlave.vagina > 0 && canPenetrate(domSlave) && fuckTarget > 33) {
 				sex = "vaginal";
-				if (canImpreg(subSlave, domSlave)) {
-					knockMeUp(subSlave, 3, 0, domSlave.ID);
-				}
+				tryKnockMeUp(subSlave, 3, 0, domSlave);
 			} else if (canDoAnal(subSlave) && subSlave.anus > 0 && canPenetrate(domSlave) && fuckTarget > 10) {
-				// i think would impregnate from anal here even without .mpreg? same in original widget too
 				sex = "anal";
-				if (canImpreg(subSlave, domSlave) && subSlave.mpreg === 1) {
-					knockMeUp(subSlave, 3, 1, domSlave.ID);
-				}
+				tryKnockMeUp(subSlave, 3, 1, domSlave);
 			} else {
 				sex = "oral";
 			}
diff --git a/src/js/statsChecker/statsChecker.js b/src/js/statsChecker/statsChecker.js
index 00fb514fe546c4c25c495f1d057f7a770ed1018e..45e0681696ce01b6a724d4545ffc957796123928 100644
--- a/src/js/statsChecker/statsChecker.js
+++ b/src/js/statsChecker/statsChecker.js
@@ -479,7 +479,7 @@ globalThis.isPure = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.isVirile = function(slave) {
@@ -1117,7 +1117,7 @@ globalThis.isVegetable = function(slave) {
 /**
  * Returns the hair color the slave was (or would be) born with.
  *
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {string}
  */
 globalThis.getGeneticHairColor = function(slave) {
@@ -1130,7 +1130,7 @@ globalThis.getGeneticHairColor = function(slave) {
 /**
  * Returns the skin color the slave was (or would be) born with.
  *
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {string}
  */
 globalThis.getGeneticSkinColor = function(slave) {
@@ -1141,7 +1141,6 @@ globalThis.getGeneticSkinColor = function(slave) {
 };
 
 /**
- *
  * @param {App.Entity.SlaveState} slave
  * @returns {boolean}
  */
@@ -1172,13 +1171,17 @@ globalThis.milkFlavor = function(slave) {
 	return `${slave.milkFlavor}-flavored `;
 };
 
+/**
+ * @param {FC.HumanState} slave
+ * @returns {boolean}
+ */
 globalThis.canBeDeflowered = function(slave) {
 	return (slave.vagina === 0 && canDoVaginal(slave)) || (slave.anus === 0 && canDoAnal(slave));
 };
 
 /**
  * A consolidated function for checking if an actor is currently aroused.
- * @param {App.Entity.HumanState} actor
+ * @param {FC.HumanState} actor
  * @returns {boolean}
  */
 globalThis.isHorny = function(actor) {
diff --git a/src/js/utilsDOM.js b/src/js/utilsDOM.js
index 9c8b0a10ab35aac4bfe32206f0f371f151a3ab2f..27dc32ec846e18b806b890b087fffc514e23c3c7 100644
--- a/src/js/utilsDOM.js
+++ b/src/js/utilsDOM.js
@@ -87,6 +87,7 @@ App.UI.DOM.link = function(linkText, handler, args = [], passage = "", tooltip =
 	};
 
 	if (tooltip) {
+		link.classList.add("has-tooltip");
 		tippy(link, {
 			content: tooltip,
 		});
diff --git a/src/js/utilsSlave.js b/src/js/utilsSlave.js
index 336c3ec997e80ef7ed4e14719942eb47fe7d8c63..200b1f3d13f84a55ab074b297f69fb5c4dd2acdf 100644
--- a/src/js/utilsSlave.js
+++ b/src/js/utilsSlave.js
@@ -637,6 +637,27 @@ globalThis.Height = (function() {
 		return applyAge(result, age, genes);
 	}
 
+	/**
+	 * @param {{nationality: string, race: FC.Race, genes: string, physicalAge: number, birthWeek: number}} slave
+	 * @param {Partial<heightConfig>} [conf]
+	 * @returns {number}
+	 */
+	function _randomAdultHeight(slave, conf) {
+		const mean = _meanHeight({
+			nationality: slave.nationality,
+			race: slave.race,
+			genes: slave.genes,
+			physicalAge: 20,
+			birthWeek: 0
+		});
+		if (conf) {
+			const localConfig = Object.assign({}, defaultConfig);
+			Object.assign(localConfig, conf);
+			return heightGenerator(localConfig, mean);
+		}
+		return heightGenerator(defaultConfig, mean);
+	}
+
 	/**
 	 * @param {{nationality: string, race: FC.Race, genes: string, physicalAge: number, birthWeek: number}} slave
 	 * @param {Partial<heightConfig>} [conf]
@@ -670,6 +691,7 @@ globalThis.Height = (function() {
 	return {
 		mean: _meanHeight,
 		random: _randomHeight,
+		randomAdult: _randomAdultHeight,
 		forAge: _forAge,
 		config: _config,
 	};
@@ -959,7 +981,8 @@ globalThis.randomCareer = function(slave) {
  * @param {FC.HumanState} slave
  */
 globalThis.resyncSlaveHeight = function(slave) {
-	slave.height = Height.random(slave);
+	slave.natural.height = Height.randomAdult(slave);
+	slave.height = Height.forAge(slave.natural.height, slave);
 };
 
 /**
@@ -1592,6 +1615,9 @@ globalThis.PoliteRudeTitle = function(slave) {
  * @returns {string}
  */
 globalThis.SlaveTitle = function(slave, adjective = true, variability = true) {
+	if (slave.custom.name) {
+		return slave.custom.name;
+	}
 	let r;
 	if (V.newDescriptions === 1) {
 		if (slave.dick > 0 && slave.balls > 0 && slave.boobs > 300 && slave.vagina > -1 && slave.ovaries === 1) {
@@ -2840,7 +2866,7 @@ globalThis.ageSlave = function(slave, forceDevelopment = false) {
 	if (slave.broodmother === 1) {
 		slave.ovaryAge += 0.2;
 	}
-	if (slave.physicalAge <= 18 && (forceDevelopment || V.loliGrow > 0)) {
+	if (slave.physicalAge <= 20 && (forceDevelopment || V.loliGrow > 0)) {
 		App.EndWeek.Shared.physicalDevelopment(slave);
 	}
 };
diff --git a/src/js/wombJS.js b/src/js/wombJS.js
index 00b724f1be45b9a491221b746190508743bfe8eb..b73dbee7883f63c9b65f608ba032b154b296d996 100644
--- a/src/js/wombJS.js
+++ b/src/js/wombJS.js
@@ -101,6 +101,13 @@ globalThis.WombInit = function(actor) {
 				{ID: null, mother: f.genetics.mother, father: f.genetics.father}
 			);
 		}
+		if (!jsDef(f.genetics.artSeed)) {
+			// probably could detect and fix clones/twins here too, but I'm not bothering
+			f.genetics.artSeed = jsRandom(0, 10 ** 14);
+		}
+		if (!jsDef(f.genetics.adultHeight)) {
+			f.genetics.adultHeight = Height.randomAdult({nationality: f.genetics.nationality, race: f.genetics.race, genes: f.genetics.gender, physicalAge: 20, birthWeek: 0});
+		}
 	});
 };
 
@@ -197,6 +204,7 @@ globalThis.WombImpregnateClone = function(actor, fCount, mother, age) {
 		tf.genetics.faceShape = motherOriginal.faceShape;
 		tf.genetics.geneticQuirks = clone(mother.geneticQuirks);
 		tf.genetics.skin = motherOriginal.skin;
+		tf.genetics.artSeed = mother.natural.artSeed;
 
 		try {
 			if (actor.womb.length === 0) {
diff --git a/src/markets/specificMarkets/eliteSlave.js b/src/markets/specificMarkets/eliteSlave.js
index 6aa670ec4e332abd00629a579a06f49410bfb0ce..8e5a2e99f015c4e5cbd8431ad69071cf9c676012 100644
--- a/src/markets/specificMarkets/eliteSlave.js
+++ b/src/markets/specificMarkets/eliteSlave.js
@@ -37,10 +37,11 @@ App.Markets["Elite Slave"] = function() {
 		slave.devotion = random(60, 100);
 		if (!heightPass(slave)) {
 			if (V.arcologies[0].FSPetiteAdmiration > 20) {
-				slave.height = Height.random(slave, {limitMult: [-4, -2]});
+				slave.natural.height = Height.randomAdult(slave, {limitMult: [-4, -2]});
 			} else if (V.arcologies[0].FSStatuesqueGlorification > 20) {
-				slave.height = Height.random(slave, {limitMult: [3, 5]});
+				slave.natural.height = Height.randomAdult(slave, {limitMult: [3, 5]});
 			}
+			slave.height = Height.forAge(slave.natural.height, slave);
 		}
 		if (V.arcologies[0].FSPaternalist > 20) {
 			setHealth(slave, 100, 0, 0, 0, 0);
diff --git a/src/markets/specificMarkets/prestigiousSlave.js b/src/markets/specificMarkets/prestigiousSlave.js
index a14e42781f7810397d086df809c5ef616ba9f524..550f2ffc5854c1f2c8d579865dd10c26783e692a 100644
--- a/src/markets/specificMarkets/prestigiousSlave.js
+++ b/src/markets/specificMarkets/prestigiousSlave.js
@@ -823,7 +823,8 @@ App.Markets["Prestigious Slave"] = function() {
 				slave.prestigeDesc = "$He was once a rising old world politician, but was forced to flee from the increasingly dangerous politics common in a stressed world, and was subsequently enslaved.";
 				slave.career = "a politician";
 				slave.muscles = random(10, 50);
-				slave.height = random(160, 200);
+				slave.natural.height = random(160, 200);
+				slave.height = slave.natural.height;
 				slave.face = Math.clamp(slave.face + 20, -100, 100);
 				slave.faceImplant += 20;
 				slave.faceShape = "masculine";
diff --git a/src/npc/children/ChildState.js b/src/npc/children/ChildState.js
index 67143dd75b9c2b2d8cf92c1a158e5a48068cc606..27388ac6e51c66ecf6dae71c516f1f358999d83a 100644
--- a/src/npc/children/ChildState.js
+++ b/src/npc/children/ChildState.js
@@ -19,6 +19,8 @@ App.Facilities.Nursery.ChildState = class ChildState {
 		this.genes = "XX";
 		/** @type {number} */
 		this.pronoun = App.Data.Pronouns.Kind.female;
+		/** slave's natural genetic properties */
+		this.natural = new App.Entity.GeneticState();
 		/** Game week slave was acquired.
 		 *
 		 * _0: Obtained prior to game start / at game start_ */
diff --git a/src/npc/databases/cheatmodeDatabase.js b/src/npc/databases/cheatmodeDatabase.js
index 919e7945e8a89d1bed3f022b79ac50c43de58777..60baa3766077f2b116ee705b27c84e124dc35c69 100644
--- a/src/npc/databases/cheatmodeDatabase.js
+++ b/src/npc/databases/cheatmodeDatabase.js
@@ -23,6 +23,7 @@ App.Intro.cheatModeSlaves = function() {
 	setHealth(cheatSlave, 50);
 	cheatSlave.devotion = 100;
 	cheatSlave.nationality = "Stateless";
+	cheatSlave.natural.height = 175;
 	cheatSlave.height = 175;
 	cheatSlave.race = "white";
 	cheatSlave.eye.origColor = "green";
@@ -92,6 +93,7 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.devotion = 100;
 	cheatSlave.nationality = "Stateless";
 	cheatSlave.muscles = 20;
+	cheatSlave.natural.height = 190;
 	cheatSlave.height = 190;
 	cheatSlave.race = "black";
 	cheatSlave.origHColor = "black";
@@ -161,6 +163,7 @@ App.Intro.cheatModeSlaves = function() {
 	setHealth(cheatSlave, 10);
 	cheatSlave.devotion = 60;
 	cheatSlave.nationality = "Stateless";
+	cheatSlave.natural.height = 175;
 	cheatSlave.height = 175;
 	cheatSlave.race = "black";
 	cheatSlave.pubicHColor = "black";
@@ -227,6 +230,7 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.devotion = 60;
 	cheatSlave.nationality = "Stateless";
 	cheatSlave.muscles = 50;
+	cheatSlave.natural.height = 190;
 	cheatSlave.height = 190;
 	cheatSlave.race = "black";
 	cheatSlave.origHColor = "black";
@@ -299,6 +303,7 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.devotion = 30;
 	cheatSlave.nationality = "Stateless";
 	cheatSlave.muscles = 50;
+	cheatSlave.natural.height = 175;
 	cheatSlave.height = 175;
 	cheatSlave.race = "white";
 	cheatSlave.eye.origColor = "green";
@@ -359,6 +364,7 @@ App.Intro.cheatModeSlaves = function() {
 	cheatSlave.devotion = 60;
 	cheatSlave.nationality = "Stateless";
 	cheatSlave.muscles = 50;
+	cheatSlave.natural.height = 190;
 	cheatSlave.height = 190;
 	cheatSlave.race = "black";
 	cheatSlave.origHColor = "black";
diff --git a/src/npc/descriptions/crotch/vagina.js b/src/npc/descriptions/crotch/vagina.js
index 3d2bbe3a17896d726f5ca655651fe7526543140f..1faf7ad00d5e7063ef9e36ad8c285a2f4d940339 100644
--- a/src/npc/descriptions/crotch/vagina.js
+++ b/src/npc/descriptions/crotch/vagina.js
@@ -66,7 +66,9 @@ App.Desc.vagina = function(slave) {
 		}
 
 		if (V.seeRace === 1) {
-			if (slave.race === "white") {
+			if (slave.geneticQuirks.albinism === 2) {
+				r.push(`${slave.albinismOverride.skin} pussylips.`);
+			} else if (slave.race === "white") {
 				r.push(`pink pussylips.`);
 			} else if (slave.race === "asian") {
 				r.push(`dark ${slave.race} pussylips.`);
diff --git a/src/npc/descriptions/limbs.js b/src/npc/descriptions/limbs.js
index e35ec86d77acd0f2d91d6babdfd350a15218edef..4eb79fa4095e84bb653d914b2ec8b0b624401b8a 100644
--- a/src/npc/descriptions/limbs.js
+++ b/src/npc/descriptions/limbs.js
@@ -59,6 +59,9 @@ App.Medicine.Limbs.selector = function(slave, oldLimbs) {
 	App.UI.DOM.appendNewElement("div", limbSelector, "Right Arm");
 	App.UI.DOM.appendNewElement("div", limbSelector, "Left Leg");
 	App.UI.DOM.appendNewElement("div", limbSelector, "Right Leg");
+	App.UI.DOM.appendNewElement("div", limbSelector, "All");
+
+	const radiosAll = [];
 
 	limbSelector.append(row("None", 0));
 	App.Data.prostheticLimbs.forEach((limb, key) => {
@@ -67,7 +70,8 @@ App.Medicine.Limbs.selector = function(slave, oldLimbs) {
 				limbSelector.append(row(capFirstChar(limb.short), key));
 			} else {
 				App.UI.DOM.appendNewElement("div", limbSelector,
-					`You need to upgrade ${his} prosthetic interface to attach ${limb.short} limbs.`, ["full", "detail"]);
+					`You need to upgrade ${his} prosthetic interface to attach ${limb.short} limbs.`, ["full",
+						"detail"]);
 			}
 		}
 	});
@@ -91,30 +95,6 @@ App.Medicine.Limbs.selector = function(slave, oldLimbs) {
 		return [getLeftArmID(slave), getRightArmID(slave), getLeftLegID(slave), getRightLegID(slave)];
 	}
 
-	/**
-	 * @param {number} limb
-	 * @param {number} id
-	 * @returns {HTMLDivElement}
-	 */
-	function radio(limb, id) {
-		const div = document.createElement("div");
-
-		if (newState[limb] !== 1) {
-			const radio = document.createElement("input");
-			radio.type = "radio";
-			radio.name = "limb" + limb;
-			if (newState[limb] === id) {
-				radio.checked = true;
-			}
-			radio.onclick = () => {
-				newState[limb] = id;
-			};
-			div.append(radio);
-		}
-
-		return div;
-	}
-
 	/**
 	 * @param {string} title
 	 * @param {number} id
@@ -125,10 +105,47 @@ App.Medicine.Limbs.selector = function(slave, oldLimbs) {
 
 		App.UI.DOM.appendNewElement("div", f, title);
 
+		const radios = [];
 		for (let i = 0; i < newState.length; i++) {
-			f.append(radio(i, id));
+			const div = document.createElement("div");
+
+			if (newState[i] !== 1) {
+				const radio = document.createElement("input");
+				radios.push(radio);
+				radio.type = "radio";
+				radio.name = "limb" + i;
+				if (newState[i] === id) {
+					radio.checked = true;
+				}
+				radio.onclick = () => {
+					newState[i] = id;
+					radiosAll.forEach(r => r.checked = false);
+				};
+				div.append(radio);
+			}
+
+			f.append(div);
 		}
 
+		const div = document.createElement("div");
+
+		const radio = document.createElement("input");
+		radiosAll.push(radio);
+		radio.type = "radio";
+		radio.name = "limb_all";
+		radio.checked = newState.reduce((acc, cur) => acc && (cur === 1 || cur === id), true);
+		radio.onclick = () => {
+			for (let i = 0; i < newState.length; i++) {
+				if (newState[i] !== 1) {
+					newState[i] = id;
+				}
+				radios.forEach(r => r.checked = true);
+			}
+		};
+		div.append(radio);
+
+		f.append(div);
+
 		return f;
 	}
 
diff --git a/src/npc/generate/generateGenetics.js b/src/npc/generate/generateGenetics.js
index 23cfcc48ee84e04852ca241c906600af580bfbbe..1a0a13c3deb543042bb233d49b9529b204adc229 100644
--- a/src/npc/generate/generateGenetics.js
+++ b/src/npc/generate/generateGenetics.js
@@ -49,7 +49,9 @@ globalThis.generateGenetics = (function() {
 			cloneID: 0,
 			geneticQuirks: {},
 			fetish: "none",
-			spermY: 50
+			spermY: 50,
+			adultHeight: 170,
+			artSeed: jsRandom(0, 10 ** 14)
 		};
 		if (actor1.ID > 0) {
 			mother = V.genePool.find(s => s.ID === actor1.ID);
@@ -109,10 +111,40 @@ globalThis.generateGenetics = (function() {
 		genes.behavioralFlaw = setBehavioralFlaw(father, mother);
 		genes.fetish = setFetish(father, mother);
 		genes.spermY = setSpermY(father, mother);
+		genes.adultHeight = setAdultHeight(father, mother, genes.gender, genes.race, genes.nationality, genes.geneticQuirks);
 
 		return genes;
 	}
 
+	/** set expected adult height for the fetus
+	 * @param {FC.Zeroable<FC.HumanState>} father
+	 * @param {FC.HumanState} mother
+	 * @param {string} gender
+	 * @param {FC.Race} race
+	 * @param {string} nationality
+	 * @param {Partial<FC.GeneticQuirks>} quirks
+	 * @returns {number}
+	 */
+	function setAdultHeight(father, mother, gender, race, nationality, quirks) {
+		const randomPart = Height.random({nationality, race, genes: gender, physicalAge: 20, birthWeek: 0});
+		if ((quirks.dwarfism === 2) !== (mother.geneticQuirks.dwarfism === 2) ||
+			(quirks.gigantism === 2) !== (mother.geneticQuirks.gigantism === 2) ||
+			father && ((quirks.dwarfism === 2) !== (father.geneticQuirks.dwarfism === 2)) ||
+			father && ((quirks.gigantism === 2) !== (father.geneticQuirks.gigantism === 2))) {
+			// we have a height quirk change compared to one of our parents.  better to just start over with a completely random target height.
+			return randomPart;
+		}
+		// global average: men are 7% taller than women. natural heights contain this bias.
+		const genderScalingFactor = 1.07;
+		// heritance ratio for height in humans is currently estimated at 79% (Yengo, L., Vedantam, S., Marouli, E., et al. "A saturated map of common genetic variants associated with human height." Nature 610, 704–712 (2022))
+		const heritanceRatio = 0.79;
+		// assemble!
+		const motherPart = mother.natural.height * (gender === "XX" ? 1.0 : genderScalingFactor);
+		const fatherPart = father ? father.natural.height * (gender === "XY" ? 1.0 : (1 / genderScalingFactor)) : motherPart;
+		const inheritedPart = (motherPart + fatherPart) * 0.5;
+		return Math.round((heritanceRatio * inheritedPart) + ((1 - heritanceRatio) * randomPart));
+	}
+
 	// get spermY value of the parent that's donating the Y chromosome
 	function getSpermY(father, mother) {
 		let sourceSpermY = 50; // default if no inherited Y chromosome (should be impossible, but the Adam Principle is optional, so it can happen)
@@ -1088,6 +1120,7 @@ globalThis.generateGenetics = (function() {
  * @returns {App.Entity.SlaveState|App.Facilities.Nursery.InfantState}
  */
 globalThis.generateChild = function(mother, ovum, incubator = false) {
+	/** @type {FC.FetusGenetics} */
 	let genes = ovum.genetics; // TODO: maybe just argument this? We'll see.
 	let child;
 
@@ -1129,6 +1162,7 @@ globalThis.generateChild = function(mother, ovum, incubator = false) {
 		child.skin = getGeneticSkinColor(child);
 		child.hColor = getGeneticHairColor(child);
 		child.spermY = genes.spermY;
+		child.natural.height = genes.adultHeight;
 		child.pubicHColor = child.hColor;
 		child.underArmHColor = child.hColor;
 		child.eyebrowHColor = child.hColor;
@@ -1219,6 +1253,7 @@ globalThis.generateChild = function(mother, ovum, incubator = false) {
 			child.tailColor = child.hColor;
 		}
 		child.spermY = genes.spermY;
+		child.natural.height = genes.adultHeight;
 		resetEyeColor(child, "both");
 		child.pubicHColor = child.hColor;
 		child.underArmHColor = child.hColor;
diff --git a/src/npc/generate/generateLeadershipSlave.js b/src/npc/generate/generateLeadershipSlave.js
index 4862b4c8e606e6cac00c10e7cd500c840fcaa3f5..0f395edb91ab4d2af8cba9d71e6bea106e2b267f 100644
--- a/src/npc/generate/generateLeadershipSlave.js
+++ b/src/npc/generate/generateLeadershipSlave.js
@@ -66,7 +66,8 @@ globalThis.generateLeadershipSlave = function(input, location) {
 			slave.devotion = jsRandom(51, 85);
 			slave.trust = jsRandom(51, 85);
 			slave.muscles = jsRandom(30, 70);
-			slave.height = Height.random(slave, {skew: 3, spread: .2, limitMult: [1, 4]});
+			slave.natural.height = Height.randomAdult(slave, {skew: 3, spread: .2, limitMult: [1, 4]});
+			slave.height = Height.forAge(slave.natural.height, slave);
 			slave.weight = jsRandom(-10, 10);
 			slave.teeth = either("normal", "pointy");
 			slave.skill.combat = 70;
@@ -164,7 +165,8 @@ globalThis.generateLeadershipSlave = function(input, location) {
 			slave.muscles = jsRandom(41, 70);
 			slave.sexualQuirk = "caring";
 			slave.weight = jsRandom(0, 30);
-			slave.height = Height.random(slave, {skew: 3, spread: .2, limitMult: [1, 4]});
+			slave.natural.height = Height.randomAdult(slave, {skew: 3, spread: .2, limitMult: [1, 4]});
+			slave.height = Height.forAge(slave.natural.height, slave);
 			applyMaleGenitalia({dick: jsRandom(3, 5), balls: jsRandom(4, 9), prostate: either(1, 1, 1, 2)});
 			slave.career = either(App.Data.Careers.Leader.farmer);
 			break;
diff --git a/src/npc/generate/generateMarketSlave.js b/src/npc/generate/generateMarketSlave.js
index f832896ffd6d4d74b6468f5d25b369701ecad0a7..c9e58b45201bb493d9d518c050286da582b051d6 100644
--- a/src/npc/generate/generateMarketSlave.js
+++ b/src/npc/generate/generateMarketSlave.js
@@ -112,7 +112,8 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 					r += `The corporation specifically targets incredibly tall slaves. `;
 					maxMult = 5; // do not limit tallness
 				}
-				slave.height = Height.random(slave, {skew: V.corp.SpecHeight - 3, limitMult: [minMult, maxMult]});
+				slave.natural.height = Height.randomAdult(slave, {skew: V.corp.SpecHeight - 3, limitMult: [minMult, maxMult]});
+				slave.height = Height.forAge(slave.natural.height, slave);
 			}
 			if (V.corp.SpecVirgin === 1) {
 				r += `The corporation ensures its slaves are virgins. `;
@@ -465,7 +466,7 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 		}
 		case "neighbor": {
 			const neighborID = (typeof V.arcologies[numArcology] === 'object') ? numArcology : 1;
-			const neighbor = V.arcologies[neighborID];
+			const neighbor = /** @type {FC.ArcologyState} */V.arcologies[neighborID];
 			const opinion = Math.clamp(Math.trunc(App.Neighbor.opinion(V.arcologies[0], neighbor) / 20), -10, 10);
 
 			/**
@@ -495,7 +496,18 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 			slave.origin += ".";
 			slave.devotion = -20 + Math.trunc(neighbor.prosperity / 10) + jsRandom(0, 10);
 			slave.trust = -20 + Math.trunc(neighbor.prosperity / 10) + jsRandom(0, 10);
-			setHealth(slave, -50 + Math.trunc(neighbor.prosperity / 25) + jsRandom(0, 5), Math.max(15 - neighbor.prosperity / 20 + normalRandInt(0, 2), 0), Math.max(15 - neighbor.prosperity / 20 + normalRandInt(0, 2), 0), undefined, Math.max(jsRandom(10, 40) - neighbor.prosperity / 15, 10));
+			let healthTarget = 0;
+			if (neighbor.FSPaternalist !== "unset") {
+				healthTarget = 20;
+			} else if (neighbor.FSDegradationist !== "unset") {
+				healthTarget = -20;
+			}
+			healthTarget += Math.trunc((neighbor.prosperity - 100) / 10) + jsRandom(0, 10);
+			setHealth(slave, healthTarget, // min: -50, max: -33
+				Math.max(15 - neighbor.prosperity / 20 + normalRandInt(0, 2), 0), // min: 0, max: 21
+				Math.max(15 - neighbor.prosperity / 20 + normalRandInt(0, 2), 0), // min: 0, max: 21
+				undefined,
+				Math.max(jsRandom(10, 40) - neighbor.prosperity / 15, 10)); // min: 10, max: 40
 			if (jsRandom(1, 100) < neighbor.prosperity / 10 + 50) {
 				slave.health.illness = 0;
 			}
@@ -854,27 +866,29 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 			}
 			if (neighbor.FSPetiteAdmiration > 20) {
 				r += `They tend to be short, some far more than others. `;
-				if (slave.height >= Height.forAge(160, slave)) {
-					slave.height = Height.random(slave, {limitMult: [-2, 0]});
-					if (slave.height >= Height.forAge(160, slave)) {
-						slave.height = Height.random(slave, {limitMult: [-3, -1]});
-						if (slave.height >= Height.forAge(160, slave)) {
-							slave.height = Height.forAge(jsRandom(90, 130), slave);
+				if (slave.natural.height >= 160) {
+					slave.natural.height = Height.random(slave, {limitMult: [-2, 0]});
+					if (slave.natural.height >= 160) {
+						slave.natural.height = Height.random(slave, {limitMult: [-3, -1]});
+						if (slave.natural.height >= 160) {
+							slave.natural.height = jsRandom(90, 130);
 							slave.geneticQuirks.dwarfism = 2;
 						}
 					}
+					slave.height = Height.forAge(slave.natural.height, slave);
 				}
 			} else if (neighbor.FSStatuesqueGlorification > 20) {
 				r += `They tend to be tall, if not unbelievably so. `;
-				if (slave.height < Height.forAge(170, slave)) {
-					slave.height = Height.random(slave, {limitMult: [0, 2]});
-					if (slave.height < Height.forAge(170, slave)) {
-						slave.height = Height.random(slave, {limitMult: [1, 3]});
-						if (slave.height < Height.forAge(170, slave)) {
-							slave.height = Height.forAge(jsRandom(200, 264), slave);
+				if (slave.natural.height < 170) {
+					slave.natural.height = Height.random(slave, {limitMult: [0, 2]});
+					if (slave.natural.height < 170) {
+						slave.natural.height = Height.random(slave, {limitMult: [1, 3]});
+						if (slave.natural.height < 170) {
+							slave.natural.height = jsRandom(200, 264);
 							slave.geneticQuirks.gigantism = 2;
 						}
 					}
+					slave.height = Height.forAge(slave.natural.height, slave);
 				}
 			}
 			if (neighbor.FSSlimnessEnthusiast > 20) {
@@ -1593,7 +1607,7 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 			} else {
 				setHealth(slave, jsRandom(-50, 100), Math.max(normalRandInt(0, 4), 0), Math.max(normalRandInt(10, 4), 0), Math.max(normalRandInt(0, 0.5), 0), jsRandom(10, 20));
 			}
-			slave.height = jsRandom(160, 210);
+			slave.height = Math.max(jsRandom(160, 210), slave.natural.height);
 			slave.butt = jsRandom(4, 10);
 			if (V.GRI.schoolUpgrade === 2) {
 				slave.boobs = 200 * jsRandom(15, 30);
@@ -2221,15 +2235,16 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 			setHealth(slave, jsRandom(60, 80), 0, Math.max(normalRandInt(0, 2), 0), 0, jsRandom(5, 20));
 			const minHeight = jsRandom(170, 180);
 			if (V.HA.schoolUpgrade === 2) {
-				slave.height = Math.clamp(Height.random(slave, {
+				slave.natural.height = Math.clamp(Height.random(slave, {
 					limitMult: [2, 15],
 					spread: 0.1
 				}), minHeight, 274);
 				slave.muscles = jsRandom(40, 80);
 			} else {
-				slave.height = Math.clamp(Height.random(slave, {limitMult: [1, 4]}), minHeight, 274);
+				slave.natural.height = Math.clamp(Height.random(slave, {limitMult: [1, 4]}), minHeight, 274);
 				slave.muscles = jsRandom(20, 40);
 			}
+			slave.height = slave.natural.height;
 			if (V.HA.schoolUpgrade === 3) {
 				slave.weight = jsEither([10, 20, 20, 30, 30, 40, 40, 50]);
 				slave.waist = jsRandom(-10, 40);
diff --git a/src/npc/generate/generateNewSlaveJS.js b/src/npc/generate/generateNewSlaveJS.js
index 771360302c3b98d907ea80a006f9073c03eb3f18..da75bca2f209edc8d3f0c424f8025d3f229bef62 100644
--- a/src/npc/generate/generateNewSlaveJS.js
+++ b/src/npc/generate/generateNewSlaveJS.js
@@ -167,12 +167,13 @@ globalThis.GenerateNewSlave = (function() {
 
 	function generateXXBodyProportions() {
 		if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2) {
-			slave.height = Height.random(slave, {limitMult: [-4, -1], spread: 0.15});
+			slave.natural.height = Height.randomAdult(slave, {limitMult: [-4, -1], spread: 0.15});
 		} else if (slave.geneticQuirks.gigantism === 2) {
-			slave.height = Height.random(slave, {limitMult: [3, 10], spread: 0.15});
+			slave.natural.height = Height.randomAdult(slave, {limitMult: [3, 10], spread: 0.15});
 		} else {
-			slave.height = Height.random(slave);
+			slave.natural.height = Height.randomAdult(slave);
 		}
+		slave.height = Height.forAge(slave.natural.height, slave);
 		if (slave.height >= Height.mean(slave) * 170 / 162.5) {
 			slave.hips = jsEither([-1, 0, 0, 1, 1, 2, 2]);
 			slave.shoulders = jsEither([-1, -1, 0, 0, 0, 1]);
@@ -200,12 +201,13 @@ globalThis.GenerateNewSlave = (function() {
 
 	function generateXYBodyProportions() {
 		if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2) {
-			slave.height = Height.random(slave, {limitMult: [-4, -1], spread: 0.15});
+			slave.natural.height = Height.randomAdult(slave, {limitMult: [-4, -1], spread: 0.15});
 		} else if (slave.geneticQuirks.gigantism === 2) {
-			slave.height = Height.random(slave, {limitMult: [3, 10], spread: 0.15});
+			slave.natural.height = Height.randomAdult(slave, {limitMult: [3, 10], spread: 0.15});
 		} else {
-			slave.height = Height.random(slave);
+			slave.natural.height = Height.randomAdult(slave);
 		}
+		slave.height = Height.forAge(slave.natural.height, slave);
 		if (slave.physicalAge <= 13) {
 			if (slave.height > Height.mean(slave) * 170 / 172.5) {
 				slave.hips = jsEither([-2, -1, -1, 0, 1]);
diff --git a/src/npc/generate/generateRelatedSlave.js b/src/npc/generate/generateRelatedSlave.js
index 9d9dd98adf8b36bd1322f6c37f06b1c293c1989b..95fc244f2afdb0b548cfc2c6518feb610c8724c9 100644
--- a/src/npc/generate/generateRelatedSlave.js
+++ b/src/npc/generate/generateRelatedSlave.js
@@ -260,6 +260,12 @@ globalThis.generateRelatedSlave = (function() {
 		if (slave.butt > 1) {
 			slave.butt += random(-1, 1);
 		}
+		// fuzz height
+		const heightAdjust = random(-5, Math.min(maxHeight(slave) - slave.height, 5));
+		slave.natural.height += heightAdjust;
+		slave.height += heightAdjust;
+		// reset art seed
+		slave.natural.artSeed = jsRandom(0, 10 ** 14);
 	}
 
 	/**
@@ -290,7 +296,7 @@ globalThis.generateRelatedSlave = (function() {
 		}
 
 		// reset height
-		slave.height = Height.random(slave);
+		slave.height = Height.forAge(slave.natural.height, slave);
 
 		// reset puberty status
 		generatePuberty(slave);
diff --git a/src/npc/generate/heroCreator.js b/src/npc/generate/heroCreator.js
index 8ebe65004b82ad359a02823b5714ce7a977c845b..b742630504754e62afd042dd5095b81cadc6539b 100644
--- a/src/npc/generate/heroCreator.js
+++ b/src/npc/generate/heroCreator.js
@@ -100,10 +100,10 @@ App.Utils.getHeroSlave = function(heroSlave) {
 	repairLimbs(newSlave);
 	generatePuberty(newSlave);
 	newSlave.weekAcquired = V.week;
-	if (!newSlave.pubicHColor) {
+	if (!heroSlave.pubicHColor) {
 		newSlave.pubicHColor = newSlave.hColor;
 	}
-	if (!newSlave.underArmHColor) {
+	if (!heroSlave.underArmHColor) {
 		newSlave.underArmHColor = newSlave.hColor;
 	}
 	if (newSlave.override_Race !== 1) {
@@ -127,6 +127,13 @@ App.Utils.getHeroSlave = function(heroSlave) {
 	if (newSlave.override_Skin !== 1) {
 		newSlave.skin = getGeneticSkinColor(newSlave);
 	}
+	if (!heroSlave.natural?.height) {
+		// assumes adult - child hero slaves MUST specify natural height separately!
+		newSlave.natural.height = newSlave.height - newSlave.heightImplant * 10;
+	}
+	if (!heroSlave.natural?.artSeed) {
+		newSlave.natural.artSeed = jsRandom(0, 10 ** 14);
+	}
 	setHealth(newSlave, newSlave.health.condition, 0, 0, 0, newSlave.health.tired);
 
 	SetBellySize(newSlave);
diff --git a/src/npc/generate/lawCompliance.js b/src/npc/generate/lawCompliance.js
index 678f80f708a33ca90d993a71cd6d51acec43157b..4cdf13f6feb2763012bb0748babc6d9cfd2a0191 100644
--- a/src/npc/generate/lawCompliance.js
+++ b/src/npc/generate/lawCompliance.js
@@ -323,14 +323,16 @@ App.Desc.lawCompliance = function(slave, market = 0) {
 
 	function FSPetiteAdmirationSMR() {
 		if (!heightPass(slave)) {
-			slave.height = Height.random(slave, {skew: -1, limitMult: [-5, -2]});
+			slave.natural.height = Height.randomAdult(slave, {skew: -1, limitMult: [-5, -2]});
+			slave.height = Height.forAge(slave.natural.height, slave);
 		}
 		return `${His} height was meticulously taken before being allowed into the markets.`;
 	}
 
 	function FSStatuesqueGlorificationSMR() {
 		if (!heightPass(slave)) {
-			slave.height = Height.random(slave, {skew: 1, limitMult: [2, 5]});
+			slave.natural.height = Height.randomAdult(slave, {skew: 1, limitMult: [2, 5]});
+			slave.height = Height.forAge(slave.natural.height, slave);
 		}
 		return `${His} height, as well as ${his} potential for growth, were meticulously taken before being allowed into the markets.`;
 	}
@@ -680,10 +682,11 @@ App.Desc.lawCompliance = function(slave, market = 0) {
 	}
 
 	function heightAdvancedSMRup() {
-		slave.height = Height.random(slave, {
+		slave.natural.height = Height.randomAdult(slave, {
 			skew: V.policies.SMR.height.advancedSMR,
 			limitMult: [0, 5 * V.policies.SMR.height.advancedSMR]
 		});
+		slave.height = Height.forAge(slave.natural.height, slave);
 		let t = [`While ${he} was in the slave pens, ${he} saw that slaves on the shorter end of the height curve were immediately designated as menials and Fuckdolls.`];
 		if (slave.physicalAge < 16) {
 			t.push(`${He} is <span class="gold">terrified</span> that if ${he} doesn't keep growing, ${he}'ll be reassigned on the spot without a second thought.`);
@@ -696,10 +699,11 @@ App.Desc.lawCompliance = function(slave, market = 0) {
 	}
 
 	function heightAdvancedSMRdown() {
-		slave.height = Height.random(slave, {
+		slave.natural.height = Height.randomAdult(slave, {
 			skew: V.policies.SMR.height.advancedSMR,
 			limitMult: [0, 5 * V.policies.SMR.height.advancedSMR]
 		});
+		slave.height = Height.forAge(slave.natural.height, slave);
 		let t = [`While ${he} was in the slave pens, ${he} saw that slaves on the taller end of the height curve were immediately designated as menials and Fuckdolls.`];
 		if (slave.physicalAge < 16) {
 			t.push(`${He} is <span class="gold">terrified</span> that if ${he} goes through a growth spurt, ${he}'ll be reassigned on the spot without a second thought.`);
diff --git a/src/npc/generate/newSlaveIntro.js b/src/npc/generate/newSlaveIntro.js
index 36e2588fccc92080929ae4bec9d299347267c074..a08c7e4705dec110762e15f04de4c21903bc9eb0 100644
--- a/src/npc/generate/newSlaveIntro.js
+++ b/src/npc/generate/newSlaveIntro.js
@@ -1089,7 +1089,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 							slave.trust -= 10;
 							return r.join(" ");
 						},
-						get requirements() { return (canDoAnal(slave)); }
+						get requirements() {
+							return (canDoAnal(slave));
+						}
 					});
 					choice({
 						linkName: `Cruelly castrate ${him}`,
@@ -1116,7 +1118,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 							App.Events.refreshEventArt(slave);
 							return r.join(" ");
 						},
-						get requirements() { return ((slave.indentureRestrictions <= 0) && (V.seeExtreme === 1)); }
+						get requirements() {
+							return ((slave.indentureRestrictions <= 0) && (V.seeExtreme === 1));
+						}
 					});
 					break;
 				case "$He asked to be enslaved out of naïve infatuation with you.":
@@ -1155,7 +1159,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 							return r.join(" ");
 						},
 
-						get requirements() { return (canDoAnal(slave) || canDoVaginal(slave)); }
+						get requirements() {
+							return (canDoAnal(slave) || canDoVaginal(slave));
+						}
 					});
 					choice({
 						linkName: `Make sure ${he} knows ${he} made a mistake`,
@@ -1179,7 +1185,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 							slave.trust -= 10;
 							return r.join(" ");
 						},
-						get requirements() { return (canDoAnal(slave)); }
+						get requirements() {
+							return (canDoAnal(slave));
+						}
 					});
 					break;
 				case "$He asked to be enslaved in the hope you'd treat a fellow woman well.":
@@ -1251,7 +1259,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 							slave.trust += 10;
 							return r.join(" ");
 						},
-						get requirements() { return canDoAnal(slave); }
+						get requirements() {
+							return canDoAnal(slave);
+						}
 					});
 					break;
 				case "$He was transformed and enslaved after $he fell into debt to you.":
@@ -1282,7 +1292,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 							slave.anus = 1;
 							return r.join(" ");
 						},
-						get requirements() { return (canDoAnal(slave)); }
+						get requirements() {
+							return (canDoAnal(slave));
+						}
 					});
 					break;
 				case "$He offered $himself to you as a slave to escape a life of boredom.":
@@ -1303,7 +1315,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 							slave.anus = 1;
 							return r.join(" ");
 						},
-						get requirements() { return (canDoAnal(slave)); }
+						get requirements() {
+							return (canDoAnal(slave));
+						}
 					});
 					break;
 				case "$He sold $himself into slavery out of fear that life on the streets was endangering $his pregnancy.":
@@ -1330,7 +1344,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 							slave.anus = 1;
 							return r.join(" ");
 						},
-						get requirements() { return (canDoAnal(slave)); }
+						get requirements() {
+							return (canDoAnal(slave));
+						}
 					});
 					break;
 				case "$He offered $himself to you as a slave to escape the hard life of a free whore.":
@@ -2799,7 +2815,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 			if (slave.vagina === 0) {
 				choice({
 					// TODO: tankBorn
-					get linkName() { return (tankBorn) ? `Take ${his} virginity` : `Tie ${him} up and take ${his} virginity`; },
+					get linkName() {
+						return (tankBorn) ? `Take ${his} virginity` : `Tie ${him} up and take ${his} virginity`;
+					},
 					result(slave) {
 						const r = [];
 						if (tankBorn) {
@@ -3367,7 +3385,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 				}
 				if (PC.vagina !== -1 && slave.dick > 0 && canAchieveErection(slave)) {
 					choice({
-						get linkName() { return (tankBorn) ? `Dominate ${his} penis` : `Dominate ${his} penis and demonstrate ${his} place`; },
+						get linkName() {
+							return (tankBorn) ? `Dominate ${his} penis` : `Dominate ${his} penis and demonstrate ${his} place`;
+						},
 						result(slave) {
 							const el = new DocumentFragment();
 							let r = [];
@@ -3529,7 +3549,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 				if (PC.belly >= 3000 && hasAnyArms(slave)) {
 					choice({
 						// TODO: tankBorn
-						get linkName() { return (tankBorn) ? `Permit ${him} to explore your pregnancy` : `Make ${him} worship your pregnancy`; },
+						get linkName() {
+							return (tankBorn) ? `Permit ${him} to explore your pregnancy` : `Make ${him} worship your pregnancy`;
+						},
 						result(slave) {
 							const r = [];
 							if (tankBorn) {
@@ -3590,7 +3612,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 						if (PC.pregMood === 2 && PC.vagina > 0 && canPenetrate(slave)) {
 							choice({
 								// TODO: tankBorn
-								get linkName() { return (tankBorn) ? `Teach ${him} how to satisfy a pregnant ${womanP}` : `${He} has a dick and you need it`; },
+								get linkName() {
+									return (tankBorn) ? `Teach ${him} how to satisfy a pregnant ${womanP}` : `${He} has a dick and you need it`;
+								},
 								result(slave) {
 									const r = [];
 									if (tankBorn) {
@@ -3777,7 +3801,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 					if (PC.boobs >= 800 && slave.boobs <= PC.boobs - 200 && slave.boobs >= 300) {
 						choice({
 							// TODO: tankBorn
-							get linkName() { return (tankBorn) ? `Permit ${him} to explore your expansive bust` : `Let your ample bust dominate ${his} pathetic one`; },
+							get linkName() {
+								return (tankBorn) ? `Permit ${him} to explore your expansive bust` : `Let your ample bust dominate ${his} pathetic one`;
+							},
 							result(slave) {
 								const el = new DocumentFragment();
 								let r = [];
@@ -4909,7 +4935,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 					}
 				}
 				if (slave.boobs >= 1000 && V.arcologies[0].FSTransformationFetishistResearch === 1) {
-					linkArray.push(
+					linkArray.push(optionWithNote(
 						App.UI.DOM.link(
 							`Implant a heaving pair of 4000cc fillable implants in ${his} chest`,
 							() => {
@@ -4936,13 +4962,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								}
 								r.push(`${his} new ridiculous fake tits. ${He}'s <span class="hotpink">deliriously happy</span> that ${he} has ${his} own pair of giant breasts hanging from ${his} stretched chest and <span class="mediumaquamarine">hopes</span> you have plans to make them even bigger, even though ${he} is already struggling to keep upright. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 								jQuery("#introResult").empty().append(r.join(" "));
-							},
-							[],
-							"",
-							`This option costs ${cashFormat(V.surgeryCost)}`
-						)
-					);
-					linkArray.push(
+							}), `This option costs ${cashFormat(V.surgeryCost)}`
+					));
+					linkArray.push(optionWithNote(
 						App.UI.DOM.link(
 							`Implant a pair of engorged 7500cc string implants in ${his} chest`,
 							() => {
@@ -4975,14 +4997,10 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								}
 								r.push(`they'll keep growing, despite ${his} near inability to stay upright. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 								jQuery("#introResult").empty().append(r.join(" "));
-							},
-							[],
-							"",
-							`This option costs ${cashFormat(V.surgeryCost)}`
-						)
-					);
+							}), `This option costs ${cashFormat(V.surgeryCost)}`
+					));
 				} else if (slave.boobs < 1000) {
-					linkArray.push(
+					linkArray.push(optionWithNote(
 						App.UI.DOM.link(
 							`Implant a pair of 1000cc fillable implants in ${his} chest`,
 							() => {
@@ -5009,14 +5027,10 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								}
 								r.push(`${his} new fake balloons. ${He}'s <span class="hotpink">deliriously happy</span> that ${he} has ${his} own pair of big breasts hanging from ${his} chest and <span class="mediumaquamarine">hopes</span> you have plans to make them even bigger. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 								jQuery("#introResult").empty().append(r.join(" "));
-							},
-							[],
-							"",
-							`This option costs ${cashFormat(V.surgeryCost)}`
-						)
-					);
+							}), `This option costs ${cashFormat(V.surgeryCost)}`
+					));
 
-					linkArray.push(
+					linkArray.push(optionWithNote(
 						App.UI.DOM.link(
 							`Implant a heavy pair of 1500cc string implants in ${his} chest`,
 							() => {
@@ -5049,12 +5063,8 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								}
 								r.push(`they'll keep growing. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 								jQuery("#introResult").empty().append(r.join(" "));
-							},
-							[],
-							"",
-							`This option costs ${cashFormat(V.surgeryCost)}`
-						)
-					);
+							}), `This option costs ${cashFormat(V.surgeryCost)}`
+					));
 				} else {
 					r.push(
 						App.UI.DOM.makeElement("span", `${His} breasts are already so large that basic implants will not have a noticeable enough effect to sate ${his} curiosity.`)
@@ -5101,7 +5111,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 					);
 				}
 				if (V.arcologies[0].FSTransformationFetishistResearch === 1) {
-					linkArray.push(
+					linkArray.push(optionWithNote(
 						App.UI.DOM.link(
 							`Put ${him} into a medical coma and implant a 200000cc belly implant in ${his} abdomen`,
 							() => {
@@ -5127,14 +5137,10 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								}
 								r.push(`you can make it bigger, despite the fact that it is nearly as large as ${he} is and pins ${him} to the bed ${he} lies upon. As it was an invasive surgery, <span class="health dec">${his} health has been greatly affected.</span>`);
 								jQuery("#introResult").empty().append(r.join(" "));
-							},
-							[],
-							"",
-							`This option costs ${cashFormat(V.surgeryCost)}`
-						)
-					);
+							}), `This option costs ${cashFormat(V.surgeryCost)}`
+					));
 				}
-				linkArray.push(
+				linkArray.push(optionWithNote(
 					App.UI.DOM.link(
 						`Implant a 2000cc belly implant in ${his} abdomen`,
 						() => {
@@ -5160,12 +5166,8 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 							}
 							r.push(`you can make it bigger. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 							jQuery("#introResult").empty().append(r.join(" "));
-						},
-						[],
-						"",
-						`This option costs ${cashFormat(V.surgeryCost)}`
-					)
-				);
+						}), `This option costs ${cashFormat(V.surgeryCost)}`
+				));
 				p.append(interestLine);
 				p.append(App.UI.DOM.generateLinksStrip(linkArray));
 			}
@@ -5299,7 +5301,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 				r.push(`door jamming hips while ${he} was around them.`);
 				interestLine.append(r.join(" "));
 				if (slave.hips === 2 && V.surgeryUpgrade === 1) {
-					linkArray.push(
+					linkArray.push(optionWithNote(
 						App.UI.DOM.link(
 							`Surgically widen ${his} hips`,
 							() => {
@@ -5319,14 +5321,10 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								}
 								r.push(`${his} wide hips, especially since ${he} can't figure out how to roll over with them. ${He}'s <span class="hotpink">deliriously happy</span> that ${he} is ridiculously wide and <span class="mediumaquamarine">wiggles ${his} door-jammers cheerfully</span> at you whenever ${he} gets the chance. Since the surgery was invasive, <span class="health dec">${his} health has been greatly affected.</span>`);
 								jQuery("#introResult").empty().append(r.join(" "));
-							},
-							[],
-							"",
-							`This option costs ${cashFormat(V.surgeryCost)}`
-						)
-					);
+							}), `This option costs ${cashFormat(V.surgeryCost)}`
+					));
 				} else if (slave.hips < 2) {
-					linkArray.push(
+					linkArray.push(optionWithNote(
 						App.UI.DOM.link(
 							`Surgically widen ${his} hips`,
 							() => {
@@ -5346,12 +5344,8 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								}
 								r.push(`${his} wide hips. ${He}'s <span class="hotpink">deliriously happy</span> that ${he} is wider than ever and <span class="mediumaquamarine">wiggles ${his} hips cheerfully</span> at you whenever ${he} gets the chance. Since the surgery was invasive, <span class="health dec">${his} health has been greatly affected.</span>`);
 								jQuery("#introResult").empty().append(r.join(" "));
-							},
-							[],
-							"",
-							`This option costs ${cashFormat(V.surgeryCost)}`
-						)
-					);
+							}), `This option costs ${cashFormat(V.surgeryCost)}`
+					));
 				} else {
 					r.push(
 						App.UI.DOM.makeElement("span", `Your surgery suite is not outfitted to widen ${his} hips further.`)
@@ -5415,7 +5409,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 					}
 				}
 				if (slave.butt >= 6 && V.arcologies[0].FSTransformationFetishistResearch === 1) {
-					linkArray.push(
+					linkArray.push(optionWithNote(
 						App.UI.DOM.link(
 							`Implant a heaving pair of fillable implants in ${his} rear`,
 							() => {
@@ -5436,14 +5430,10 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								}
 								r.push(`${his} new ridiculous fake ass, not that ${he} has much choice, since it has ${him} pinned to the bed. ${He}'s <span class="hotpink">deliriously happy</span> that ${he} has ${his} own pair of giant butt cheeks ballooning from ${his} bottom and <span class="mediumaquamarine">hopes</span> you have plans to make them even bigger, even though ${he} is already struggling to escape from under them. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 								jQuery("#introResult").empty().append(r.join(" "));
-							},
-							[],
-							"",
-							`This option costs ${cashFormat(V.surgeryCost)}`
-						)
-					);
+							}), `This option costs ${cashFormat(V.surgeryCost)}`
+					));
 				} else if (slave.butt < 6) {
-					linkArray.push(
+					linkArray.push(optionWithNote(
 						App.UI.DOM.link(
 							`Implant a pair of fillable implants in ${his} rear`,
 							() => {
@@ -5464,13 +5454,9 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								}
 								r.push(`${his} new fake bottom. ${He}'s <span class="hotpink">deliriously happy</span> that ${he} has ${his} own pair of big butt cheeks hanging from ${his} rear and <span class="mediumaquamarine">hopes</span> you have plans to make them even bigger. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 								jQuery("#introResult").empty().append(r.join(" "));
-							},
-							[],
-							"",
-							`This option costs ${cashFormat(V.surgeryCost)}`
-						)
-					);
-					linkArray.push(
+							}), `This option costs ${cashFormat(V.surgeryCost)}`
+					));
+					linkArray.push(optionWithNote(
 						App.UI.DOM.link(
 							`Implant a heavy pair of string implants in ${his} rear`,
 							() => {
@@ -5497,12 +5483,8 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 								}
 								r.push(`they'll keep growing. As with all surgery <span class="health dec">${his} health has been slightly affected.</span>`);
 								jQuery("#introResult").empty().append(r.join(" "));
-							},
-							[],
-							"",
-							`This option costs ${cashFormat(V.surgeryCost)}`
-						)
-					);
+							}),  `This option costs ${cashFormat(V.surgeryCost)}`
+					));
 				} else {
 					r.push(
 						App.UI.DOM.makeElement("span", `${His} butt is already so large that basic implants will not have a noticeable enough effect to sate ${his} curiosity.`)
@@ -5514,4 +5496,15 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 		}
 		return p;
 	}
+
+	/**
+	 * @param {HTMLAnchorElement} link
+	 * @param {string} note
+	 */
+	function optionWithNote(link, note) {
+		const f = new DocumentFragment();
+		f.append(link, " ");
+		App.Events.addNode(f, [note], "span", "note");
+		return f;
+	}
 };
diff --git a/src/npc/infants/InfantState.js b/src/npc/infants/InfantState.js
index 1d74fcd36deeed36191af52fb613bd3c6de9f8a3..b0c36f76a85116b76606a57b4ffa1c64435708c5 100644
--- a/src/npc/infants/InfantState.js
+++ b/src/npc/infants/InfantState.js
@@ -13,6 +13,8 @@ App.Facilities.Nursery.InfantState = class InfantState {
 		/** @type {FC.GenderGenes} */
 		this.genes = "XX";
 		this.pronoun = App.Data.Pronouns.Kind.female;
+		/** slave's natural genetic properties */
+		this.natural = new App.Entity.GeneticState();
 		/** game week child was acquired.
 		 *
 		 * _0: Obtained prior to game start / at game start_ */
diff --git a/src/npc/interaction/killSlave.js b/src/npc/interaction/killSlave.js
index 01e4cf80c88db7c95c3e760a716c9104f6e1329a..63d85c72287569ee3597f699c832ee9dda8d62e1 100644
--- a/src/npc/interaction/killSlave.js
+++ b/src/npc/interaction/killSlave.js
@@ -774,90 +774,19 @@ App.UI.SlaveInteract.killSlave = function(slave) {
 			if (slave.skill.combat > 30) {
 				reactionText = `${He} nods ${his} head and straightens up, as though mentally preparing ${himself} for the fight for ${his} life.`;
 			}
-
-			if (V.animals.canine.length || V.animals.hooved.length || V.animals.feline.length) {
-				combatDiv.append(animals());
-			} else {
-				combatDiv.append(bodyguard());
-			}
+			combatDiv.append(bodyguard());
 
 			return combatDiv;
 
-			function animals() {
-				const subDiv = document.createElement("div");
-				const linksDiv = App.UI.DOM.makeElement("div", null, ['kill-slave-options']);
-
-				const links = [];
-
-				const moreThanOneAnimal = V.active.canine && V.active.hooved ||
-					V.active.canine && V.active.feline ||
-					V.active.hooved && V.active.feline;
-
-				let activeAnimal;
-
-				if (!moreThanOneAnimal) {
-					if (V.active.canine) {
-						activeAnimal = V.active.canine;
-					} else if (V.active.hooved) {
-						activeAnimal = V.active.hooved;
-					} else {
-						activeAnimal = V.active.feline;
-					}
-				}
-
-				subDiv.append(`You tell ${him} you'll give ${him} the chance to win ${his} life in combat – if ${he} wants to live, ${he} can either fight your bodyguard or one of your beasts.`);
-
-				links.push(App.UI.DOM.link(`Have ${him} fight ${S.Bodyguard.slaveName}`, () => {
-					V.pit.slaveFightingBodyguard = slave.ID;
-					V.pit.slaveFightingAnimal = null;
-					V.pit.lethal = true;
-					V.pit.animal = null;
-
-					App.UI.DOM.replace(linksDiv, `It's decided. ${He} will fight your bodyguard, ${S.Bodyguard.slaveName}. ${reactionText}`);
-				}));
-
-				if (V.active.canine && getAnimal(V.active.canine).species === "dog" && !V.active.hooved && !V.active.feline) {
-					links.push(App.UI.DOM.disabledLink(`Have ${him} fight one of your animals`, [`A dog isn't a proper challenge.`]));
-				} else if (V.active.feline && getAnimal(V.active.feline).species === "cat" && !V.active.hooved && !V.active.canine) {
-					links.push(App.UI.DOM.disabledLink(`Have ${him} fight one of your animals`, [`Housecats are much too small to fight.`]));
-				} else {
-					links.push(App.UI.DOM.link(`Have ${him} fight one of your animals`, () => {
-						const animalOptions = [];
-
-						if (V.active.canine && getAnimal(V.active.canine).species !== "dog") {
-							animalOptions.push(V.active.canine);
-						}
-						if (V.active.hooved) {
-							animalOptions.push(V.active.hooved);
-						}
-						if (V.active.feline && getAnimal(V.active.feline).species !== "cat") {
-							animalOptions.push(V.active.feline);
-						}
-
-						V.pit.slaveFightingAnimal = slave.ID;
-						V.pit.slaveFightingBodyguard = null;
-						V.pit.lethal = true;
-						V.pit.animal = animalOptions.random();
-
-						App.UI.DOM.replace(linksDiv, `It's decided. ${He} will fight ${moreThanOneAnimal ? ` one of your animals.` : ` your ${activeAnimal.species}.`} ${reactionText}`);
-					}));
-				}
-
-				App.UI.DOM.appendNewElement("div", linksDiv, App.UI.DOM.generateLinksStrip(links));
-
-				subDiv.append(linksDiv);
-
-				return subDiv;
-			}
-
 			function bodyguard() {
 				const subDiv = document.createElement("div");
 
 				subDiv.append(`You tell ${him} you'll let your bodyguard decide ${his} fate — if ${he} wants to live, ${he}'ll have to beat ${S.Bodyguard.slaveName} in hand-to-hand combat in ${V.pit.name}. `, reactionText);
 
 				V.pit.slaveFightingBodyguard = slave.ID;
-				V.pit.lethal = true;
-				V.pit.animal = null;
+				if (V.pit.lethal === 0) {
+					V.pit.lethal = 1;
+				}
 
 				return subDiv;
 			}
diff --git a/src/npc/startingGirls/startingGirls.js b/src/npc/startingGirls/startingGirls.js
index 00d1aa92736a01108b049182270906d8249987a5..42021b2aa1b38967a555faab80c98bb226a43792 100644
--- a/src/npc/startingGirls/startingGirls.js
+++ b/src/npc/startingGirls/startingGirls.js
@@ -66,6 +66,7 @@ App.StartingGirls.cleanup = function(slave) {
 		slave.indenture = Math.clamp(slave.indenture, 26, 208) || 26;
 	}
 
+	slave.natural.height = Math.clamp(slave.natural.height, 85, 274) || 140;
 	slave.height = Math.clamp(slave.height, 85, 274) || 140;
 	slave.boobs = Math.clamp(Math.trunc(slave.boobs / 50) * 50, 0, 50000) || 200;
 	slave.hLength = Math.clamp(slave.hLength, 0, 500) || 40;
@@ -714,13 +715,13 @@ App.StartingGirls.physical = function(slave, cheat = false) {
 			.showTextBox().pulldown();
 	}
 
-	options.addOption(`Height: ${heightToEitherUnit(slave.height)}`, "height", slave).showTextBox({unit: "cm"})
+	options.addOption(`Natural Adult Height: ${heightToEitherUnit(slave.natural.height)}`, "height", slave.natural).showTextBox({unit: "cm"})
 		.addRange(145, 150, "<", "Petite")
 		.addRange(155, 160, "<", "Short")
 		.addRange(165, 170, "<", "Average")
 		.addRange(180, 185, "<", "Tall")
 		.addRange(190, 185, ">=", "Very tall");
-	option = options.addCustomOption(`Average height for a ${slave.physicalAge} year old is ${heightToEitherUnit(Height.mean(slave))}`)
+	option = options.addCustomOption(`Average natural adult height is ${heightToEitherUnit(Height.mean(slave.nationality, slave.race, slave.genes, 20))}`)
 		.addButton(
 			"Make average",
 			() => resyncSlaveHeight(slave),
@@ -729,17 +730,29 @@ App.StartingGirls.physical = function(slave, cheat = false) {
 	if (cheat || slave.geneticQuirks.dwarfism === 2) {
 		option.addButton(
 			"Make dwarf",
-			() => slave.height = Height.random(slave, {limitMult: [-4, -1], spread: 0.15}),
+			() => slave.natural.height = Height.random(slave, {limitMult: [-4, -1], spread: 0.15}),
 			""
 		);
 	}
 	if (cheat || slave.geneticQuirks.gigantism === 2) {
 		option.addButton(
 			"Make giant",
-			() => slave.height = Height.random(slave, {limitMult: [3, 10], spread: 0.15}),
+			() => slave.natural.height = Height.random(slave, {limitMult: [3, 10], spread: 0.15}),
 			""
 		);
 	}
+	options.addOption(`Current Height: ${heightToEitherUnit(slave.height)}`, "height", slave).showTextBox({unit: "cm"})
+		.addRange(Height.forAge(145, slave), Height.forAge(150, slave), "<", `Petite for age`)
+		.addRange(Height.forAge(155, slave), Height.forAge(160, slave), "<", "Short for age")
+		.addRange(Height.forAge(165, slave), Height.forAge(170, slave), "<", "Average for age")
+		.addRange(Height.forAge(180, slave), Height.forAge(185, slave), "<", "Tall for age")
+		.addRange(Height.forAge(190, slave), Height.forAge(185, slave), ">=", "Very tall for age");
+	options.addCustomOption(`Average height for a ${slave.physicalAge} year old is ${heightToEitherUnit(Height.mean(slave))}`)
+		.addButton(
+			"Scale for age from adult height",
+			() => slave.height = Height.forAge(slave.natural.height, slave),
+			""
+		);
 
 	if (cheat) {
 		options.addOption("Height implant", "heightImplant", slave)
@@ -1714,7 +1727,7 @@ App.StartingGirls.profile = function(slave, cheat = false) {
 
 	options.addOption("Age", "actualAge", slave).showTextBox()
 		.customButton("Resync characteristics to age", () => resyncSlaveToAge(slave), "")
-		.customButton("Resync only height to age", () => slave.height = Height.random(slave), "")
+		.customButton("Resync only height to age", () => resyncSlaveHeight(slave), "")
 		.addComment("It is recommended to resync if you change age significantly");
 	if (cheat) {
 		options.addOption("Physical age", "physicalAge", slave).showTextBox();
@@ -1821,6 +1834,11 @@ App.StartingGirls.profile = function(slave, cheat = false) {
 	options.addOption("Description", "desc", slave.custom).showTextBox({large: true})
 		.addComment("Use complete, capitalized and punctuated sentences.");
 	options.addOption("Label", "label", slave.custom).showTextBox().addComment("Use a short phrase");
+	if (V.imageChoice === 4) {
+		options.addOption("Art Seed", "artSeed", slave.natural).showTextBox({large: true})
+			.customButton("Randomize", () => slave.natural.artSeed = jsRandom(0, 10 ** 14), "")
+			.addComment(`The WebGL Art Renderer uses the art seed to set minor face and body parameters. You can change it if you don't like this slave's appearance.`);
+	}
 
 	el.append(options.render());
 	return el;
diff --git a/src/npc/startingGirls/startingGirlsPassage.js b/src/npc/startingGirls/startingGirlsPassage.js
index 91e4def4d8c6904fa16ff483c875f26090b81da9..dbdacc91f568f7bc8a957fb3f03962f3c7838cf6 100644
--- a/src/npc/startingGirls/startingGirlsPassage.js
+++ b/src/npc/startingGirls/startingGirlsPassage.js
@@ -120,7 +120,8 @@ App.StartingGirls.passage = function() {
 						V.activeSlave.face = 55;
 						V.activeSlave.muscles = 20;
 						V.activeSlave.weight = -20;
-						V.activeSlave.height = Height.forAge(190, V.activeSlave);
+						V.activeSlave.natural.height = 190;
+						V.activeSlave.height = Height.forAge(V.activeSlave.natural.height, V.activeSlave);
 					},
 					[],
 					"Starting Girls"
diff --git a/src/npc/surgery/bodySwap/bodySwap.js b/src/npc/surgery/bodySwap/bodySwap.js
index b532dae1485c0e8cc3918711863375bb596e012e..a14253a4510200b1abd031c42a917888560f8df1 100644
--- a/src/npc/surgery/bodySwap/bodySwap.js
+++ b/src/npc/surgery/bodySwap/bodySwap.js
@@ -7,6 +7,7 @@
 globalThis.bodySwap = function(soul, body, fromGenepool) {
 	WombInit(body); // Just to be sure.
 	soul.genes = body.genes;
+	soul.natural = body.natural;
 	soul.physicalAge = body.physicalAge;
 	soul.visualAge = body.visualAge;
 	soul.ageImplant = body.ageImplant;
@@ -261,7 +262,7 @@ globalThis.bodySwapSelection = function(soul) {
 			App.UI.DOM.link(
 				body.slaveName,
 				() => {
-					V.swappingSlave = body;
+					V.swappingSlave = body.ID;
 					cashX(forceNeg(cost), "slaveSurgery", body);
 				},
 				[],
@@ -335,7 +336,7 @@ globalThis.huskSwapSelection = function(body) {
 										App.UI.DOM.link(
 											soul.slaveName,
 											() => {
-												V.swappingSlave = soul;
+												V.swappingSlave = soul.ID;
 												cashX(forceNeg(cost), "slaveSurgery", soul);
 											},
 											[],
diff --git a/src/npc/surgery/bodySwap/bodySwapReaction.js b/src/npc/surgery/bodySwap/bodySwapReaction.js
index b18c2db8460914255f4ca049760d31ecf3a1c6a4..a95555ac5a3700df722b0ede0a4756916b121cac 100644
--- a/src/npc/surgery/bodySwap/bodySwapReaction.js
+++ b/src/npc/surgery/bodySwap/bodySwapReaction.js
@@ -2028,25 +2028,32 @@ globalThis.bodySwapReaction = function(body, soul) {
 				}
 			}
 
+			App.Events.addParagraph(el, r);
+			r = [];
 			if (body.fetish !== Fetish.MINDBROKEN) {
+				let recognizesBody = false;
 				if (body.origBodyOwnerID === body.ID) {
 					r.push(`This is ${his} body alright.`);
+					recognizesBody = true;
 				} else if (body.ID === body.cloneID) {
 					r.push(`This feels like ${his} body, in a sense.`);
+					recognizesBody = true;
 				}
-				r.push(`Some things might have changed,`);
-				if (body.devotion > 50) {
-					r.push(`but ${he} enjoyed the time they spent apart.`);
-				} else if (body.devotion >= -20) {
-					r.push(`but <span class="mediumaquamarine">it's good to be home.</span>`);
-					body.trust += 15;
-				} else {
-					r.push(`but <span class="mediumaquamarine">${he}'s where ${he} belongs.</span> Now to get it back the way <span class="mediumorchid">${he} likes it.</span>`);
-					body.trust += 30;
-					body.devotion -= 15;
-				}
-				if (body.ID === body.cloneID) {
-					r.push(`Whether or not ${he}'ll figure out it is a clone of ${his} original body remains to be seen.`);
+				if (recognizesBody) {
+					r.push(`Some things might have changed,`);
+					if (body.devotion > 50) {
+						r.push(`but ${he} enjoyed the time they spent apart.`);
+					} else if (body.devotion >= -20) {
+						r.push(`but <span class="mediumaquamarine">it's good to be home.</span>`);
+						body.trust += 15;
+					} else {
+						r.push(`but <span class="mediumaquamarine">${he}'s where ${he} belongs.</span> Now to get it back the way <span class="mediumorchid">${he} likes it.</span>`);
+						body.trust += 30;
+						body.devotion -= 15;
+					}
+					if (body.ID === body.cloneID) {
+						r.push(`Whether or not ${he}'ll figure out it is a clone of ${his} original body remains to be seen.`);
+					}
 				}
 			}
 		}
@@ -3782,6 +3789,8 @@ globalThis.bodySwapReaction = function(body, soul) {
 				}
 			}
 
+			App.Events.addParagraph(el, r);
+			r = [];
 			if (body.fetish !== Fetish.MINDBROKEN) {
 				if (body.origBodyOwnerID === body.ID) {
 					r.push(`This is ${his} body alright. Some things might have changed,`);
diff --git a/src/npc/surgery/bodySwap/huskSlaveSwap.js b/src/npc/surgery/bodySwap/huskSlaveSwap.js
index 599ceb4acfdf26c8084c55bd4a93179352157194..56a0b484bfeaf005c723dc8d3351b10604001135 100644
--- a/src/npc/surgery/bodySwap/huskSlaveSwap.js
+++ b/src/npc/surgery/bodySwap/huskSlaveSwap.js
@@ -1,61 +1,61 @@
 App.UI.SlaveInteract.huskSlaveSwap = function() {
 	const node = new DocumentFragment();
 
-	const oldSlave = clone(V.swappingSlave);
-	const m = V.slaveIndices[V.swappingSlave.ID];
+	const target = getSlave(V.swappingSlave);
+	const oldSlave = clone(target);
 	const {
 		he
-	} = getPronouns(V.swappingSlave);
+	} = getPronouns(target);
 
-	App.UI.DOM.appendNewElement("p", node, `You strap ${V.slaves[m].slaveName}, and the body to which ${he} will be transferred, into the remote surgery and stand back as it goes to work.`);
-	bodySwap(V.slaves[m], V.activeSlave, false);
-	const gps = V.genePool.findIndex(function(s) { return s.ID === V.slaves[m].ID; });
-	// special exception to swap genePool since the temporary body lacks an entry. Otherwise we could just call the widget using the genePool entries
-	V.genePool[gps].race = V.slaves[m].race;
-	V.genePool[gps].origRace = V.slaves[m].origRace;
-	V.genePool[gps].skin = V.slaves[m].skin;
-	V.genePool[gps].markings = V.slaves[m].markings;
-	V.genePool[gps].eye.origColor = V.slaves[m].eye.origColor;
-	V.genePool[gps].origHColor = V.slaves[m].origHColor;
-	V.genePool[gps].origSkin = V.slaves[m].origSkin;
-	V.genePool[gps].face = V.slaves[m].face;
-	V.genePool[gps].pubicHStyle = V.slaves[m].pubicHStyle;
-	V.genePool[gps].underArmHStyle = V.slaves[m].underArmHStyle;
-	V.genePool[gps].eyebrowHStyle = V.slaves[m].eyebrowHStyle;
+	App.UI.DOM.appendNewElement("p", node, `You strap ${target.slaveName}, and the body to which ${he} will be transferred, into the remote surgery and stand back as it goes to work.`);
+	bodySwap(target, V.activeSlave, false);
+	const gps = V.genePool.find(s => s.ID === target.ID);
+	// special exception to swap genePool since the temporary body lacks an entry. Otherwise we could just call bodySwap using the genePool entries
+	gps.race = target.race;
+	gps.origRace = target.origRace;
+	gps.skin = target.skin;
+	gps.markings = target.markings;
+	gps.eye.origColor = target.eye.origColor;
+	gps.origHColor = target.origHColor;
+	gps.origSkin = target.origSkin;
+	gps.face = target.face;
+	gps.pubicHStyle = target.pubicHStyle;
+	gps.underArmHStyle = target.underArmHStyle;
+	gps.eyebrowHStyle = target.eyebrowHStyle;
 
 	App.Events.addParagraph(node, [
-		`After an honestly impressive procedure, ${V.slaves[m].slaveName} is recovering nicely.`,
-		bodySwapReaction(V.slaves[m], oldSlave)
+		`After an honestly impressive procedure, ${target.slaveName} is recovering nicely.`,
+		bodySwapReaction(target, oldSlave)
 	]);
 
 	const cost = slaveCost(oldSlave);
 	const payout = Math.trunc(cost/3);
 	let r = [];
-	r.push(`${V.slaves[m].slaveName}'s old body was bought by the Flesh Heap for ${cashFormat(payout)}.`);
-	if (V.slaves[m].bodySwap > 0) {
-		const myBody = V.slaves.findIndex(function(s) { return s.origBodyOwnerID === V.slaves[m].ID; });
-		if (myBody !== -1) {
-			V.slaves[myBody].origBodyOwnerID = 0;
+	r.push(`${target.slaveName}'s old body was bought by the Flesh Heap for ${cashFormat(payout)}.`);
+	if (target.bodySwap > 0) {
+		const origBodyOwner = V.slaves.find(s => s.origBodyOwnerID === target.ID);
+		if (origBodyOwner) {
+			origBodyOwner.origBodyOwnerID = 0;
 			const {
 				he2, him2, his2
-			} = getPronouns(V.slaves[myBody]).appendSuffix("2");
-			if (V.slaves[myBody].fetish !== Fetish.MINDBROKEN && V.slaves[myBody].fuckdoll === 0) {
-				if (V.slaves[myBody].devotion > 20) {
-					r.push(`${V.slaves[myBody].slaveName} is somewhat saddened to see ${his2} body leave forever.`);
-				} else if (V.slaves[myBody].devotion >= -50) {
-					r.push(`${V.slaves[myBody].slaveName} is <span class="mediumorchid">disturbed</span> to find ${his2} body is gone for good, damaging ${his2} <span class="gold">ability to trust you.</span>`);
-					V.slaves[myBody].devotion -= 30;
-					V.slaves[myBody].trust -= 30;
+			} = getPronouns(origBodyOwner).appendSuffix("2");
+			if (origBodyOwner.fetish !== Fetish.MINDBROKEN && origBodyOwner.fuckdoll === 0) {
+				if (origBodyOwner.devotion > 20) {
+					r.push(`${origBodyOwner.slaveName} is somewhat saddened to see ${his2} body leave forever.`);
+				} else if (origBodyOwner.devotion >= -50) {
+					r.push(`${origBodyOwner.slaveName} is <span class="mediumorchid">disturbed</span> to find ${his2} body is gone for good, damaging ${his2} <span class="gold">ability to trust you.</span>`);
+					origBodyOwner.devotion -= 30;
+					origBodyOwner.trust -= 30;
 				} else {
-					r.push(`${V.slaves[myBody].slaveName} is <span class="mediumorchid">deeply upset</span> that ${he2}'ll never see ${his2} body again. With so little left, ${he2} finds it easy to take vengeance by <span class="orangered">completely rejecting your ownership of ${him2}.</span>`);
-					V.slaves[myBody].devotion -= 50;
-					V.slaves[myBody].trust = 100;
+					r.push(`${origBodyOwner.slaveName} is <span class="mediumorchid">deeply upset</span> that ${he2}'ll never see ${his2} body again. With so little left, ${he2} finds it easy to take vengeance by <span class="orangered">completely rejecting your ownership of ${him2}.</span>`);
+					origBodyOwner.devotion -= 50;
+					origBodyOwner.trust = 100;
 				}
 			}
 		}
 	}
 	App.Events.addParagraph(node, r);
-	V.slaves[m].bodySwap++;
+	target.bodySwap++;
 	cashX(payout, "slaveTransfer");
 	V.activeSlave = 0;
 	V.swappingSlave = 0;
diff --git a/src/npc/surgery/bodySwap/slaveSlaveSwap.js b/src/npc/surgery/bodySwap/slaveSlaveSwap.js
index 285c6cf015f1588f2b2945a44b10e626aa14bc3f..77097c3d15b044a97b25c105cd948fceac11173a 100644
--- a/src/npc/surgery/bodySwap/slaveSlaveSwap.js
+++ b/src/npc/surgery/bodySwap/slaveSlaveSwap.js
@@ -1,57 +1,55 @@
 App.UI.SlaveInteract.slaveSlaveSwap = function() {
 	const node = new DocumentFragment();
 
-	const ss1 = V.slaveIndices[V.AS];
-	const ss1Clone = clone(getSlave(V.AS));
+	const ss1 = getSlave(V.AS);
+	const ss1Clone = clone(ss1);
 
-	const ss2 = V.slaveIndices[V.swappingSlave.ID];
-	const ss2Clone = clone(V.swappingSlave);
+	const ss2 = getSlave(V.swappingSlave);
+	const ss2Clone = clone(ss2);
 
-	const gps1 = V.genePool.findIndex(s => s.ID === V.slaves[ss1].ID);
-	const gps1Clone = clone(V.genePool[gps1]);
+	const gps1 = V.genePool.find(s => s.ID === ss1.ID);
+	const gps1Clone = clone(gps1);
 
-	const gps2 = V.genePool.findIndex(s => s.ID === V.slaves[ss2].ID);
-	const gps2Clone = clone(V.genePool[gps2]);
+	const gps2 = V.genePool.find(s => s.ID === ss2.ID);
+	const gps2Clone = clone(gps2);
 
-	App.UI.DOM.appendNewElement("p", node, `You strap ${getSlave(V.AS).slaveName} and ${V.swappingSlave.slaveName} into the remote surgery and stand back as it goes to work.`);
+	App.UI.DOM.appendNewElement("p", node, `You strap ${ss1.slaveName} and ${ss2.slaveName} into the remote surgery and stand back as it goes to work.`);
 
-	bodySwap(V.slaves[ss1], ss2Clone, false);
-	bodySwap(V.genePool[gps1], gps2Clone, true);
+	bodySwap(ss1, ss2Clone, false);
+	bodySwap(gps1, gps2Clone, true);
 
-	bodySwap(V.slaves[ss2], ss1Clone, false);
-	bodySwap(V.genePool[gps2], gps1Clone, true);
+	bodySwap(ss2, ss1Clone, false);
+	bodySwap(gps2, gps1Clone, true);
+
+	// figuring out who has whose body now
+	whoHasWho(ss1, ss2, ss2Clone);
+	whoHasWho(ss2, ss1, ss1Clone);
+
+	// now to handle whose body it is, name-wise
+	bodySwapName(ss1, ss2Clone);
+	bodySwapName(ss2, ss1Clone);
 
 	App.Events.addParagraph(node, [
-		`After an honestly impressive procedure, ${V.slaves[ss1].slaveName} is recovering nicely.`,
-		bodySwapReaction(V.slaves[ss1], ss1Clone)
+		`After an honestly impressive procedure, ${ss1.slaveName} is recovering nicely.`,
+		bodySwapReaction(ss1, ss1Clone)
 	]);
 
 	App.UI.DOM.appendNewElement("hr", node);
 
 	App.Events.addParagraph(node, [
-		`In the neighboring bed, ${V.slaves[ss2].slaveName} rests peacefully.`,
-		bodySwapReaction(V.slaves[ss2], ss2Clone)
+		`In the neighboring bed, ${ss2.slaveName} rests peacefully.`,
+		bodySwapReaction(ss2, ss2Clone)
 	]);
 
-	// figuring out whom has whose body now
-	whoHasWho(ss1, ss2Clone);
-	whoHasWho(ss2, ss1Clone);
-
-	// now to handle whose body it is, name-wise
-	bodySwapName(V.slaves[ss1], V.slaves[ss2]);
-	bodySwapName(V.slaves[ss2], V.slaves[ss1]);
-
 	for (const ss of [ss1, ss2]) {
-		if (ss1Clone.bodySwap > 0) {
-			if (V.slaves[ss].origBodyOwnerID === V.slaves[ss].ID) {
-				V.slaves[ss].bodySwap = 0;
-				V.slaves[ss].origBodyOwnerID = 0;
-				V.slaves[ss].origBodyOwner = "";
-			} else {
-				V.slaves[ss].bodySwap++;
-			}
+		if (ss.origBodyOwnerID === ss.ID) {
+			// if we got our own original body back, clear our bodyswap records
+			ss.bodySwap = 0;
+			ss.origBodyOwnerID = 0;
+			ss.origBodyOwner = "";
 		} else {
-			V.slaves[ss].bodySwap++;
+			// otherwise, increment the bodyswap counter
+			ss.bodySwap++;
 		}
 	}
 
@@ -59,13 +57,22 @@ App.UI.SlaveInteract.slaveSlaveSwap = function() {
 	V.swappingSlave = 0;
 	return node;
 
-	function whoHasWho(index, opposingClone) {
-		if (V.slaves[index].bodySwap === 0) {
-			V.slaves[index].origBodyOwnerID = opposingClone.ID;
-		} else if (V.slaves[ss2].origBodyOwner !== "") { // now who's going to be looking for you?
-			const myBody = V.slaves.findIndex(function(s) { return s.origBodyOwnerID === V.slaves[ss2].ID; });
-			if (myBody !== -1) {
-				V.slaves[myBody].origBodyOwnerID = V.slaves[index].ID;
+	/** Update origBodyOwnerID appropriately.
+	 * @param {App.Entity.SlaveState} target
+	 * @param {App.Entity.SlaveState} opposing
+	 * @param {App.Entity.SlaveState} opposingClone
+	 */
+	function whoHasWho(target, opposing, opposingClone) {
+		if (opposingClone.bodySwap === 0) {
+			// if my new body came directly from its original owner, give them a reference to me
+			opposing.origBodyOwnerID = target.ID;
+		} else {
+			// if my new body originally belonged to someone else, update the original owner's reference to point to me
+			// note that the original owner may also be me; we'll take care of that later (after generating the reaction)
+			// but we never want to find a self-reference, since those are always temporary
+			const originalOwner = V.slaves.find(s => s.origBodyOwnerID === opposingClone.ID && s.origBodyOwnerID !== s.ID);
+			if (originalOwner) {
+				originalOwner.origBodyOwnerID = target.ID;
 			}
 		}
 	}
diff --git a/src/npc/surgery/cloningWorkaround.js b/src/npc/surgery/cloningWorkaround.js
index 04780cf1848a8215186d7b6d1a3cc1505cfb65f7..2231b3cbe93e80fa0b972f04b055713fe576040c 100644
--- a/src/npc/surgery/cloningWorkaround.js
+++ b/src/npc/surgery/cloningWorkaround.js
@@ -35,11 +35,12 @@ App.UI.cloningWorkaround = function() {
 		}
 	));
 	for (const slave of V.slaves) {
+		const div = App.UI.DOM.appendNewElement("div", node, App.UI.DOM.referenceSlaveWithPreview(slave, SlaveFullName(slave)));
 		if (donatrix !== "undecided" && donatrix.ID === slave.ID) {
-			App.UI.DOM.appendNewElement("div", node, SlaveFullName(slave), "note");
+			div.classList.add("note");
 		} else {
-			App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
-				SlaveFullName(slave),
+			div.append(" ", App.UI.DOM.link(
+				"Select",
 				() => {
 					V.donatrix = slave;
 					App.UI.reload();
@@ -52,18 +53,20 @@ App.UI.cloningWorkaround = function() {
 
 	for (const slave of V.slaves) {
 		if (canBeReceptrix(slave)) {
-			const name = SlaveFullName(slave);
+			const div = App.UI.DOM.appendNewElement("div", node, App.UI.DOM.referenceSlaveWithPreview(slave, SlaveFullName(slave)));
 			if (receptrix !== "undecided" && receptrix.ID === slave.ID) {
-				App.UI.DOM.appendNewElement("div", node, name, "note");
+				div.classList.add("note");
 			} else {
-				App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
-					name,
+				div.append(" ", App.UI.DOM.link(
+					"Select",
 					() => {
 						V.receptrix = slave;
 						App.UI.reload();
-					}, [], "",
-					(slave.pregType >= 4) ? `Using a slave carrying multiples is inadvisable` : ``
+					}
 				));
+				if (slave.pregType >= 4) {
+					App.UI.DOM.appendNewElement("span", div, `Using a slave carrying multiples is inadvisable`, ["note"]);
+				}
 			}
 			eligibility = 1;
 		}
diff --git a/src/npc/surgery/ovaTransplantWorkaround.js b/src/npc/surgery/ovaTransplantWorkaround.js
index 26d1d7f063f621f8585b9b40a8980e98cc1ea1b4..3bca0240b073fc030132ced491761903714c0db7 100644
--- a/src/npc/surgery/ovaTransplantWorkaround.js
+++ b/src/npc/surgery/ovaTransplantWorkaround.js
@@ -8,16 +8,23 @@ App.UI.ovaTransplantWorkaround = function() {
 	App.UI.DOM.appendNewElement("h2", node, "Select a slave to serve as the host");
 
 	for (const slave of V.slaves) {
-		if ((V.donatrix.ID !== slave.ID && slave.ovaries > 0 || slave.mpreg > 0) && isSlaveAvailable(slave) && slave.preg >= 0 && slave.preg < slave.pregData.normalBirth / 10 && slave.pregWeek >= 0 && slave.pubertyXX === 1 && slave.pregType < 12 && slave.bellyImplant === -1 && slave.broodmother === 0 && slave.inflation <= 2 && slave.physicalAge < 70) {
-			App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
-				SlaveFullName(slave),
+		if ((V.donatrix.ID !== slave.ID && slave.ovaries > 0 || slave.mpreg > 0) &&
+			isSlaveAvailable(slave) && slave.preg >= 0 && slave.preg < slave.pregData.normalBirth / 10 &&
+			slave.pregWeek >= 0 && slave.pubertyXX === 1 && slave.pregType < 12 && slave.bellyImplant === -1 &&
+			slave.broodmother === 0 && slave.inflation <= 2 && slave.physicalAge < 70
+		) {
+			const div = App.UI.DOM.appendNewElement("div", node, App.UI.DOM.referenceSlaveWithPreview(slave, SlaveFullName(slave)));
+			div.append(" ", App.UI.DOM.passageLink(
+				"Select", "Surrogacy",
 				() => {
 					V.receptrix = slave;
 					cashX(forceNeg(V.surgeryCost * 2), "slaveSurgery");
 					V.surgeryType = "transplant";
-				}, [], "Surrogacy",
-				(slave.pregType >= 4) ? `Using a slave carrying multiples is inadvisable` : ``
+				}
 			));
+			if (slave.pregType >= 4) {
+				App.UI.DOM.appendNewElement("span", div, `Using a slave carrying multiples is inadvisable`, ["note"]);
+			}
 			eligibility = 1;
 		}
 	}
diff --git a/src/npc/surgery/surgery.js b/src/npc/surgery/surgery.js
index eb04fa79269118ef3ab0cbd960714b8f6044d0ab..1a80f90a23ad3daf5402cce3cb81c1b0c034d5bb 100644
--- a/src/npc/surgery/surgery.js
+++ b/src/npc/surgery/surgery.js
@@ -726,7 +726,7 @@ globalThis.resetEyeColor = function(slave, side = "both") {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @param {FC.GeneticQuirk} level
  */
 globalThis.induceAlbinism = function(slave, level) {
diff --git a/src/personalAssistant/assistantOptions.js b/src/personalAssistant/assistantOptions.js
index 00b455bb04273fd2a0f0173c9edf132f1cba2b12..ff5467ce440c8858f09114a141b3ee00a0f7b794 100644
--- a/src/personalAssistant/assistantOptions.js
+++ b/src/personalAssistant/assistantOptions.js
@@ -46,9 +46,9 @@ App.UI.personalAssistantOptions = function() {
 	tabBar.addTab("Computer Core Upgrades", "upgrades", upgrades());
 	if (V.week >= 11) {
 		tabBar.addTab("Settings", "settings", settings());
-		if (V.assistant.personality !== 0 && V.assistant.options) {
-			tabBar.addTab("Appearance", "appearance", appearance());
-		}
+	}
+	if (V.assistant.personality !== 0 && V.assistant.options) {
+		tabBar.addTab("Appearance", "appearance", appearance());
 	}
 	node.append(tabBar.render());
 
@@ -200,17 +200,19 @@ App.UI.personalAssistantOptions = function() {
 		}
 		*/
 		if (!V.assistant.Extra2) {
-			const price = (V.PC.skill.hacking < 75) ? 10000 * V.upgradeMultiplierArcology : 0;
-			App.UI.DOM.appendNewElement("div", frag, App.UI.DOM.link(
-				`${V.PC.skill.hacking < 75 ? "Purchase" : "Acquire"} a set of heaven and hell themed appearances`,
+			const price = (V.PC.skill.hacking < 75) ? Math.trunc(10000 * V.upgradeMultiplierArcology) : 0;
+			const div = document.createElement("div");
+			div.append(App.UI.DOM.link(
+				`${price ? "Purchase" : "Acquire"} a set of heaven and hell themed appearances`,
 				() => {
 					V.assistant.Extra2 = 1;
-					cashX(Math.trunc(-price), "capEx");
+					cashX(-price, "capEx");
 				},
 				[],
 				"Assistant Appearance Pack Two",
-				(price) ? `Costs ${cashFormat(price)}` : `Unencrypted files, ripe for the taking`
 			));
+			App.Events.addNode(div, [price ? ` Costs ${cashFormatColor(price)}` : ` Unencrypted files, ripe for the taking`], "span", "note");
+			frag.append(div);
 		} else {
 			App.UI.DOM.appendNewElement("div", frag, `You have downloaded a set of heavenly and hellish appearances for your avatar.`);
 		}
diff --git a/src/player/desc/pLongBelly.js b/src/player/desc/pLongBelly.js
index d286a0e638ef361af165bdd4a55bc94470537f95..2abd50c54d75eeb020b280dcbc97baad7aa7432a 100644
--- a/src/player/desc/pLongBelly.js
+++ b/src/player/desc/pLongBelly.js
@@ -1614,7 +1614,7 @@ App.Desc.Player.belly = function(PC = V.PC) {
 				r.push(`You're far enough along at this point that it's in your best interest to stay in the nest and wait things out instead of risking going to labor at an inopportune time.`);
 			}
 			if (PC.geneMods.rapidCellGrowth !== 1 && PC.bellyPreg >= 100000 && PC.belly > (PC.pregAdaptation * 3200) && (PC.bellyPreg >= 500000 || PC.wombImplant !== "restraint")) {
-				r.push(`You are undergoing a <span class="red">very high risk pregnancy,</span> so to decrease the likelyhood of ${V.seeExtreme === 1 && V.dangerousPregnancy === 1 ? "abdominal rupture" : "your water breaking early"}, you have been placed on medical bed rest.`);
+				r.push(`You are undergoing a <span class="red">very high risk pregnancy,</span> so to decrease the probability of ${V.seeExtreme === 1 && V.dangerousPregnancy === 1 ? "abdominal rupture" : "your water breaking early"}, you have been placed on medical bed rest.`);
 			} else if (PC.bellyPreg > PC.pregAdaptation * 1000 && PC.bellyPreg < PC.pregAdaptation * 2200 && PC.geneMods.progenitor !== 1) {
 				r.push(`You are undergoing a <span class="red">high risk pregnancy,</span> so taking things easy is probably a good idea.`);
 			}
diff --git a/src/player/desc/pLongCrotch.js b/src/player/desc/pLongCrotch.js
index 64e17f6304daa1023af925bd20e564fe2597bb75..e36a876caba543708e5f5dc153d086dfbb61186b 100644
--- a/src/player/desc/pLongCrotch.js
+++ b/src/player/desc/pLongCrotch.js
@@ -845,7 +845,9 @@ App.Desc.Player.crotch = function(PC = V.PC) {
 			r.push(`with huge dangling`);
 		}
 		if (V.seeRace === 1) {
-			if (PC.race === "white") {
+			if (PC.geneticQuirks.albinism === 2) {
+				r.push(`${PC.albinismOverride.skin} pussylips.`);
+			} else if (PC.race === "white") {
 				r.push(`pink pussylips.`);
 			} else if (PC.race === "asian") {
 				r.push(`dark ${PC.race} pussylips.`);
diff --git a/src/player/js/PlayerState.js b/src/player/js/PlayerState.js
index 54e5149ca8e6ce07d6523bcab73c489d7dfb9afe..01dbb6fea5ca80b496375e75a92eeb1666dce4b7 100644
--- a/src/player/js/PlayerState.js
+++ b/src/player/js/PlayerState.js
@@ -258,6 +258,8 @@ App.Entity.PlayerState = class PlayerState {
 		this.refreshmentType = 0;
 		/** @type {number} */
 		this.pronoun = App.Data.Pronouns.Kind.male;
+		/** player's natural genetic properties */
+		this.natural = new App.Entity.GeneticState();
 		/**
 		 * * career prior to becoming owner
 		 * * (22+)			(14+)					(10+)
@@ -2039,6 +2041,10 @@ App.Entity.PlayerState = class PlayerState {
 		 *
 		 * 0: stable; 1: gaining; -1: losing */
 		this.weightDirection = 0;
+		/** Stores the exact colors of the albinism quirk
+		 * @type {{skin:string, eyeColor:string, hColor:string}}
+		 */
+		this.albinismOverride = null;
 		// exclusive minor player variables (probably) here
 		/** have you been drugged with fertility drugs
 		 *
diff --git a/src/player/pcSalon.js b/src/player/pcSalon.js
index 1c99c140dc96b4a359ed9a4ddecc06347e973811..e63c46a24df84ca385114bd8e347e3169d12823b 100644
--- a/src/player/pcSalon.js
+++ b/src/player/pcSalon.js
@@ -35,9 +35,11 @@ App.UI.playerSalon = function(PC) {
 			if (PC.tail !== "none") {
 				el.append(tail());
 			}
+			/*
 			if (PC.appendages !== "none") {
 				el.append(appendages());
 			}
+			*/
 			el.append(skin());
 		}
 		return el;
@@ -615,7 +617,7 @@ App.UI.playerSalon = function(PC) {
 			if (PC.markings === "birthmark") {
 				option = options.addOption(`You have a large visible birthmark`, "markings", PC)
 					.addValue("Bleach it", "none", billMod);
-				if (PC.prestige > 0 || PC.porn.prestige > 1) {
+				if (PC.prestige > 0) {
 					option.addComment(`It makes you look unique among your peers.`);
 				}
 			}