diff --git a/devNotes/legacy files/bellyInflation.js b/devNotes/legacy files/bellyInflation.js
index 516e8b3226e7e04307696ce05ede56a07757b0d5..154a759219c3e8b9a09c3b670616d81ec323ee31 100644
--- a/devNotes/legacy files/bellyInflation.js	
+++ b/devNotes/legacy files/bellyInflation.js	
@@ -636,7 +636,7 @@ App.Desc.bellyInflation = function(slave, {market, eventDescription} = {}) {
 						r.push(`${slave.slaveName}'s tight leotard shows off every movement within ${his} jiggling ${slave.inflationType}-filled belly. The material tightly clings to ${his} popped navel.`);
 						break;
 					case "a monokini":
-						r.push(`${slave.slaveName}'s monokini overs only half of ${his} jiggling ${slave.inflationType}-filled belly.`);
+						r.push(`${slave.slaveName}'s monokini covers only half of ${his} jiggling ${slave.inflationType}-filled belly.`);
 						break;
 					case "overalls":
 						if (slave.boobs > (slave.belly + 250)) {
diff --git a/devTools/minify/README.md b/devTools/minify/README.md
index 79dee7f67b3c98b8d1fe611a8a81f562415096f2..d1544d4026118b9197b02799fc279a12378b95b0 100644
--- a/devTools/minify/README.md
+++ b/devTools/minify/README.md
@@ -38,6 +38,12 @@ yay -Syu minify
 pkg install minify
 ```
 
+### Alpine Linux
+Enable the [https://wiki.alpinelinux.org/wiki/Enable_Community_Repository](community repo) and run
+```
+apk add minify
+```
+
 ### MacOS
 Using Homebrew:
 
@@ -66,11 +72,12 @@ Pull the image:
 docker pull tdewolff/minify
 ```
 
+> The `ENTRYPOINT` of the container is the `minify` command
+
 and run the image, for example in interactive mode:
 
-```
-docker run -i tdewolff/minify
-echo "(function(){ if (a == false) { return 0; } else { return 1; } })();" | minify --type js
+```bash
+docker run -i --entrypoint "" tdewolff/minify sh -c 'echo "(function(){ if (a == false) { return 0; } else { return 1; } })();" | minify --type js'
 ```
 
 which will output
diff --git a/devTools/minify/minify_darwin_amd64 b/devTools/minify/minify_darwin_amd64
index 3d7867ddf8c6256cab6735ef723dcc226aaff8e0..9493dd5d13eec83e639df82e2bb70860f4489c6a 100755
Binary files a/devTools/minify/minify_darwin_amd64 and b/devTools/minify/minify_darwin_amd64 differ
diff --git a/devTools/minify/minify_linux_amd64 b/devTools/minify/minify_linux_amd64
index c5bd2be54251b96ca241f2831df07b7767731694..417be68018bdfdfac2ec2917fdfcb513076a81d8 100755
Binary files a/devTools/minify/minify_linux_amd64 and b/devTools/minify/minify_linux_amd64 differ
diff --git a/devTools/minify/minify_win_amd64.exe b/devTools/minify/minify_win_amd64.exe
index c478435ac99942f89aa492c3c14e5ddb1f71ef98..606bf006036f38751bebaec597db5e0890545e4f 100755
Binary files a/devTools/minify/minify_win_amd64.exe and b/devTools/minify/minify_win_amd64.exe differ
diff --git a/devTools/types/FC/RA.d.ts b/devTools/types/FC/RA.d.ts
index d9c75fff29ffea78e0b574b757ee501e71f33834..4552816cf06dc92914abb6a88d289ca20914f201 100644
--- a/devTools/types/FC/RA.d.ts
+++ b/devTools/types/FC/RA.d.ts
@@ -8,8 +8,12 @@ declare namespace FC {
 		type NumericTarget = GenericNumericTarget<number>;
 		type ExpressiveNumericTarget = GenericNumericTarget<number | string>;
 
-		interface RuleConditions {
+		interface RuleConditionEditorArguments {
 			activation: PostFixRule;
+			advancedMode: boolean;
+		}
+
+		interface RuleConditions extends RuleConditionEditorArguments{
 			selectedSlaves: number[];
 			excludedSlaves: number[];
 			applyRuleOnce: boolean;
diff --git a/devTools/types/FC/facilities.d.ts b/devTools/types/FC/facilities.d.ts
index d506384103756c3cad822b247186462f4e2a3beb..0e884609c141ffce5f35457119301563662d5295 100644
--- a/devTools/types/FC/facilities.d.ts
+++ b/devTools/types/FC/facilities.d.ts
@@ -34,9 +34,9 @@ declare namespace FC {
 		 *
 		 * If none are given, the upgrade will always be available.
 		 */
-		prereqs?: Array<() => boolean>
+		prereqs?: boolean[];
 		/** Any additional nodes to attach. */
-		nodes?: Array<string|HTMLElement|DocumentFragment>
+		nodes?: Array<string|HTMLElement|DocumentFragment>;
 	}
 
 	namespace Facilities {
@@ -47,9 +47,9 @@ declare namespace FC {
 
 		interface Rule {
 			/** The variable name of the rule. */
-			property: string
+			property: string;
 			/** Any prerequisites that must be met for the rule to be displayed. */
-			prereqs: Array<() => boolean>
+			prereqs: boolean[];
 			/** Properties pertaining to any options available. */
 			options: Array<{
 				/** The text displayed when the rule is active. */
@@ -63,10 +63,10 @@ declare namespace FC {
 				/** Any additional information to display with on the link. */
 				note?: string;
 				/** Any prerequisites that must be met for the option to be displayed. */
-				prereqs?: Array<() => boolean>;
-			}>
+				prereqs?: boolean[];
+			}>;
 			/** Any additional nodes to attach. */
-			nodes?: Array<string|HTMLElement|DocumentFragment>
+			nodes?: Array<string|HTMLElement|DocumentFragment>;
 			/** Any object the rule property is part of, if not the default `V`. */
 			object?: Object;
 		}
diff --git a/devTools/types/FC/human.d.ts b/devTools/types/FC/human.d.ts
index 23ef528c941aa38f747d8df9d0c601c561d67594..b7bf00245fce571609aec683c6c1bf0bee64c77c 100644
--- a/devTools/types/FC/human.d.ts
+++ b/devTools/types/FC/human.d.ts
@@ -464,6 +464,8 @@ declare global {
 		}
 		//#endregion
 
+		type LimbType = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
+
 		type ArmState = InstanceType<typeof App.Entity.ArmState>;
 		type LegState = InstanceType<typeof App.Entity.LegState>;
 
@@ -476,7 +478,7 @@ declare global {
 				left: LegState,
 				right: LegState;
 			};
-			PLimb: number;
+			PLimb: 0 | 1 | 2 | 3;
 		}
 
 		interface PregnancyData {
diff --git a/js/003-data/clothes/001-slaveWearData.js b/js/003-data/clothes/001-slaveWearData.js
index a0aecb385e206f234cfdce68921f46ed7c3cd4bf..8de9e186cfd26738c7abe82b4a606dece7a6f740 100644
--- a/js/003-data/clothes/001-slaveWearData.js
+++ b/js/003-data/clothes/001-slaveWearData.js
@@ -1531,19 +1531,19 @@ App.Data.bellyAccessory = new Map([
 	["a corset",
 		{
 			name: "Tight corset",
-			note: "Slowly narrows the waist into wispy one."
+			note: "Slowly narrows the waist into a wispy one."
 		}
 	],
 	["an extreme corset",
 		{
 			name: "Extreme corset",
-			note: "Narrows the waist up to absurd level, painfully, if waist is feminine or wider(scaring and increasing obedience on resistant slaves), but risks miscarriage if a pregnant belly becomes too big"
+			note: "Narrows the waist up to an absurd level, painfully if waist is feminine or wider (increasing obedience and fear in resistant slaves), but risks miscarriage if a pregnant belly becomes too big."
 		}
 	],
 	["a support band",
 		{
 			name: "Supportive band",
-			note: "Reduces chance of miscarriage."
+			note: "Eases the pains of pregnancy and reduces chance of miscarriage."
 		}
 	],
 	["a small empathy belly",
diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js
index de255cd4948a0eacddf79bdae31066b21f12cd37..b7cfd32dd0f364801862588827e1d2c0710c0f12 100644
--- a/js/003-data/gameVariableData.js
+++ b/js/003-data/gameVariableData.js
@@ -168,6 +168,7 @@ App.Data.defaultGameStateVariables = {
 	setImageSize: 1,
 	set3QView: false,
 	seeAnimation: true,
+	animFPS: 12,
 	showAgeDetail: 1,
 	showAppraisal: 1,
 	showAssignToScenes: 1,
diff --git a/js/rulesAssistant/conditionEditorSimple.js b/js/rulesAssistant/conditionEditorSimple.js
new file mode 100644
index 0000000000000000000000000000000000000000..0dd064745d83a4d77e11f0c6ebbde7184a18acc2
--- /dev/null
+++ b/js/rulesAssistant/conditionEditorSimple.js
@@ -0,0 +1,335 @@
+/**
+ * All functions should only be called from z1-conditionEditorController.js
+ */
+App.RA.Activation.SimpleEditor = (function() {
+	/**
+	 * @typedef {object} RuleState
+	 * @property {"always"|"never"|"boolean"|"number"|"string"} activeRuleType
+	 * @property {string} boolGetter
+	 * @property {boolean} negateBool
+	 * @property {string} stringGetter
+	 * @property {string} stringComparator
+	 * @property {string} stringValue
+	 * @property {string} numberGetter
+	 * @property {number} numberUpperValue
+	 * @property {"lt"|"lte"|""} numberUpperComparator
+	 * @property {number} numberLowerValue
+	 * @property {"gt"|"gte"|""} numberLowerComparator
+	 */
+
+	/**
+	 * @type {HTMLDivElement}
+	 */
+	let editorNode = null;
+	/**
+	 * @type {RuleState}
+	 */
+	let currentRule = null;
+
+	/**
+	 * @param {FC.RA.PostFixRule} rule
+	 * @param {HTMLDivElement}parent
+	 */
+	function editor(rule, parent) {
+		currentRule = deserializeRule(rule);
+		editorNode = parent;
+		editorNode.append(buildEditor());
+	}
+
+	function refreshEditor() {
+		if (editorNode !== null) {
+			$(editorNode).empty().append(buildEditor());
+		}
+	}
+
+	/**
+	 * If the rule is valid, returns the serialized rule, otherwise null.
+	 *
+	 * @returns {FC.RA.PostFixRule}
+	 */
+	function saveEditor() {
+		if (currentRule == null) {
+			return null;
+		}
+		return serializeRule(currentRule);
+	}
+
+	function resetEditor() {
+		currentRule = null;
+		editorNode = null;
+	}
+
+	/**
+	 * @returns {HTMLElement}
+	 */
+	function buildEditor() {
+		const outerDiv = document.createElement("div");
+		// selector
+		const selectorDiv = document.createElement("div");
+		selectorDiv.classList.add("button-group");
+		outerDiv.append(selectorDiv);
+		App.UI.DOM.appendNewElement("button", selectorDiv, "Always", currentRule.activeRuleType === "always" ? ["selected", "disabled"] : []).onclick = () => {
+			currentRule.activeRuleType = "always";
+			refreshEditor();
+		};
+		App.UI.DOM.appendNewElement("button", selectorDiv, "Never", currentRule.activeRuleType === "never" ? ["selected", "disabled"] : []).onclick = () => {
+			currentRule.activeRuleType = "never";
+			refreshEditor();
+		};
+		App.UI.DOM.appendNewElement("button", selectorDiv, "Boolean", currentRule.activeRuleType === "boolean" ? ["selected", "disabled"] : []).onclick = () => {
+			currentRule.activeRuleType = "boolean";
+			refreshEditor();
+		};
+		App.UI.DOM.appendNewElement("button", selectorDiv, "Number", currentRule.activeRuleType === "number" ? ["selected", "disabled"] : []).onclick = () => {
+			currentRule.activeRuleType = "number";
+			refreshEditor();
+		};
+		App.UI.DOM.appendNewElement("button", selectorDiv, "String", currentRule.activeRuleType === "string" ? ["selected", "disabled"] : []).onclick = () => {
+			currentRule.activeRuleType = "string";
+			refreshEditor();
+		};
+
+		// add bool
+		if (currentRule.activeRuleType === "boolean") {
+			const boolDiv = document.createElement("div");
+			boolDiv.classList.add("button-group");
+			outerDiv.append(boolDiv);
+			/**
+			 * @type {selectOption[]}
+			 */
+			const options = [];
+			App.RA.Activation.getterManager.booleanGetters.forEach((getter, key) => {
+				if (!getter.visible || getter.visible()) {
+					options.push({
+						key: key, name: getter.name, enabled: !getter.enabled || getter.enabled()
+					});
+				}
+			});
+			boolDiv.append(App.UI.DOM.makeSelect(options, currentRule.boolGetter, key => {
+				currentRule.boolGetter = key;
+				refreshEditor();
+			}));
+			boolDiv.append(" should be ");
+			App.UI.DOM.appendNewElement("button", boolDiv, "True", currentRule.negateBool ? [] : ["selected", "disabled"]).onclick = () => {
+				currentRule.negateBool = false;
+				refreshEditor();
+			};
+			App.UI.DOM.appendNewElement("button", boolDiv, "False", currentRule.negateBool ? ["selected", "disabled"] : []).onclick = () => {
+				currentRule.negateBool = true;
+				refreshEditor();
+			};
+		} else if (currentRule.activeRuleType === "number") {
+			const numberDiv = document.createElement("div");
+			outerDiv.append(numberDiv);
+			/**
+			 * @type {selectOption[]}
+			 */
+			const options = [];
+			App.RA.Activation.getterManager.numberGetters.forEach((getter, key) => {
+				if (!getter.visible || getter.visible()) {
+					options.push({
+						key: key, name: getter.name, enabled: !getter.enabled || getter.enabled()
+					});
+				}
+			});
+			numberDiv.append(App.UI.DOM.makeSelect(options, currentRule.numberGetter, key => {
+				currentRule.numberGetter = key;
+				refreshEditor();
+			}));
+			numberDiv.append(" should be ");
+			numberDiv.append(App.UI.DOM.makeSelect(
+				[{key: "gt", name: "greater than"}, {key: "gte", name: "greater than or equal to"},
+					{key: "", name: "ignored"}],
+				currentRule.numberLowerComparator, key => {
+					currentRule.numberLowerComparator = key;
+					refreshEditor();
+				}));
+			if (currentRule.numberLowerComparator !== "") {
+				numberDiv.append(" ", App.UI.DOM.makeTextBox(currentRule.numberLowerValue, val => {
+					currentRule.numberLowerValue = val;
+				}, true));
+			}
+			numberDiv.append(" and ");
+			numberDiv.append(App.UI.DOM.makeSelect(
+				[{key: "lt", name: "less than"}, {key: "lte", name: "less than or equal to"},
+					{key: "", name: "ignored"}],
+				currentRule.numberUpperComparator, key => {
+					currentRule.numberUpperComparator = key;
+					refreshEditor();
+				}));
+			if (currentRule.numberUpperComparator !== "") {
+				numberDiv.append(" ", App.UI.DOM.makeTextBox(currentRule.numberUpperValue, val => {
+					currentRule.numberUpperValue = val;
+				}, true));
+			}
+		} else if (currentRule.activeRuleType === "string") {
+			const stringDiv = document.createElement("div");
+			outerDiv.append(stringDiv);
+			/**
+			 * @type {selectOption[]}
+			 */
+			const options = [];
+			App.RA.Activation.getterManager.stringGetters.forEach((getter, key) => {
+				if (!getter.visible || getter.visible()) {
+					options.push({
+						key: key, name: getter.name, enabled: !getter.enabled || getter.enabled()
+					});
+				}
+			});
+			stringDiv.append(App.UI.DOM.makeSelect(options, currentRule.stringGetter, key => {
+				currentRule.stringGetter = key;
+				refreshEditor();
+			}));
+			stringDiv.append(" should ");
+			stringDiv.append(App.UI.DOM.makeSelect(
+				[{key: "eqstr", name: "equal"}, {key: "substr", name: "contain"}, {key: "match", name: "match"}],
+				currentRule.stringComparator, key => {
+					currentRule.stringComparator = key;
+					refreshEditor();
+				}));
+			stringDiv.append(" ", App.UI.DOM.makeTextBox(currentRule.stringValue, val => {
+				currentRule.stringValue = val;
+			}));
+		}
+
+		return outerDiv;
+	}
+
+	/**
+	 * @param {FC.RA.PostFixRule} rule
+	 * @returns {RuleState}
+	 */
+	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.
+		/**
+		 * @type {RuleState}
+		 */
+		const ruleState = {
+			activeRuleType: "always",
+			boolGetter: "isfertile",
+			negateBool: false,
+			stringGetter: "label",
+			stringValue: "",
+			stringComparator: "eqstr",
+			numberGetter: "devotion",
+			numberUpperValue: 100,
+			numberUpperComparator: "",
+			numberLowerValue: -100,
+			numberLowerComparator: ""
+		};
+		// we know there is only one rule.
+		let i = 0;
+		const rulePart = rule[i];
+		if (rulePart === true) {
+			ruleState.activeRuleType = "always";
+		} else if (rulePart === false) {
+			ruleState.activeRuleType = "never";
+		} else if (App.RA.Activation.getterManager.isBoolean(rulePart)) {
+			ruleState.activeRuleType = "boolean";
+			ruleState.boolGetter = rulePart;
+			if (rule[i + 1] === "not") {
+				ruleState.negateBool = true;
+				i++;
+			}
+		} else if (App.RA.Activation.getterManager.isNumber(rulePart)) {
+			ruleState.activeRuleType = "number";
+			ruleState.numberGetter = rulePart;
+			// check if there is a lower rule:
+			if (rule[i + 2].startsWith("g")) {
+				ruleState.numberLowerValue = rule[i + 1];
+				ruleState.numberLowerComparator = rule[i + 2];
+				// check if there is also an upper value:
+				if (rule[i + 3] === ruleState.numberGetter) {
+					ruleState.numberUpperValue = rule[i + 4];
+					ruleState.numberUpperComparator = rule[i + 5];
+					i += 3;
+				}
+			} else {
+				ruleState.numberUpperValue = rule[i + 1];
+				ruleState.numberUpperComparator = rule[i + 2];
+			}
+			i += 2;
+		} else if (App.RA.Activation.getterManager.isString(rulePart)) {
+			ruleState.activeRuleType = "string";
+			ruleState.stringGetter = rulePart;
+			ruleState.stringValue = rule[i + 1].slice(1);
+			ruleState.stringComparator = rule[i + 2];
+			i += 2;
+		} else {
+			throw new Error("Rule is not in simple mode format!");
+		}
+		i++;
+
+		return ruleState;
+	}
+
+	/**
+	 * Expects a valid RulePart structure
+	 *
+	 * @param {RuleState} ruleState
+	 * @returns {FC.RA.PostFixRule}
+	 */
+	function serializeRule(ruleState) {
+		/**
+		 * @type {FC.RA.PostFixRule}
+		 */
+		const rule = [];
+		let counter = 0;
+
+		switch (ruleState.activeRuleType) {
+			case "always":
+				rule.push(true);
+				counter++;
+				break;
+			case "never":
+				rule.push(false);
+				counter++;
+				break;
+			case "boolean":
+				rule.push(ruleState.boolGetter);
+				if (ruleState.negateBool) {
+					rule.push("not");
+				}
+				counter++;
+				break;
+			case "number":
+				// eslint-disable-next-line no-case-declarations
+				let any = false;
+				if (ruleState.numberLowerComparator !== "") {
+					any = true;
+					rule.push(ruleState.numberGetter);
+					rule.push(ruleState.numberLowerValue);
+					rule.push(ruleState.numberLowerComparator);
+					counter++;
+				}
+				if (ruleState.numberUpperComparator !== "") {
+					any = true;
+					rule.push(ruleState.numberGetter);
+					rule.push(ruleState.numberUpperValue);
+					rule.push(ruleState.numberUpperComparator);
+					counter++;
+				}
+				if (!any) {
+					rule.push(true);
+					counter++;
+				}
+				break;
+			case "string":
+				rule.push(ruleState.stringGetter);
+				rule.push("!"+ruleState.stringValue);
+				rule.push(ruleState.stringComparator);
+				counter++;
+				break;
+		}
+		rule.push(counter, "and");
+		return rule;
+	}
+
+	return {
+		build: editor,
+		save: saveEditor,
+		reset: resetEditor,
+	};
+})();
diff --git a/js/rulesAssistant/conditionEditor.js b/js/rulesAssistant/conditionEditorTree.js
similarity index 98%
rename from js/rulesAssistant/conditionEditor.js
rename to js/rulesAssistant/conditionEditorTree.js
index e6f4ec6be0004e6857e6223bd5ec849d95752fb4..87b8831b4c84ac0ce7038e4de05b276dee6b1f02 100644
--- a/js/rulesAssistant/conditionEditor.js
+++ b/js/rulesAssistant/conditionEditorTree.js
@@ -1,4 +1,7 @@
-App.RA.Activation.Editor = (function() {
+/**
+ * All functions should only be called from z1-conditionEditorController.js
+ */
+App.RA.Activation.TreeEditor = (function() {
 	/**
 	 * @type {HTMLDivElement}
 	 */
@@ -14,14 +17,13 @@ App.RA.Activation.Editor = (function() {
 
 	/**
 	 * @param {FC.RA.PostFixRule} rule
-	 * @returns {HTMLDivElement}
+	 * @param {HTMLDivElement}parent
 	 */
-	function editor(rule) {
+	function editor(rule, parent) {
 		rulePartMap = new Map();
 		currentRule = deserializeRule(rule);
-		editorNode = document.createElement("div");
+		editorNode = parent;
 		editorNode.append(buildEditor());
-		return editorNode;
 	}
 
 	function refreshEditor() {
@@ -31,18 +33,19 @@ App.RA.Activation.Editor = (function() {
 	}
 
 	/**
-	 * Save the rule, if it is valid.
+	 * If the rule is valid, returns the serialized rule, otherwise null.
 	 *
-	 * @param {(rule:FC.RA.PostFixRule)=>void} callback
+	 * @returns {FC.RA.PostFixRule}
 	 */
-	function saveEditor(callback) {
+	function saveEditor() {
 		if (currentRule == null) {
-			return;
+			return null;
 		}
 		const error = currentRule.validate([]) === "error";
 		if (!error) {
-			callback(serializeRule(currentRule));
+			return serializeRule(currentRule);
 		}
+		return null;
 	}
 
 	function resetEditor() {
diff --git a/js/rulesAssistant/z1-conditionEditorController.js b/js/rulesAssistant/z1-conditionEditorController.js
new file mode 100644
index 0000000000000000000000000000000000000000..a45aa13f4624221969686df21c0af27483cf14bb
--- /dev/null
+++ b/js/rulesAssistant/z1-conditionEditorController.js
@@ -0,0 +1,98 @@
+App.RA.Activation.Editor = (function() {
+	/**
+	 * Should the advanced mode (tree editor) be used?
+	 * @type {boolean}
+	 */
+	let advanced = false;
+	/**
+	 * Keep a reference to the outermost node, so we can refresh it when needed.
+	 * @type {HTMLDivElement}
+	 */
+	let outerNode = null;
+
+	/**
+	 * @param {FC.RA.RuleConditionEditorArguments} args
+	 * @returns {HTMLDivElement}
+	 */
+	function editor(args) {
+		outerNode = document.createElement("div");
+		fillOuterNode(args);
+		return outerNode;
+	}
+
+	/**
+	 * @param {FC.RA.RuleConditionEditorArguments} args
+	 */
+	function fillOuterNode(args) {
+		advanced = args.advancedMode;
+		let editorNode = document.createElement("div");
+		if (advanced) {
+			outerNode.append(App.UI.DOM.link("Reset to simple mode", () => {
+				if (SugarCube.Dialog.isOpen()) {
+					SugarCube.Dialog.close();
+				}
+				SugarCube.Dialog.setup("Reset RA to simple mode");
+				$(SugarCube.Dialog.body()).empty().append(
+					"<p>Resetting will delete your current conditions. Do you want to continue?</p>",
+					App.UI.DOM.link("Yes, delete conditions.", () => {
+						args.advancedMode = false;
+						args.activation = App.RA.newRule.conditions().activation;
+						SugarCube.Dialog.close();
+						$(outerNode).empty();
+						fillOuterNode(args);
+					}), " ",
+					App.UI.DOM.makeElement("p", App.UI.DOM.link("Abort.", () => {
+						SugarCube.Dialog.close();
+					})));
+				SugarCube.Dialog.open();
+			}));
+			App.RA.Activation.TreeEditor.build(args.activation, editorNode);
+		} else {
+			outerNode.append(App.UI.DOM.link("Switch to advanced mode", () => {
+				args.advancedMode = true;
+				$(outerNode).empty();
+				fillOuterNode(args);
+			}));
+			App.RA.Activation.SimpleEditor.build(args.activation, editorNode);
+		}
+		outerNode.append(editorNode);
+	}
+
+	/**
+	 * Save the rule, if it is valid.
+	 *
+	 * @param {FC.RA.RuleConditionEditorArguments} args
+	 */
+	function saveEditor(args) {
+		if (advanced) {
+			let rule = App.RA.Activation.TreeEditor.save();
+			if (rule == null) {
+				return;
+			}
+			args.advancedMode = advanced;
+			args.activation = rule;
+		} else {
+			let rule = App.RA.Activation.SimpleEditor.save();
+			if (rule == null) {
+				return;
+			}
+			args.advancedMode = advanced;
+			args.activation = rule;
+		}
+	}
+
+	function resetEditor() {
+		App.RA.Activation.TreeEditor.reset();
+		App.RA.Activation.SimpleEditor.reset();
+		outerNode = null;
+		advanced = false;
+	}
+
+	return {
+		build: editor,
+		save: saveEditor,
+		reset: resetEditor,
+		// Because of this reference we need to load after conditionEditorTree.js
+		validateRule: App.RA.Activation.TreeEditor.validateRule,
+	};
+})();
diff --git a/src/002-config/fc-version.js b/src/002-config/fc-version.js
index 39cb83be86f21ba4839ff7b4c999fbd7d7988c6c..f4d6e7d1f1ada7c03685c7f962f5cea16da5c46b 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.17",
 	commitHash: null,
-	release: 1170, // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js.
+	release: 1172, // 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/facilityFramework.js b/src/004-base/facilityFramework.js
index 81aeeee1596ddae8ef624e92bf14c137692fb79e..3b28365077a1b1ed3128866a9bdca8ec52bd309f 100644
--- a/src/004-base/facilityFramework.js
+++ b/src/004-base/facilityFramework.js
@@ -165,7 +165,7 @@ App.Facilities.Facility = class Facility {
 					for (const expand of [10, 25, 50, 100].filter(s => capacity - occupancy >= s)) {
 						cost = baseCost * (expand / 5);
 						array.push(
-							App.UI.DOM.link(`x${expand}`, () => { expandFacility(expand, cost); }, [], '', `+${expand} slots will cost ${cashFormat(Math.trunc(cost))}`)
+							App.UI.DOM.link(`x${expand}`, () => { expandFacility(expand, cost); }, [], '', `An additional ${num(expand)} slots will cost ${cashFormat(Math.trunc(cost))}.`)
 						);
 					}
 					link.append(App.UI.DOM.generateLinksStrip(array));
@@ -231,16 +231,16 @@ App.Facilities.Facility = class Facility {
 	_makeRules() {
 		const div = document.createElement("div");
 
-		if (this.rules.length > 0 && this.rules.some(rule => rule.prereqs.every(prereq => prereq()))) {
+		if (this.rules.length > 0 && this.rules.some(rule => rule.prereqs.every(prereq => prereq === true))) {
 			App.UI.DOM.appendNewElement("h2", div, `Rules`);
 
 			this._rules.forEach(rule => {
-				if (rule.prereqs.every(prereq => prereq())) {
+				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())) {
+						if (!o.prereqs || o.prereqs.every(prereq => prereq === true)) {
 							option.addValue(o.link, o.value);
 							if (o.handler) {
 								option.addCallback(o.handler);
diff --git a/src/Mods/SecExp/events/conflictOptions.js b/src/Mods/SecExp/events/conflictOptions.js
index 8296d64c40c343305b76566c6f9012716f627e07..fb55b8872015e35790ec582c6c723fdf648ab044 100644
--- a/src/Mods/SecExp/events/conflictOptions.js
+++ b/src/Mods/SecExp/events/conflictOptions.js
@@ -2,8 +2,7 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 	eventPrerequisites() {
 		return [
 			() => V.secExpEnabled > 0,
-			() => V.SecExp.war.foughtThisWeek === 0,
-			() => V.SecExp.war.type !== ""
+			() => V.SecExp.war.type
 		];
 	}
 
@@ -31,7 +30,7 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 							r.push(`Some of your citizens saw the disorganized horde of raiders coming towards the city and quickly reported it. To such jackals your arcology surely looks like an appetizing morsel.`);
 						}
 						const div = document.createElement("div");
-						App.UI.DOM.makeElement("span", `Raiders`, "strong");
+						App.UI.DOM.makeElement("span", `Raiders`, ["strong"]);
 						App.UI.DOM.makeElement("span", `are roaming gangs of bandits, preying on the vulnerable supply lines of Free Cities and old world nations. They are rarely equipped with decent armaments and even more rarely have any formal military training, but they make up for that with high mobility and numbers.`);
 						r.push(div);
 					} else if (V.SecExp.war.attacker.type === "free city") {
@@ -42,7 +41,7 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 							r.push(`Some of your citizens saw the menacing column of slavers and hired mercenaries and rushed to your office to bring the grim news. Another free city is ready to use their best tools to bring down a dangerous competitor.`);
 						}
 						const div = document.createElement("div");
-						App.UI.DOM.makeElement("span", `Free City expeditions`, "strong");
+						App.UI.DOM.makeElement("span", `Free City expeditions`, ["strong"]);
 						App.UI.DOM.makeElement("span", `are usually composed of mercenaries hired to take down sensible supplies or infrastructure in order to damage the enemies of their contractor. They have on average good equipment and training, together with decent mobility, making them a formidable force. Their biggest weakness however is their relatively low numbers.`);
 						r.push(div);
 					} else if (V.SecExp.war.attacker.type === "freedom fighters") {
@@ -53,7 +52,7 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 							r.push(`Some of your citizens saw the dangerous looking army of guerrillas is gathering just outside the arcology. Fanatics and idealists armed with dead men's words and hope, set on erasing your fledgling empire.`);
 						}
 						const div = document.createElement("div");
-						App.UI.DOM.makeElement("span", `Freedom Fighters`, "strong");
+						App.UI.DOM.makeElement("span", `Freedom Fighters`, ["strong"]);
 						App.UI.DOM.makeElement("span", `are groups of individuals fighting to rid the planet of "evils" such as the Free Cities and their way of life. Lacking the strength to assault one directly they fight guerrilla style slowly starving to death their enemies. They are rarely well equipped, but with good training and mobility they are not a threat that can be taken lightly.`);
 						r.push(div);
 					} else if (V.SecExp.war.attacker.type === "old world") {
@@ -64,7 +63,7 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 							r.push(`Some of your citizens saw the disciplined yet dusty, scruffy old world army is approaching the confines of your arcology. There's nothing better than a good war to unite the electorate and your arcology is just the perfect target.`);
 						}
 						const div = document.createElement("div");
-						App.UI.DOM.makeElement("span", `Old world expeditions`, "strong");
+						App.UI.DOM.makeElement("span", `Old world expeditions`, ["strong"]);
 						App.UI.DOM.makeElement("span", `are usually sent to secure resources and trade routes for their nation or, more often, to provide their citizens with a bogeyman to be scared of. They are usually decently equipped and trained, which together with their generous numbers make them a tough nut to crack. However, they often lack in mobility.`);
 						r.push(div);
 					}
@@ -121,27 +120,27 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 			const isOceanic = V.terrain === "oceanic";
 			r.push(`It seems your troops and your adversary will fight`);
 			if (V.SecExp.war.terrain === "rural") {
-				r.push(`in`, App.UI.DOM.makeElement("span", `the rural land`, "strong"), `surrounding the free city.`);
+				r.push(`in`, App.UI.DOM.makeElement("span", `the rural land`, ["strong"]), `surrounding the free city.`);
 			} else if (V.SecExp.war.terrain === "urban") {
-				r.push(`in the old`, App.UI.DOM.makeElement("span", `abandoned city`, "strong"), `surrounding the free city.`);
+				r.push(`in the old`, App.UI.DOM.makeElement("span", `abandoned city`, ["strong"]), `surrounding the free city.`);
 			} else if (V.SecExp.war.terrain === "hills") {
-				r.push(`on`, App.UI.DOM.makeElement("span", `the hills`, "strong"), `around the free city.`);
+				r.push(`on`, App.UI.DOM.makeElement("span", `the hills`, ["strong"]), `around the free city.`);
 			} else if (V.SecExp.war.terrain === "coast") {
-				r.push(`along`, App.UI.DOM.makeElement("span", `the coast`, "strong"), `just outside the free city.`);
+				r.push(`along`, App.UI.DOM.makeElement("span", `the coast`, ["strong"]), `just outside the free city.`);
 			} else if (V.SecExp.war.terrain === "outskirts") {
-				r.push(`right against`, App.UI.DOM.makeElement("span", `the walls of the arcology.`, "strong"));
+				r.push(`right against`, App.UI.DOM.makeElement("span", `the walls of the arcology.`, ["strong"]));
 			} else if (V.SecExp.war.terrain === "mountains") {
-				r.push(`in`, App.UI.DOM.makeElement("span", `the mountains`, "strong"), `overlooking the arcology.`);
+				r.push(`in`, App.UI.DOM.makeElement("span", `the mountains`, ["strong"]), `overlooking the arcology.`);
 			} else if (V.SecExp.war.terrain === "wasteland") {
-				r.push(`in`, App.UI.DOM.makeElement("span", `the wastelands`, "strong"), `outside the free city territory.`);
+				r.push(`in`, App.UI.DOM.makeElement("span", `the wastelands`, ["strong"]), `outside the free city territory.`);
 			} else if (V.SecExp.war.terrain === "international waters") {
-				r.push(`in`, App.UI.DOM.makeElement("span", `the water surrounding`, "strong"), `the free city.`);
+				r.push(`in`, App.UI.DOM.makeElement("span", `the water surrounding`, ["strong"]), `the free city.`);
 			} else if (["a sunken ship", "an underwater cave"].includes(V.SecExp.war.terrain)) {
-				r.push(`in`, App.UI.DOM.makeElement("span", `${V.SecExp.war.terrain}`, "strong"), `near the free city.`);
+				r.push(`in`, App.UI.DOM.makeElement("span", `${V.SecExp.war.terrain}`, ["strong"]), `near the free city.`);
 			} else if (V.SecExp.war.terrain === "error") {
-				r.push(App.UI.DOM.makeElement("span", `Error: failed to assign terrain.`, "red"), `${V.SecExp.war.terrain} reads: ${V.SecExp.war.terrain}.`);
+				r.push(App.UI.DOM.makeElement("span", `Error: failed to assign terrain.`, ["red"]), `${V.SecExp.war.terrain} reads: ${V.SecExp.war.terrain}.`);
 			} else {
-				r.push(App.UI.DOM.makeElement("span", `Error: failed to read terrain.`, "red"), `${V.SecExp.war.terrain} reads: ${V.SecExp.war.terrain}.`);
+				r.push(App.UI.DOM.makeElement("span", `Error: failed to read terrain.`, ["red"]), `${V.SecExp.war.terrain} reads: ${V.SecExp.war.terrain}.`);
 			}
 			if (App.Mods.SecExp.battle.recon() === 3) {
 				r.push(`Your recon capabilities are top notch. The information collected will be most likely correct or very close to be so:`);
@@ -153,22 +152,22 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 				r.push(`Your recon capabilities are almost non-existent. The information collected will be wild guesses at best:`);
 			}
 			r.push(`approximately`);
-			r.push(App.UI.DOM.makeElement("span", `${estimatedMen} men`, "strong"));
+			r.push(App.UI.DOM.makeElement("span", `${estimatedMen} men`, ["strong"]));
 			r.push(`are coming, they seem to be`);
 			if (expectedEquip <= 0) {
-				r.push(App.UI.DOM.makeElement("span", `poorly armed.`, "strong"));
+				r.push(App.UI.DOM.makeElement("span", `poorly armed.`, ["strong"]));
 				r.push(`Old rusty small arms are the norm with just a few barely working civilian ${isOceanic ? 'boats' : 'vehicles'}.`);
 			} else if (expectedEquip === 1) {
-				r.push(App.UI.DOM.makeElement("span", `lightly armed,`, "strong"));
+				r.push(App.UI.DOM.makeElement("span", `lightly armed,`, ["strong"]));
 				r.push(`mostly with small arms and some repurposed civilian ${isOceanic ? 'boats' : 'vehicles'} with scattered machine gun support. There's no sign of heavy ${isOceanic ? 'boats' : 'vehicles'}, ${isOceanic ? 'submarines' : 'artillery'} or aircraft.`);
 			} else if (expectedEquip === 2) {
-				r.push(App.UI.DOM.makeElement("span", `decently armed`, "strong"));
+				r.push(App.UI.DOM.makeElement("span", `decently armed`, ["strong"]));
 				r.push(`with good quality small arms, machine guns and a few mortars. There appear to be some heavy military ${isOceanic ? 'boats' : 'vehicles'} coming as well.`);
 			} else if (expectedEquip === 3) {
-				r.push(App.UI.DOM.makeElement("span", `well armed`, "strong"));
+				r.push(App.UI.DOM.makeElement("span", `well armed`, ["strong"]));
 				r.push(`with high quality small arms, ${isOceanic ? 'spear men' : 'snipers'}, demolitions teams, heavy duty machine guns and mortars. Heavy military ${isOceanic ? 'boats' : 'vehicles'} are numerous and a few ${isOceanic ? 'submarines' : 'artillery pieces'} are accompanying the detachment.`);
 			} else if (expectedEquip >= 4) {
-				r.push(App.UI.DOM.makeElement("span", `extremely well armed`, "strong"));
+				r.push(App.UI.DOM.makeElement("span", `extremely well armed`, ["strong"]));
 				r.push(`with excellent small arms and specialized teams with heavy duty infantry support weapons. Heavy presence of armored military ${isOceanic ? 'boats' : 'vehicles'}, ${isOceanic ? 'submarines' : 'artillery pieces'} and even some attack helicopters.`);
 			}
 			App.Events.addParagraph(node, r);
@@ -176,7 +175,7 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 
 			App.UI.DOM.appendNewElement("h2", node, `Battle plan`);
 			if (V.SecExp.war.commander === "bodyguard" && V.BodyguardID === 0 || V.SecExp.war.commander === "headGirl" && V.HeadGirlID === 0) {
-				App.UI.DOM.makeElement("span", `Chosen leader ${V.SecExp.war.commander} cannot be found, please select another.`, "warning");
+				App.UI.DOM.makeElement("span", `Chosen leader ${V.SecExp.war.commander} cannot be found, please select another.`, ["warning"]);
 				V.SecExp.war.commander = "PC";
 			}
 			options = new App.UI.OptionsGroup(); // leader assignment
@@ -218,14 +217,14 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 				option = options.addOption(tactic, "chosenTactic", V.SecExp.war).addValue("Select", tactic);
 				const comment = document.createElement("span");
 				if (tactics[tactic].atkMod > 0.1) {
-					App.UI.DOM.appendNewElement("span", comment, "Atk+, ", "green");
+					App.UI.DOM.appendNewElement("span", comment, "Atk+, ", ["green"]);
 				} else if (tactics[tactic].atkMod < 0.1) {
-					App.UI.DOM.appendNewElement("span", comment, "Atk-, ", "red");
+					App.UI.DOM.appendNewElement("span", comment, "Atk-, ", ["red"]);
 				}
 				if (tactics[tactic].defMod > 0.1) {
-					App.UI.DOM.appendNewElement("span", comment, "Def+, ", "green");
+					App.UI.DOM.appendNewElement("span", comment, "Def+, ", ["green"]);
 				} else if (tactics[tactic].defMod < 0.1) {
-					App.UI.DOM.appendNewElement("span", comment, "Def-, ", "red");
+					App.UI.DOM.appendNewElement("span", comment, "Def-, ", ["red"]);
 				}
 				comment.append(tacticsDesc.get(tactic));
 				option.addComment(comment);
@@ -307,7 +306,7 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 			// troop deployment
 			if (App.Mods.SecExp.battle.deployableUnits() > 0) {
 				r.push(`With your current readiness level you can send an additional`);
-				r.push(App.UI.DOM.makeElement("span", String(App.Mods.SecExp.battle.deployableUnits()), "strong"));
+				r.push(App.UI.DOM.makeElement("span", String(App.Mods.SecExp.battle.deployableUnits()), ["strong"]));
 				r.push(`units.`);
 			}
 		} else {
@@ -333,30 +332,29 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 			if (V.SecExp.war.irregulars > 0) {
 				r.push(`${num(Math.trunc(V.SecExp.war.irregulars))} of your citizens took up arms to defend their arcology owner.`);
 			}
-			if (V.SecExp.war.rebellingID.length > 0) {
-				App.Events.addParagraph(node, r);
-				r = [];
-				let rebelling = [];
-				for (const squad of App.Mods.SecExp.unit.squads("human")) {
-					if (squad.active === 1 && (V.SecExp.war.rebellingID.includes(squad.ID))) {
-						rebelling.push(squad.platoonName);
-					}
-				}
-				r.push(`${toSentence(rebelling)} betrayed you and joined the insurrection.`);
-			}
-			let defending = [];
+
+			const rebelling = [];
+			const defending = [];
 			if (V.arcologyUpgrade.drones === 1) {
 				defending.push(`Your security drones`);
 			}
-			for (const squad of App.Mods.SecExp.unit.squads("human")) {
-				if (squad.active === 1 && (!V.SecExp.war.rebellingID.includes(squad.ID))) {
-					defending.push(squad.platoonName);
-				}
-			}
 			if (V.SF.Toggle && V.SF.Active >= 1) {
 				let SFname = defending.length > 0 ? V.SF.Lower : capFirstChar(V.SF.Lower);
 				defending.push(`${SFname}, ${num(V.SF.ArmySize)} strong`);
 			}
+			for (const squad of App.Mods.SecExp.unit.squads("human").filter(u => u.active)) {
+				if (V.SecExp.war.rebellingID.includes(squad.ID)) {
+					rebelling.push(squad.platoonName);
+				} else {
+					defending.push(squad.platoonName);
+				}
+			}
+
+			if (V.SecExp.war.rebellingID.length > 0) {
+				App.Events.addParagraph(node, r);
+				r = [];
+				r.push(`${toSentence(rebelling)} betrayed you and joined the insurrection.`);
+			}
 			if (defending.length > 0) {
 				App.Events.addParagraph(node, r);
 				r = [];
@@ -378,7 +376,7 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 				text = `Your troops will make use of the special weaponry, equipment and infrastructure developed by the riot control center to surgically eliminate rebels and dissidents with little to no collateral damage.`;
 			}
 			if (text) {
-				App.UI.DOM.appendNewElement("div", node, text, "note");
+				App.UI.DOM.appendNewElement("div", node, text, ["note"]);
 			}
 
 			const engageRules = new Map([
@@ -409,7 +407,7 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 			]);
 			const activeDefenses = Array.from(locations.keys()).filter(loc => V.SecExp.war[loc] === 1);
 			if (activeDefenses.length > 0) {
-				App.UI.DOM.appendNewElement("div", node, `Your troops will garrison the ${toSentence(activeDefenses.map(loc => locations.get(loc)))}.`, "note");
+				App.UI.DOM.appendNewElement("div", node, `Your troops will garrison the ${toSentence(activeDefenses.map(loc => locations.get(loc)))}.`, ["note"]);
 			}
 			for (const [loc, text] of locations) {
 				const choices = [];
@@ -434,7 +432,7 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 		node.append(App.Mods.SecExp.unit.replenishAll());
 		if (isBattle) {
 			if (App.Mods.SecExp.battle.deployableUnits() === 0) {
-				App.UI.DOM.appendNewElement("div", node, `Unit roster full.`, "strong");
+				App.UI.DOM.appendNewElement("div", node, `Unit roster full.`, ["strong"]);
 			}
 			if (App.Mods.SecExp.unit.squads().length > 0) {
 				options = new App.UI.OptionsGroup();
@@ -457,20 +455,17 @@ App.Events.conflictOptions = class conflictOptions extends App.Events.BaseEvent
 		if (isBattle && App.Mods.SecExp.battle.deployedUnits() > 0 || !isBattle) {
 			option.addButton(isBattle ? `Deploy troops` : `Proceed`, () => {
 				V.SecExp.war.result = 4; // Sets to a value outside accepted range (-3, 3) to avoid evaluation problems
-				V.SecExp.war.foughtThisWeek = 1;
 			}, `conflictHandler`);
 		} else if (isBattle && App.Mods.SecExp.battle.deployedUnits() === 0) {
-			App.UI.DOM.appendNewElement("div", node, `You need at least a unit in your roster to proceed to battle.`, "red");
+			App.UI.DOM.appendNewElement("div", node, `You need at least a unit in your roster to proceed to battle.`, ["red"]);
 		}
 		if (isBattle) {
 			option.addButton(`Attempt to bribe (approximately ${cashFormat(Math.round(App.Mods.SecExp.battle.bribeCost() * (1 + either(-1, 1) * random(2) * 0.1)))})`, () => {
 				V.SecExp.war.result = 1;
-				V.SecExp.war.foughtThisWeek = 1;
 			}, `conflictHandler`);
 		}
 		option.addButton(`Surrender`, () => {
 			V.SecExp.war.result = -1;
-			V.SecExp.war.foughtThisWeek = 1;
 		}, "conflictReport");
 		node.append(options.render());
 		return node;
diff --git a/src/Mods/SecExp/events/conflictReport.js b/src/Mods/SecExp/events/conflictReport.js
index 2983e3b35df72ddb51501f8823505132c581cdd7..145c6ab7e30e2be361e421d7d0ba0701d1bff42b 100644
--- a/src/Mods/SecExp/events/conflictReport.js
+++ b/src/Mods/SecExp/events/conflictReport.js
@@ -1217,14 +1217,12 @@ App.Events.conflictReport = function() {
 
 	App.Events.addParagraph(node, r);
 	if (inRebellion) {
+		const inverse = slaveRebellion ? 'citizen' : 'slave';
 		V.SecExp.rebellions[V.SecExp.war.type.toLowerCase().replace(' rebellion', '') + 'Progress'] = 0;
 		V.SecExp.rebellions.tension = Math.clamp(V.SecExp.rebellions.tension - random(50, 100), 0, 100);
-		if (slaveRebellion) {
-			V.SecExp.rebellions.citizenProgress = Math.clamp(V.SecExp.rebellions.citizenProgress - random(50, 100), 0, 100);
-		} else {
-			V.SecExp.rebellions.slaveProgress = Math.clamp(V.SecExp.rebellions.slaveProgress - random(50, 100), 0, 100);
-		}
+		V.SecExp.rebellions[inverse + 'Progress'] = Math.clamp(V.SecExp.rebellions[inverse + 'Progress'] - random(50, 100), 0, 100);
 	}
+	delete V.SecExp.war.type;
 	return node;
 };
 /**
diff --git a/src/Mods/SecExp/events/secExpSmilingMan0.js b/src/Mods/SecExp/events/secExpSmilingMan0.js
index cda9d50687c37470760be95fdb352dc026eaa702..32685d4c074440fc78db3d991434aac8fef992a9 100644
--- a/src/Mods/SecExp/events/secExpSmilingMan0.js
+++ b/src/Mods/SecExp/events/secExpSmilingMan0.js
@@ -9,24 +9,23 @@ App.Events.secExpSmilingMan0 = class secExpSmilingMan0 extends App.Events.BaseEv
 	}
 
 	execute(node) {
-		let r = [];
+		V.fcnn.push("...encryption techniques: how to protect you and your loved ones from hackers ...");
 		V.SecExp.smilingMan.progress++;
-
+		V.SecExp.smilingMan.relationship = 0;
+		let r = [];
 		const {heA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
+		const cost = 10000;
+		const choices = [];
 
-		V.SecExp.smilingMan.relationship = 0;
-		V.fcnn.push("...encryption techniques: how to protect you and your loved ones from hackers ...");
 		r.push(
 			`During your morning routine, a peculiar report appears: it's been several weeks since your arcology was the victim of a series of cyber-crimes conducted by a mysterious figure. The egocentric criminal apparently took great pride in their acts, to the point of signing them with a symbol: a stylized smiling face. Your arcology was not the only one under assault by the machinations of the one the media quickly nicknamed`,
-			App.UI.DOM.makeElement("span", "the Smiling Man.", "note")
+			App.UI.DOM.makeElement("span", "the Smiling Man.", ["note"])
 		);
 		App.Events.addParagraph(node, r);
 		App.Events.addParagraph(node, [`Despite the sheer damage this criminal did, you cannot help but admire the skill with which every misdeed was performed — the worst white collar crimes of the century, carried out with such elegance that they almost seemed the product of natural laws, rather than masterful manipulation of the digital market. While sifting through the report, ${V.assistant.name} remains strangely quiet. "I'm worried, ${properTitle()} — this individual seems to be able to penetrate whichever system garners his attention. I... feel vulnerable," ${heA} says. "It's not something I'm used to."`]);
 		App.Events.addParagraph(node, [`Fortunately you have not been hit directly by this criminal — yet. Still, the repercussions of numerous bankruptcies take their toll on your arcology, whose <span class="red">prosperity suffers.</span>`]);
 		V.arcologies[0].prosperity *= random(80, 90) * 0.01;
 
-		const choices = [];
-		const cost = 10000;
 		if (V.cash >= cost) {
 			choices.push(new App.Events.Result(`Devote funds to the search for this dangerous criminal`, search, `This will cost ${cashFormat(cost)}`));
 			choices.push(new App.Events.Result(`Attempt to contact the mysterious figure`, contact, `This will cost ${cashFormat(cost)}`));
@@ -39,27 +38,26 @@ App.Events.secExpSmilingMan0 = class secExpSmilingMan0 extends App.Events.BaseEv
 
 		function search() {
 			cashX(-10000, "event");
-			V.SecExp.smilingMan.investedFunds = 1;
+			App.Events.queueEvent(3, new App.Events.secExpSmilingMan1(), {investedFunds: V.SecExp.smilingMan.investedFunds || 1});
 			V.SecExp.smilingMan.relationship++;
 			return `You devote funds to capture and neutralize the threat. You cannot help but wonder what the end game of this "smiling man" is. Money? Fame? Or is he on an ideological crusade?`;
 		}
-
 		function contact() {
 			cashX(-10000, "event");
-			V.SecExp.smilingMan.investedFunds = 1;
+			App.Events.queueEvent(3, new App.Events.secExpSmilingMan1(), {investedFunds: V.SecExp.smilingMan.investedFunds || 1});
 			V.SecExp.smilingMan.relationship += 2;
 			return `You devote funds to an attempt at communicating with the smiling man. You cannot help but wonder what the end game of this "smiling man" is. Money? Fame? Or is he on an ideological crusade?`;
 		}
-
 		function invest() {
 			cashX(-10000, "event");
-			V.SecExp.smilingMan.investedFunds = 1;
+			App.Events.queueEvent(3, new App.Events.secExpSmilingMan1(), {investedFunds: V.SecExp.smilingMan.investedFunds || 1});
 			V.SecExp.smilingMan.relationship += random(5, 10);
 			return `You devote funds to the improvement of the cyber-security of your arcology. You cannot help but wonder what the end game of this "smiling man" is. Money? Fame? Or is he on an ideological crusade?`;
 		}
-
 		function bliss() {
+			App.Events.queueEvent(3, new App.Events.secExpSmilingMan1());
 			return `You do not consider this individual a threat.`;
 		}
+		
 	}
 };
diff --git a/src/Mods/SecExp/events/secExpSmilingMan1.js b/src/Mods/SecExp/events/secExpSmilingMan1.js
index c51c512a248dba98c82ca715fc4d11ffe525ad0e..fe4e5c768467aac3a4967ebd511114e3030b03bd 100644
--- a/src/Mods/SecExp/events/secExpSmilingMan1.js
+++ b/src/Mods/SecExp/events/secExpSmilingMan1.js
@@ -1,19 +1,17 @@
 App.Events.secExpSmilingMan1 = class secExpSmilingMan1 extends App.Events.BaseEvent {
 	eventPrerequisites() {
 		return [
-			() => V.rival.state <= 1 || V.rival.state > 2,
 			() => V.secExpEnabled > 0,
-			() => V.SecExp.smilingMan.progress === 1,
-			() => App.Events.effectiveWeek() >= 77,
 		];
 	}
 
 	execute(node) {
-		let r = [];
+		App.Events.queueEvent(5, new App.Events.secExpSmilingMan2());
+		V.fcnn.push("...cybersecurity market is booming thanks to a series of recent high-profile attacks...");
 		V.SecExp.smilingMan.progress++;
-
+		let r = [];
 		const {hisA, heA, himA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
-		V.fcnn.push("...cybersecurity market is booming thanks to a series of recent high-profile attacks...");
+
 		r.push(
 			`You have just reached your penthouse when your faithful assistant appears in front of you, evidently excited.`,
 			`"${properTitle()}, I have just received news of a new attack by the Smiling Man. It appears a few hours ago he infiltrated another arcology and caused a catastrophic failure of its power plant.`,
@@ -53,13 +51,9 @@ App.Events.secExpSmilingMan1 = class secExpSmilingMan1 extends App.Events.BaseEv
 		}
 		if (V.SecExp.buildings.secHub && V.SecExp.buildings.secHub.upgrades.security.cyberBots === 1) {
 			lostCash -= Math.min(30000, lostCash);
-			r.push(`The additional cyber defenses acquired and running in the security HQ`);
-			if (lostCash < 200000) {
-				r.push(`further`);
-			}
-			r.push(`limit the damage.`);
+			r.push(`The additional cyber defenses acquired and running in the security HQ ${lostCash < 200000 ? 'further' : ''} limit the damage.`);
 		}
-		if (V.SecExp.smilingMan.investedFunds) {
+		if (V.SecExp.smilingMan.investedFunds || this.params.investedFunds) {
 			lostCash -= Math.min(20000, lostCash);
 			r.push(`The funding you dedicated to the Smiling Man case saved some of the assets that would have been otherwise lost.`);
 			delete V.SecExp.smilingMan.investedFunds;
@@ -67,7 +61,6 @@ App.Events.secExpSmilingMan1 = class secExpSmilingMan1 extends App.Events.BaseEv
 		cashX(forceNeg(lostCash), "event");
 		App.Events.addParagraph(node, r);
 
-
 		App.Events.addResponses(node, [
 			new App.Events.Result(`"I want them dead. Now."`, kill),
 			new App.Events.Result(`"I want them, dead or alive!"`, find),
@@ -79,17 +72,14 @@ App.Events.secExpSmilingMan1 = class secExpSmilingMan1 extends App.Events.BaseEv
 			V.SecExp.smilingMan.relationship--;
 			return `You command your loyal operatives to double down on the search and elimination of the threat.`;
 		}
-
 		function find() {
 			V.SecExp.smilingMan.relationship++;
 			return `You command your loyal operatives to double down on the search and capture of the threat.`;
 		}
-
 		function findFast() {
 			V.SecExp.smilingMan.relationship += 2;
 			return `You command your loyal operatives to double down on the search and neutralization of the threat.`;
 		}
-
 		function peace() {
 			return `You take no further action. Hopefully this ordeal is over.`;
 		}
diff --git a/src/Mods/SecExp/events/secExpSmilingMan2.js b/src/Mods/SecExp/events/secExpSmilingMan2.js
index 021d1cac5f5a64553ad54a15c939e0fc5e0e9bb8..c1bc510d96ac2785f60eb5fe443ef73365f6f152 100644
--- a/src/Mods/SecExp/events/secExpSmilingMan2.js
+++ b/src/Mods/SecExp/events/secExpSmilingMan2.js
@@ -1,19 +1,16 @@
 App.Events.secExpSmilingMan2 = class secExpSmilingMan2 extends App.Events.BaseEvent {
 	eventPrerequisites() {
 		return [
-			() => V.rival.state <= 1 || V.rival.state > 2,
 			() => V.secExpEnabled > 0,
-			() => V.SecExp.smilingMan.progress === 2,
-			() => App.Events.effectiveWeek() >= 82,
 		];
 	}
 
 	execute(node) {
-		let r = [];
+		App.Events.queueEvent(0, new App.Events.secExpSmilingMan3());
+		V.fcnn.push("...my money safe the old-fashioned way: I store it all underneath my mattress...");
 		V.SecExp.smilingMan.progress++;
-
+		let r = [];
 		const {hisA} = getPronouns(assistant.pronouns().main).appendSuffix("A");
-		V.fcnn.push("...my money safe the old-fashioned way: I store it all underneath my mattress...");
 
 		r.push(`When ${V.assistant.name} violently wakes you up, ${hisA} worried expression can mean only one thing: the Smiling Man had been back. "We were anonymously sent a link to a new website: it's a very simple site, no visuals, no text; only a countdown ticking away. It will reach zero this evening." your assistant says.`);
 		r.push(`This is troubling, yet somewhat exciting. The Smiling Man never failed to cause damage, but his ego had gotten the best of him this time — having time to prepare before their attack will give you a chance to find them. For the rest of the day you do your best to plan, prepare and focus.`);
@@ -79,17 +76,14 @@ App.Events.secExpSmilingMan2 = class secExpSmilingMan2 extends App.Events.BaseEv
 			V.SecExp.smilingMan.relationship--;
 			return `You command your loyal operatives to prepare for a manhunt.`;
 		}
-
 		function find() {
 			V.SecExp.smilingMan.relationship++;
 			return `You command your loyal operatives to prepare for a manhunt.`;
 		}
-
 		function findFast() {
 			V.SecExp.smilingMan.relationship += 2;
 			return `You command your loyal operatives to prepare for a manhunt.`;
 		}
-
 		function peace() {
 			return `You take no further action. Hopefully this ordeal is finally over.`;
 		}
diff --git a/src/Mods/SecExp/events/secExpSmilingMan3.js b/src/Mods/SecExp/events/secExpSmilingMan3.js
index c11f7de1eb9c274bc3ced369e4b5482fcdb42b24..17a8269c5471685c25a6e8107f2967cda1911a86 100644
--- a/src/Mods/SecExp/events/secExpSmilingMan3.js
+++ b/src/Mods/SecExp/events/secExpSmilingMan3.js
@@ -1,30 +1,23 @@
 App.Events.secExpSmilingMan3 = class secExpSmilingMan3 extends App.Events.BaseEvent {
 	eventPrerequisites() {
 		return [
-			() => V.rival.state <= 1 || V.rival.state > 2,
 			() => V.secExpEnabled > 0,
-			() => V.SecExp.smilingMan.progress === 3,
 		];
 	}
 
 	execute(node) {
+		V.fcnn.push("...sometimes high-tech problems have low-tech solutions. Back to you in the...");
+		V.nextButton = " ";
 		let r = [];
+		const smileSlave = GenerateNewSlave(V.seeDicks !== 100 ? "XX" : "XY", {
+			minAge: 16, maxAge: 18, ageOverridesPedoMode: 1, disableDisability: 1, race: "asian", nationality: "Japanese"
+		});
 
-		let smileSlave;
+		smileSlave.faceShape = V.seeDicks !== 100 ? "cute" : "androgynous";
+		smileSlave.boobs = V.seeDicks !== 100 ? 450 : 250;
 		if (V.seeDicks !== 100) {
-			smileSlave = GenerateNewSlave("XX", {
-				minAge: 16, maxAge: 18, ageOverridesPedoMode: 1, disableDisability: 1, race: "asian", nationality: "Japanese"
-			});
-			smileSlave.faceShape = "cute";
-			smileSlave.boobs = 450;
 			smileSlave.vagina = 0;
 			smileSlave.ovaries = 1;
-		} else {
-			smileSlave = GenerateNewSlave("XY", {
-				minAge: 16, maxAge: 18, ageOverridesPedoMode: 1, disableDisability: 1, race: "asian", nationality: "Japanese"
-			});
-			smileSlave.boobs = 250;
-			smileSlave.faceShape = "androgynous";
 		}
 		smileSlave.boobShape = "perky";
 		smileSlave.nipples = "cute";
@@ -69,8 +62,6 @@ App.Events.secExpSmilingMan3 = class secExpSmilingMan3 extends App.Events.BaseEv
 			His, He,
 			his, he, him, girl
 		} = getPronouns(smileSlave);
-		V.nextButton = " ";
-		V.fcnn.push("...sometimes high-tech problems have low-tech solutions. Back to you in the...");
 
 		r.push(`The day has come to finally put an end to this story. Your men are ready to go, waiting only on your signal. You quickly don your protective gear and proceed down the busy streets of your arcology.`);
 		r.push(`You carefully planned the day so that nothing could exit the arcology without being scanned at least three times and poked twice. The Smiling Man has no escape.`);
@@ -87,10 +78,8 @@ App.Events.secExpSmilingMan3 = class secExpSmilingMan3 extends App.Events.BaseEv
 		function inside() {
 			const frag = new DocumentFragment();
 			let r = [];
+			App.Events.drawEventArt(frag, smileSlave);
 
-			if (V.seeImages === 1) {
-				App.Events.drawEventArt(frag, smileSlave);
-			}
 			r.push(`"So it was you to find me first.`);
 			if (V.SecExp.smilingMan.relationship > 2) {
 				r.push(`I was hoping you would be the one!`);
@@ -117,14 +106,11 @@ App.Events.secExpSmilingMan3 = class secExpSmilingMan3 extends App.Events.BaseEv
 				r.push(`You decide it would be criminally wasteful to throw away such talent. You offer ${him} a new life at your side. ${His} expertise will surely guarantee safety, if not supremacy, to your arcology in cyberspace, while ${he} will have safety and luxury in the physical world.`);
 				r.push(App.UI.DOM.link(
 					"Continue",
-					() => {
-						$(node).empty().append(result());
-					}
+					() => { $(node).empty().append(result()); }
 				));
 				App.Events.addParagraph(frag, r);
 				return frag;
 			}
-
 			function punish() {
 				const frag = new DocumentFragment();
 				let r = [];
@@ -132,14 +118,11 @@ App.Events.secExpSmilingMan3 = class secExpSmilingMan3 extends App.Events.BaseEv
 				r.push(`You decide to end ${his} pitiful life. ${He} has crossed the wrong master of the new world ${he} worked so hard to create. No mercy was asked for and no mercy will be given.`);
 				r.push(App.UI.DOM.link(
 					"Continue",
-					() => {
-						$(node).empty().append(result());
-					}
+					() => { $(node).empty().append(result()); }
 				));
 				App.Events.addParagraph(frag, r);
 				return frag;
 			}
-
 			function enslave() {
 				const frag = new DocumentFragment();
 				let r = [];
@@ -147,14 +130,11 @@ App.Events.secExpSmilingMan3 = class secExpSmilingMan3 extends App.Events.BaseEv
 				r.push(`You decide to enslave the ${girl}. ${His} skill may be great, but ${his} crimes are equally so, which will make it all the sweeter to turn ${him} into an obedient little toy to play with.`);
 				r.push(App.UI.DOM.link(
 					"Continue",
-					() => {
-						$(node).empty().append(result());
-					}
+					() => { $(node).empty().append(result()); }
 				));
 				App.Events.addParagraph(frag, r);
 				return frag;
 			}
-
 			function result() {
 				const frag = new DocumentFragment();
 				let r = [];
@@ -162,9 +142,8 @@ App.Events.secExpSmilingMan3 = class secExpSmilingMan3 extends App.Events.BaseEv
 				App.Utils.scheduleSidebarRefresh();
 				window.scrollTo(0, window.pageYOffset);
 				if (V.SecExp.smilingMan.progress < 30) {
-					if (V.seeImages === 1) {
-						App.Events.drawEventArt(frag, smileSlave);
-					}
+					App.Events.drawEventArt(frag, smileSlave);
+
 					if (V.SecExp.smilingMan.progress === 10) {
 						r.push(`The ${girl} asks for a few minutes to think about your offer,`);
 						if (V.SecExp.smilingMan.relationship >= 4) {
diff --git a/src/Mods/SecExp/js/secExp.js b/src/Mods/SecExp/js/secExp.js
index 293c029b6f93f4a5fa27b27e77037aa8e821d999..1db9a45cca83a184ad7b8e6b17ce0a9d3818328f 100644
--- a/src/Mods/SecExp/js/secExp.js
+++ b/src/Mods/SecExp/js/secExp.js
@@ -20,7 +20,7 @@ App.Mods.SecExp.generator = (function() {
 	function attack() {
 		let attackChance = 0; // attackChance value is the chance out of 100 of an attack happening this week
 		// attacks are deactivated if security drones are not around yet, there is not a rebellion this week or the last attack/rebellion happened within 3 weeks
-		if (V.arcologyUpgrade.drones === 1 && V.SecExp.war.type === "" && V.SecExp.battles.lastEncounterWeeks > 3 && V.SecExp.rebellions.lastEncounterWeeks > 3) {
+		if (V.arcologyUpgrade.drones === 1 && !V.SecExp.war.type && V.SecExp.battles.lastEncounterWeeks > 3 && V.SecExp.rebellions.lastEncounterWeeks > 3) {
 			if (V.week < 30) {
 				attackChance = 5;
 			} else if (V.week < 60) {
@@ -205,11 +205,11 @@ App.Mods.SecExp.generator = (function() {
 			}
 		}
 
-		if (V.SecExp.settings.rebellion.force === 1 && V.SecExp.war.foughtThisWeek === 0) {
+		if (V.SecExp.settings.rebellion.force === 1) {
 			V.SecExp.war.type = `${random(1, 100) <= 50 ? 'Slave' : 'Citizen'} Rebellion`;
 		}
 
-		if (V.SecExp.war.type === "") {
+		if (!V.SecExp.war.type) {
 			V.SecExp.rebellions.lastEncounterWeeks++;
 		} else {
 			const isSlaveRebellion = V.SecExp.war.type.includes("Slave");
@@ -262,135 +262,6 @@ App.Mods.SecExp.militiaCap = function(x = 0) {
 	}
 };
 
-App.Mods.SecExp.initTrade = function() {
-	if (V.SecExp.core.trade === 0 || !jsDef(V.SecExp.core.trade)) {
-		let init = jsRandom(20, 30);
-		if (V.terrain === "urban") {
-			init += jsRandom(10, 10);
-		} else if (V.terrain === "ravine") {
-			init -= jsRandom(5, 5);
-		}
-		if (isPCCareerInCategory("wealth") || isPCCareerInCategory("capitalist") || isPCCareerInCategory("celebrity") || isPCCareerInCategory("BlackHat")) {
-			init += jsRandom(5, 5);
-		} else if (isPCCareerInCategory("escort") || isPCCareerInCategory("gang") || isPCCareerInCategory("servant")) {
-			init -= jsRandom(5, 5);
-		}
-		V.SecExp.core.trade = init;
-	}
-};
-
-App.Mods.SecExp.generalInit = function() {
-	if (V.secExpEnabled === 0) {
-		return;
-	}
-
-	Object.assign(V.SecExp, {
-		battles: {
-			major: 0,
-			slaveVictories: [],
-			lastSelection: [],
-			victories: 0,
-			victoryStreak: 0,
-			losses: 0,
-			lossStreak: 0,
-			lastEncounterWeeks: 0,
-			saved: {}
-		},
-		rebellions: {
-			tension: 0,
-			slaveProgress: 0,
-			citizenProgress: 0,
-			victories: 0,
-			losses: 0,
-			lastEncounterWeeks: 0,
-			repairTime: {},
-		},
-		core: {
-			trade: 0,
-			authority: 0,
-			security: 100,
-			crimeLow: 30,
-			totalKills: 0,
-		},
-		settings: {
-			difficulty: 1,
-			unitDescriptions: 0,
-			showStats: 0,
-			battle: {
-				enabled: 1,
-				allowSlavePrestige: 1,
-				force: 0,
-				frequency: 1,
-				major: {
-					enabled: 0,
-					gameOver: 1,
-					mult: 1,
-					force: 0
-				}
-			},
-			rebellion: {
-				enabled: 1,
-				force: 0,
-				gameOver: 1,
-				speed: 1
-			}
-		},
-		buildings: {},
-		proclamation: {
-			cooldown: 0,
-			currency: "",
-			type: "crime"
-		},
-		units: {},
-		edicts: {
-			alternativeRents: 0,
-			enslavementRights: 0,
-			sellData: 0,
-			propCampaignBoost: 0,
-			tradeLegalAid: 0,
-			taxTrade: 0,
-			slaveWatch: 0,
-			subsidyChurch: 0,
-			SFSupportLevel: 0,
-			limitImmigration: 0,
-			openBorders: 0,
-			weaponsLaw: 3,
-			defense: {
-				soldierWages: 1,
-				slavesOfficers: 0,
-				discountMercenaries: 0,
-				militia: 0,
-				militaryExemption: 0,
-				noSubhumansInArmy: 0,
-				pregExemption: 0,
-				liveTargets: 0,
-				privilege: {
-					militiaSoldier: 0,
-					slaveSoldier: 0,
-					mercSoldier: 0,
-				},
-				// Soldiers
-				martialSchool: 0,
-				eliteOfficers: 0,
-				lowerRequirements: 0,
-				// FS soldiers
-				legionTradition: 0,
-				eagleWarriors: 0,
-				ronin: 0,
-				sunTzu: 0,
-				mamluks: 0,
-				pharaonTradition: 0,
-			}
-		},
-		smilingMan: {progress: 0}
-	});
-
-	for (const [unit] of App.Mods.SecExp.unit.list()) {
-		App.Mods.SecExp.unit.gen(unit);
-	}
-	App.Mods.SecExp.initTrade();
-};
-
 App.Mods.SecExp.battle = (function() {
 	"use strict";
 	const unitFunctions = App.Mods.SecExp.unit;
diff --git a/src/Mods/SecExp/js/secExpBC.js b/src/Mods/SecExp/js/secExpObject.js
similarity index 84%
rename from src/Mods/SecExp/js/secExpBC.js
rename to src/Mods/SecExp/js/secExpObject.js
index d645ae5fb31b41fc5096aae17709f9ca2bcf4cf8..5425b3e89f4ac0e5a03b692997369a3cb26c709d 100644
--- a/src/Mods/SecExp/js/secExpBC.js
+++ b/src/Mods/SecExp/js/secExpObject.js
@@ -1,5 +1,8 @@
 // @ts-nocheck
-App.Mods.SecExp.generalBC = function() {
+/**
+	* @param {string} mode
+	*/
+App.Mods.SecExp.object = function(mode) {
 	if (jsDef(V.secExp)) {
 		if (V.secExpEnabled !== 1) {
 			V.secExpEnabled = V.secExp;
@@ -11,14 +14,17 @@ App.Mods.SecExp.generalBC = function() {
 
 	delete V.SecExp.army;
 
-	if (V.secExpEnabled === 0) {
+	if (V.secExpEnabled === 0 || (mode === "in-game" && Object.entries(V.SecExp).length > 0)) {
 		return;
 	}
+	V.SecExp.war = V.SecExp.war || {};
 	V.SecExp.settings = V.SecExp.settings || {};
 	V.SecExp.edicts = V.SecExp.edicts || {};
 	V.SecExp.edicts.defense = V.SecExp.edicts.defense || {};
 	V.SecExp.units = V.SecExp.units || {};
-	V.SecExp.units.bots = V.SecExp.units.bots || {};
+	if (mode !== "init") {
+		V.SecExp.units.bots = V.SecExp.units.bots || {};
+	}
 	V.SecExp.smilingMan = V.SecExp.smilingMan || {};
 	V.SecExp.core = V.SecExp.core || {};
 	V.SecExp.battles = V.SecExp.battles || {};
@@ -90,39 +96,41 @@ App.Mods.SecExp.generalBC = function() {
 
 	for (const [unit, data] of App.Mods.SecExp.unit.list()) {
 		App.Mods.SecExp.unit.gen(unit);
-		V.SecExp.units[unit].squads.forEach(u => {
-			if (unit === 'bots') {
-				u.active = Math.max(0, u.active) || V.arcologyUpgrade.drones > 0 ? 1 : 0;
-				u.troops = Math.max(u.troops || 0, V.arcologyUpgrade.drones > 0 ? 30 : 0);
-				u.maxTroops = Math.max(u.maxTroops || 0, V.arcologyUpgrade.drones > 0 ? 30 : 0);
-				if (V.secBots) {
-					V.SecExp.units.bots.squads[0] = Object.assign(V.secBots, {platoonName: "1st " + data.defaultName});
-				}
-				if (V.SecExp.units[unit].squads.length === 1 && !u.platoonName) {
-					u.platoonName = "1st " + data.defaultName;
-				}
-			} else {
-				u.SF = u.SF || 0;
-				if (!jsDef(u.ID)) {
-					u.ID = genID();
+		if (mode !== "init") {
+			V.SecExp.units[unit].squads.forEach(u => {
+				if (unit === 'bots') {
+					u.active = Math.max(0, u.active) || V.arcologyUpgrade.drones > 0 ? 1 : 0;
+					u.troops = Math.max(u.troops || 0, V.arcologyUpgrade.drones > 0 ? 30 : 0);
+					u.maxTroops = Math.max(u.maxTroops || 0, V.arcologyUpgrade.drones > 0 ? 30 : 0);
+					if (V.secBots) {
+						V.SecExp.units.bots.squads[0] = Object.assign(V.secBots, {platoonName: "1st " + data.defaultName});
+					}
+					if (V.SecExp.units[unit].squads.length === 1 && !u.platoonName) {
+						u.platoonName = "1st " + data.defaultName;
+					}
+				} else {
+					u.SF = u.SF || 0;
+					if (!jsDef(u.ID)) {
+						u.ID = genID();
+					}
+					u.cyber = u.cyber || 0;
+					u.commissars = u.commissars || 0;
+					u.troops = Math.clamp(u.troops, 0, u.maxTroops || 30);
+					u.training = Math.clamp(u.training, 0, 100);
+					if (V.SF.Active < 1) {
+						u.SF = 0;
+					}
 				}
-				u.cyber = u.cyber || 0;
-				u.commissars = u.commissars || 0;
-				u.troops = Math.clamp(u.troops, 0, u.maxTroops || 30);
-				u.training = Math.clamp(u.training, 0, 100);
-				if (V.SF.Active < 1) {
-					u.SF = 0;
+	
+				if (unit !== 'bots' && u.platoonName.contains('undefined')) {
+					u.platoonName = u.platoonName.replace('undefined', data.defaultName);
 				}
-			}
-
-			if (unit !== 'bots' && u.platoonName.contains('undefined')) {
-				u.platoonName = u.platoonName.replace('undefined', data.defaultName);
-			}
-
-			App.Mods.SecExp.unit.genID(u, unit);
-			u.equip = u.equip || 0;
-			delete u.isDeployed;
-		});
+	
+				App.Mods.SecExp.unit.genID(u, unit);
+				u.equip = u.equip || 0;
+				delete u.isDeployed;
+			});
+		}
 	}
 
 	if (V.SecExp.units.mercs.free === 0) {
@@ -167,7 +175,20 @@ App.Mods.SecExp.generalBC = function() {
 
 	delete V.SecExp.core.crimeCap;
 	V.SecExp.core.trade = V.SecExp.core.trade || V.trade || 0;
-	App.Mods.SecExp.initTrade();
+	if (V.SecExp.core.trade === 0 || !jsDef(V.SecExp.core.trade)) {
+		let init = jsRandom(20, 30);
+		if (V.terrain === "urban") {
+			init += jsRandom(10, 10);
+		} else if (V.terrain === "ravine") {
+			init -= jsRandom(5, 5);
+		}
+		if (isPCCareerInCategory("wealth") || isPCCareerInCategory("capitalist") || isPCCareerInCategory("celebrity") || isPCCareerInCategory("BlackHat")) {
+			init += jsRandom(5, 5);
+		} else if (isPCCareerInCategory("escort") || isPCCareerInCategory("gang") || isPCCareerInCategory("servant")) {
+			init -= jsRandom(5, 5);
+		}
+		V.SecExp.core.trade = init;
+	}
 
 	V.SecExp.core.authority = V.SecExp.core.authority || V.authority || 0;
 	V.SecExp.core.security = V.SecExp.core.security || V.security || 100;
@@ -291,12 +312,14 @@ App.Mods.SecExp.generalBC = function() {
 		V.SecExp.settings.showStats = V.showBattleStatistics;
 	}
 
-	App.Mods.SecExp.BC.propHub();
-	App.Mods.SecExp.BC.barracks();
-	App.Mods.SecExp.BC.secHub();
-	App.Mods.SecExp.BC.transportHub();
-	App.Mods.SecExp.BC.riotCenter();
-	App.Mods.SecExp.BC.weaponsManufacturing();
+	if (mode === "BC") {
+		App.Mods.SecExp.BC.propHub();
+		App.Mods.SecExp.BC.barracks();
+		App.Mods.SecExp.BC.secHub();
+		App.Mods.SecExp.BC.transportHub();
+		App.Mods.SecExp.BC.riotCenter();
+		App.Mods.SecExp.BC.weaponsManufacturing();
+	}
 
 	V.SecExp.proclamation.cooldown = V.SecExp.proclamation.cooldown || V.proclamationsCooldown || 0;
 	V.SecExp.proclamation.currency = V.SecExp.proclamation.currency || V.proclamationCurrency || "";
diff --git a/src/Mods/SpecialForce/SpecialForceFS.js b/src/Mods/SpecialForce/SpecialForceFS.js
index 5835b1237d253f5045b4c86b3bb113b7ecc1543b..9253971efcd9a609cadc3afaebe99d16faf00afe 100644
--- a/src/Mods/SpecialForce/SpecialForceFS.js
+++ b/src/Mods/SpecialForce/SpecialForceFS.js
@@ -419,7 +419,7 @@ App.Mods.SF.fsIntegration = (function() {
 				break;
 			case 'Roman_Revivalism':
 				dec = `Roman Revivalism: a vision of a new Rome.`;
-				gift = `The Colonel has been bestowed with an unmistakable and peerless. badge of office - a mastercrafted SPATHI sword, forged from nigh-unbreakable metals, made extremely sharp with the help of a machine that she also now owns, and equipped with an inbuilt communications array, holographic display projector, recharging port, and fingerprint scanner that delivers electric shocks to anyone other than The Colonel when wielded. It comes with an immaculate sheath, and a complementary gold-wrought laurel wreath and fine linen toga, further enabling her to command the legions of the Firebase with absolute authority and authenticity within the Roman tradition.`;
+				gift = `The Colonel has been bestowed with an unmistakable and peerless badge of office - a mastercrafted SPATHI sword, forged from nigh-unbreakable metals, made extremely sharp with the help of a machine that she also now owns, and equipped with an inbuilt communications array, holographic display projector, recharging port, and fingerprint scanner that delivers electric shocks to anyone other than The Colonel when wielded. It comes with an immaculate sheath, and a complementary gold-wrought laurel wreath and fine linen toga, further enabling her to command the legions of the Firebase with absolute authority and authenticity within the Roman tradition.`;
 				foods = `You spare no expense to supply your troops with increasingly rare boar and deer meat, distinctive of Roman cuisine.`;
 				media = `Soldiers also enjoy fresh fruits while watching gladiator games, public speakings of famous orators or the history of Ancient Rome on wall-screen TV.`;
 				slaves = `All of the slaves serving here are from outside of your arcology, captured during the many military expeditions staged from the Firebase.`;
@@ -810,7 +810,7 @@ App.Mods.SF.fsIntegration = (function() {
 				r += `Finally fed up with your constant intrusions into her territory and crew, The Colonel riles up her people for a full takeover against your arcology. The promises of plunder and dominion over some of the wealthiest tenants in the entire Free City (and their world-class slaves), including you, are all that's needed to get things started.`;
 				r += `<br>At midnight, the lights are the first thing The Colonel's forces disable, as they still have the excellent night vision equipment you purchased for them. Some of your citizens panic almost immediately at the sudden blackout; this is very reminiscent of the Daughters of Liberty attack that still haunts many of their memories. Her army vanguard strikes fast and hard throughout, cutting through your security units and drones with an ease that stinks of months of careful planning and study. Most disturbingly, your penthouse's communications networks are all but destroyed, and your PA has been unreachable, seemingly hacked by some obscure technology you figure only The Colonel's contacts and few others could provide.`;
 				r += `<br>Outside, her many aircraft swarm the local airspace to patrol the arcology outskirts, conduct recon scans of the upper levels, or monitor your now-secured penthouse, while shooting down any other fleeing VTOL's. You will not be escaping by air. No one will. No escaping by land either: Swarms of her drones are tasing fleeing noncombatants by the hundreds for detainment, as the remainder of her army seizes control of vital arcology infrastructure. After just a few days, the entire arcology falls under her direct control, all dissidents, criminals, and rebels hopelessly outgunned by her lavishly equipped and experienced warriors.`;
-				r += `<br>You are trapped inside your Penthouse by the detachment of infantry guarding its exits in order to keep you in, probably with the goal of starving you out until you surrender yourself. With your communications down as well. your penthouse might as well be an island. You only salvation comes in the form of your neighboring arcologies and their respective mercenary contingents. They are intervening on your behalf out of paranoia; Free Cities are extremely wary of military power buildups near their borders, and they absolutely will not tolerate a full scale military coup within its borders. Fighting men and women from all over the City are seen battling in the streets of your arcology in a brutal blitzkrieg that your own tenants and mercenaries quickly join in on, pushing The Colonel's forces back gradually with sheer numbers. Eventually they are forced back into the Firebase proper, where they are sealed inside by using explosives to collapse part of the arcology atop them, rendering the Firebase itself totally defunct. Only a few small groups manage to scatter and flee this holding action, and your intelligence networks suspects that The Colonel herself was among one of them.`;
+				r += `<br>You are trapped inside your Penthouse by the detachment of infantry guarding its exits in order to keep you in, probably with the goal of starving you out until you surrender yourself. With your communications down as well, your penthouse might as well be an island. You only salvation comes in the form of your neighboring arcologies and their respective mercenary contingents. They are intervening on your behalf out of paranoia; Free Cities are extremely wary of military power buildups near their borders, and they absolutely will not tolerate a full scale military coup within its borders. Fighting men and women from all over the City are seen battling in the streets of your arcology in a brutal blitzkrieg that your own tenants and mercenaries quickly join in on, pushing The Colonel's forces back gradually with sheer numbers. Eventually they are forced back into the Firebase proper, where they are sealed inside by using explosives to collapse part of the arcology atop them, rendering the Firebase itself totally defunct. Only a few small groups manage to scatter and flee this holding action, and your intelligence networks suspects that The Colonel herself was among one of them.`;
 				r += `With the help of some unlikely intervention, you've won this little war. Your arcology is once more yours, but your people will never forget the traumatic week they spent under the heel of the army that you convinced them to allow, or the fact that it took an entire coalition of outsiders to save them.`;
 				break;
 			case "jaded":
diff --git a/src/art/webgl/art.js b/src/art/webgl/art.js
index 23560d11b93946e738f5339ead8a82d0fcbe426b..cedf59222987981359832f4889067cd11cf56197 100644
--- a/src/art/webgl/art.js
+++ b/src/art/webgl/art.js
@@ -1822,186 +1822,262 @@ App.Art.applyMaterials = function(slave, scene, p) {
 	}
 };
 
-App.Art.fps = 12;
-App.Art.animLength = 0; // how many seconds the anim will play over
-App.Art.animWaitTime = 0; // how long to wait until playing the next anim
-App.Art.currentAnim = "";
-App.Art.currentAnimFrame = 0;
-App.Art.animFacialExpChange = false; // hopefully temporary until more facial exp options become available -- lets it randomly decide whether to change facial expression or just neutralise
-App.Art.animBreathState = 0; // tracker for cyclic breathing animation
-App.Art.animRespRate = Math.floor(Math.random() * 6) + 6; // variable resp rate
-
-App.Art.getAnimState = function(morphs, isAnimTick) {
-	// TODO: separate body and facial animation lists, with separate picker and timings
-	let animList = ["idle1", "idle2", "idle3"];
-
-	// select a new animation to play
-	if (App.Art.currentAnim === "") {
-		App.Art.currentAnim = animList[Math.floor(Math.random() * animList.length)];
-		App.Art.animLength = (Math.random() * 4) + 2;
-		App.Art.animWaitTime = (Math.floor(Math.random() * 50) + 10) * App.Art.fps;
-		App.Art.currentAnimFrame = 0;
-		App.Art.animFacialExpChange = Math.random() > 0.8;
-	}
-
-	// figure out which 'base' poses/expressions are in play -- this is ugly and inefficient
-	let currentPose = "";
-	let currentPoseIndex = 0;
-	let currentExpression = "";
-	let currentExpressionIndex = 0;
-	let breathingMorph = "";
-	let breathingMorphIndex = 0;
-	// let blinkMorph = "";
-	// let blinkMorphIndex = 0;
-	let armPose = "";
-	let armPoseIndex = 0; // hack workaround for weight based arm position changes
-
-	for (let i = 0; i < morphs.length; i++) {
-		// get body pose
-		if (morphs[i][0] === "posesHigh") {
-			currentPose = "posesHigh";
-			currentPoseIndex = i;
-		} else if (morphs[i][0] === "posesMid") {
-			currentPose = "posesMid";
-			currentPoseIndex = i;
-		} else if (morphs[i][0] === "posesLow") {
-			currentPose = "posesLow";
-			currentPoseIndex = i;
-		}
-
-		// get facial expression
-		if (morphs[i][0] === "expressionsFear") {
-			currentExpression = "expressionsFear";
-			currentExpressionIndex = i;
-		} else if (morphs[i][0] === "expressionsHappy") {
-			currentExpression = "expressionsHappy";
-			currentExpressionIndex = i;
-		}
-
-		// get breathing chest morph
-		if (morphs[i][0] === "bodyShape2") {
-			breathingMorph = "bodyShape2";
-			breathingMorphIndex = i;
+// array variables - pose || face || breathing || blink || look X || look Y
+App.Art.animLength = [0, 0, 0, 0, 0, 0]; // how many seconds the anim will play over
+App.Art.animPower = [0, 0, 0, 0, 0, 0]; // morph strength
+App.Art.animDelay = [0, 0, 0, 0, 0, 0];  // how long to wait until playing the next anim
+App.Art.currentAnim = ["", "", "", "", "", ""];
+App.Art.animFrame = [0, 0, 0, 0, 0, 0]; // tracking how many frames into the anim
+App.Art.eyeMoveReciprocal = jsEither([true, false]); // randomly decides whether eye movements follow head movements
+
+App.Art.getAnimState = function(slave, scene, p, morphs, isAnimTick) {
+
+	const poseAnimList = ["idle1", "idle2", "idle3"];
+	const faceAnimList = [];
+	if (Math.random() < (slave.trust + 100) / 200) {
+		// trusting slave - happy animations
+		faceAnimList.push("expressionsHappy", "expressionsHappyCheerful", "expressionsHappyDelighted", "expressionsHappyFriendly", "expressionsHappySweet");
+	}
+	else {
+		// fearful slave - fear/sad animations
+		faceAnimList.push("expressionsFear", "expressionsFearAlarm", "expressionsFearAnticipation", "expressionsFearFrightened", "expressionsSadConfused", "expressionsSadOffended", "expressionsSadDejected", "expressionsSadIll");
+	}
+	if (Math.random() < (slave.devotion + 100) / 200) {
+		// devoted slave - seductive animations
+		faceAnimList.push("expressionsSeductiveDesire", "expressionsSeductiveLoving");
+	}
+	else {
+		// hateful slave - angry animations
+		faceAnimList.push("expressionsAngerFierce", "expressionsAngerGrumpy", "expressionsAngerSnarl");
+	}
+	const animList = [poseAnimList, faceAnimList];
+
+	const animState = [0, 0, 0, 0, 0, 0];
+
+	// run animations from here
+	for (let i = 0; i < App.Art.animFrame.length; i++) {
+		// reset anim
+		if (App.Art.currentAnim[i] === "") {
+			switch (i) {
+				case 0: // pose
+					App.Art.currentAnim[i] = animList[i][Math.floor(Math.random() * animList[i].length)];
+					App.Art.animLength[i] = (Math.random() * 4) + 2;
+					App.Art.animDelay[i] = (Math.floor(Math.random() * 20) + 5) * V.animFPS;
+					break;
+				case 1: // facial exp
+					App.Art.currentAnim[i] = animList[i][Math.floor(Math.random() * animList[i].length)];
+					App.Art.animLength[i] = (Math.random() * 4) + 1;
+					App.Art.animDelay[i] = (Math.floor(Math.random() * 20) + 10) * V.animFPS;
+					App.Art.animPower[i] = (Math.random() * 0.75) + 0.25;
+					break;
+				case 2: // breathing
+					App.Art.currentAnim[i] = "breathAnim";
+					App.Art.animLength[i] = (Math.random() * 2) + 2;
+					App.Art.animDelay[i] = (Math.floor(Math.random() * 2) + 1) * V.animFPS;
+					App.Art.animPower[i] = (Math.random() * 0.025) + 0.025;
+					break;
+				case 3: // blink
+					App.Art.currentAnim[i] = "blinkAnim";
+					App.Art.animLength[i] = (Math.random() * 0.25) + 0.25;
+					App.Art.animDelay[i] = (Math.floor(Math.random() * 8) + 2) * V.animFPS;
+					break;
+				case 4: // look X
+				case 5: // look Y
+					if (App.Art.currentAnim[4] === "" && App.Art.currentAnim[5] === "") {
+						App.Art.currentAnim[4] = jsEither(["headBendLeft", "headTwistLeft", "headBendRight", "headTwistRight"]);
+						App.Art.animLength[4] = (Math.random() * 2) + 0.5;
+						App.Art.animDelay[4] = (Math.floor(Math.random() * 10) + 5) * V.animFPS;
+						App.Art.animPower[4] = Math.random();
+						
+						App.Art.currentAnim[5] = ((Math.random() < (slave.trust + 100) / 200) ? "down" : "up");
+						App.Art.eyeMoveReciprocal = (Math.random() > (slave.trust + 100) / 200);
+						App.Art.animLength[5] = (Math.random() * 2) + 0.5;
+						App.Art.animDelay[5] = (Math.floor(Math.random() * 10) + 5) * V.animFPS;
+						App.Art.animPower[5] = Math.random();
+					}
+					break;
+			}
+			App.Art.animFrame[i] = 0;
 		}
 
-		// get blinking morph
-		/*
-		if (morphs[i][0] === "eyeShapeOpen") {
-			blinkMorph = "eyeShapeOpen";
-			blinkMorphIndex = i;
-		}
-		*/
+		animState[i] = Math.sin((Math.PI / (Math.floor(App.Art.animLength[i] * V.animFPS))) * App.Art.animFrame[i] - (Math.PI / 2));
 
-		// get arm pose
-		if (morphs[i][0] === "posesArmsDown") {
-			armPose = "posesArmsDown";
-			armPoseIndex = i;
+		function getAnimState(morphPower) {
+			return (animState[i] / (2 / Math.abs(morphPower))) + (1 / (2 / morphPower));
 		}
-	}
 
-	let animState = Math.sin((Math.PI / (Math.floor(App.Art.animLength * App.Art.fps))) * App.Art.currentAnimFrame - (Math.PI / 2));
-
-	function getAnimState(morphPower) {
-		return (animState / (2 / Math.abs(morphPower))) + (1 / (2 / morphPower));
-	}
+		// animation picker
+		switch (i) {
+			case 0: // pose
+				// lots of things change arms down and legs closed states, so these need to be summated and pushed as one morph below
+				let slaveArmsDown = 0;
+				let slaveLegsClosed = 0;
+
+				if (!scene.inspect) {
+					if (slave.scrotum > 20) {
+						if (slave.devotion <= 50) {
+							slaveArmsDown += Math.max(Math.min(-slave.weight/300/3.5, -slave.scrotum/200), -0.5);
+						}
+		
+						if (p.applyExtremeHeels || p.applyExtremeHeels2) {
+							slaveLegsClosed += Math.max(Math.min(-slave.weight/300/3.5 - 0.5, -slave.scrotum/20), -1.5);
+						} else {
+							slaveLegsClosed += Math.max(Math.min(-slave.weight/300/3.5, -slave.scrotum/20), -1.5);
+						}
+					} else {
+						if (slave.devotion <= 50) {
+							slaveArmsDown += Math.max(-slave.weight/300/3.5, -0.5);
+						}
+		
+						if (p.applyExtremeHeels || p.applyExtremeHeels2 && !scene.inspect) {
+							slaveLegsClosed += Math.max(-slave.weight/300/3.5 - 0.5, -1.5);
+						} else {
+							slaveLegsClosed += Math.max(-slave.weight/300/3.5, -1.5);
+						}
+					}
+				}
 
-	// animation picker -- TODO: MOAR!
-	switch (App.Art.currentAnim) {
-		case "idle1":
-			// body animation
-			if (currentPose === "posesHigh") {
-				morphs[currentPoseIndex][1] -= getAnimState(0.5); // decrement base pose by 0.5 over course of animation
-				morphs.push(["posesInspect2", getAnimState(0.5)]);
-				morphs.push(["posesArmsDown", getAnimState(0.25)]);
-			} else if (currentPose === "posesMid") {
-				morphs[currentPoseIndex][1] -= getAnimState(0.5);
-				morphs.push(["posesInspect2", getAnimState(0.5)]);
-			} else if (currentPose === "posesLow") {
-				morphs[currentPoseIndex][1] -= getAnimState(0.5);
-				morphs.push(["posesInspect2", getAnimState(0.5)]);
-			}
-			break;
-		case "idle2":
-			if (currentPose === "posesHigh") {
-				morphs[currentPoseIndex][1] -= getAnimState(0.5);
-				morphs.push(["posesLow", getAnimState(0.5)]);
-			} else if (currentPose === "posesMid") {
-				morphs[currentPoseIndex][1] -= getAnimState(0.5);
-				morphs.push(["posesHigh", getAnimState(0.5)]);
-			} else if (currentPose === "posesLow") {
-				morphs[currentPoseIndex][1] -= getAnimState(0.6);
-				morphs.push(["posesHigh", getAnimState(0.4)]);
-			}
-			break;
-		case "idle3":
-			if (currentPose === "posesHigh") {
-				morphs.push(["posesInspect2", getAnimState(-0.25)]);
-				morphs.push(["posesArmsDown", getAnimState(0.25)]);
-			} else if (currentPose === "posesMid") {
-				morphs.push(["posesInspect2", getAnimState(-0.2)]);
-				if (armPose !== "") {
-					morphs[armPoseIndex][1] -= getAnimState(0.2);
+				switch (App.Art.currentAnim[i]) {
+					case "idle1":
+						if (slave.devotion > 50) {
+							morphs.push(["posesHigh", 1 - getAnimState(0.5)]);
+							if (p.applyExtremeHeels || p.applyExtremeHeels2) {
+								slaveLegsClosed -= 0.5;
+							}
+						} else if (slave.devotion > -20) {
+							morphs.push(["posesMid", 1 - getAnimState(0.5)]);
+						} else {
+							morphs.push(["posesLow", 1 - getAnimState(0.5)]);
+						}
+						morphs.push(["posesInspect2", getAnimState(0.5)]);
+						break;
+					case "idle2":
+						if (slave.devotion > 50) {
+							morphs.push(["posesHigh", 1 - getAnimState(0.4)]);
+							morphs.push(["posesLow", getAnimState(0.6)]);
+							if (p.applyExtremeHeels || p.applyExtremeHeels2) {
+								slaveLegsClosed -= 0.5;
+							}
+						} else if (slave.devotion > -20) {
+							morphs.push(["posesMid", 1 - getAnimState(0.5)]);
+							morphs.push(["posesHigh", getAnimState(0.5)]);
+						} else {
+							morphs.push(["posesLow", 1 - getAnimState(0.6)]);
+							morphs.push(["posesHigh", getAnimState(0.4)]);
+						}
+						break;
+					case "idle3":
+						if (slave.devotion > 50) {
+							morphs.push(["posesHigh", 1]);
+							morphs.push(["posesInspect2", getAnimState(-0.25)]);
+							slaveArmsDown += 0.1
+							if (p.applyExtremeHeels || p.applyExtremeHeels2) {
+								slaveLegsClosed -= 0.5;
+							}
+						} else if (slave.devotion > -20) {
+							morphs.push(["posesMid", 1]);
+							morphs.push(["posesInspect2", getAnimState(-0.2)]);
+							slaveArmsDown -= 0.2
+						} else {
+							morphs.push(["posesLow", 1 - getAnimState(0.6)]);
+							morphs.push(["posesHigh", getAnimState(0.4)]);
+						}
+						break;
 				}
-			} else if (currentPose === "posesLow") {
-				morphs[currentPoseIndex][1] -= getAnimState(0.6);
-				morphs.push(["posesHigh", getAnimState(0.4)]);
-			}
-			break;
-	}
 
-	// face animation -- currently limited to either neutral or opposite expression because that's all I've got to play with
-	morphs[currentExpressionIndex][1] -= getAnimState(morphs[currentExpressionIndex][1]);
-	if (App.Art.animFacialExpChange) {
-		if (currentExpression === "expressionsFear") {
-			morphs.push(["expressionsHappy", getAnimState(1.0)]);
-		} else if (currentExpression === "expressionsHappy") {
-			morphs.push(["expressionsFear", getAnimState(1.0)]);
+				morphs.push(["poseArmsDown", Math.min(Math.max(slaveArmsDown, 0), 1)])
+				morphs.push(["posesLegsClosed", Math.min(Math.max(slaveLegsClosed, 0), 1)])
+				break;
+			case 1: // facial exp
+				morphs.push([App.Art.currentAnim[i], getAnimState(App.Art.animPower[i])]);
+				break;
+			case 2: // breathing
+				morphs.push(["posesInspect", getAnimState(App.Art.animPower[i]) - (App.Art.animPower[i] / 2)]);
+				morphs.push(["bodyShape2", getAnimState(App.Art.animPower[i]) - (App.Art.animPower[i] / 2)]); // note, may need to change this morph if Elohiem decides to use it for something later; see commented code ln 2321
+				break;
+			case 3: // blink
+				morphs.push(["eyesClosed", Math.min(Math.max(getAnimState(1.0), 0), 1)]);
+				break;
+			case 4: // look X
+				if (App.Art.currentAnim[i] === "") {
+					break; // little catch code if it's waiting for look Y to reset
+				}
+				morphs.push([App.Art.currentAnim[i], getAnimState(App.Art.animPower[i] * 0.5)]);
+				if (App.Art.currentAnim[i] === "headBendLeft" || App.Art.currentAnim[i] === "headTwistLeft") {
+					if (App.Art.eyeMoveReciprocal) {
+						morphs.push(["eyesLookRight", getAnimState(App.Art.animPower[i] * 0.75)]);
+					}
+					else {
+						morphs.push(["eyesLookLeft", getAnimState(App.Art.animPower[i] * 0.75)]);
+					}
+				}
+				else {
+					if (App.Art.eyeMoveReciprocal) {
+						morphs.push(["eyesLookLeft", getAnimState(App.Art.animPower[i] * 0.75)]);
+					}
+					else {
+						morphs.push(["eyesLookRight", getAnimState(App.Art.animPower[i] * 0.75)]);
+					}
+				}
+				break;
+			case 5: // look Y
+				switch (App.Art.currentAnim[i]) {
+					case "up":
+						morphs.push(["headBendBackwards", getAnimState(App.Art.animPower[i] * 0.15)]);
+						if (App.Art.eyeMoveReciprocal) {
+							morphs.push(["eyesLookDown", getAnimState(App.Art.animPower[i] * 0.5)]);
+						}
+						else {
+							morphs.push(["eyesLookUp", getAnimState(App.Art.animPower[i] * 0.5)]);
+						}
+						break;
+					case "down":
+						morphs.push(["headBendForward", getAnimState(App.Art.animPower[i] * 0.25)]);
+						if (App.Art.eyeMoveReciprocal) {
+							morphs.push(["eyesLookUp", getAnimState(App.Art.animPower[i] * 0.5)]);
+						}
+						else {
+							morphs.push(["eyesLookDown", getAnimState(App.Art.animPower[i] * 0.5)]);
+						}
+						break;
+				}
+				break;
 		}
-	}
 
-	if (isAnimTick) { // this is needed so that mouse movement frame updates don't break animation state
-		if (animState === 1.0 || App.Art.currentAnimFrame === 0) { // pause during start and apogee of anim track
-			App.Art.animWaitTime--;
-			if (App.Art.animWaitTime <= 0) {
-				App.Art.animWaitTime = (Math.floor(Math.random() * 50) + 10) * App.Art.fps;
-				App.Art.currentAnimFrame++;
+		// do animation tick
+		if (isAnimTick) { // this is needed so that mouse movement frame updates don't break animation state
+			if (animState[i] === 1.0 || App.Art.animFrame[i] === 0) { // pause during start and apogee of anim track
+				App.Art.animDelay[i]--;
+				if (App.Art.animDelay[i] <= 0) {
+					switch (i) {
+						case 0: // pose
+							App.Art.animDelay[i] = (Math.floor(Math.random() * 50) + 10) * V.animFPS;
+							break;
+						case 1: // facial exp
+							App.Art.animDelay[i] = (Math.floor(Math.random() * 20) + 10) * V.animFPS;
+							break;
+						case 2: // breathing
+							App.Art.animDelay[i] = (Math.floor(Math.random() * 2) + 1) * V.animFPS;
+							break;
+						case 3: // blink
+							App.Art.animDelay[i] = 0;
+							break;
+						case 4: // look X
+						case 5: // look Y
+							App.Art.animDelay[i] = (Math.floor(Math.random() * 10) + 5) * V.animFPS;
+							break;
+					}
+					App.Art.animFrame[i]++;
+				}
+			}
+			else if (animState[i] === -1.0 && App.Art.animFrame[i] > 0) { // end of anim track
+				App.Art.currentAnim[i] = "";
+			}
+			else {
+				App.Art.animFrame[i]++;
 			}
-		} else if (animState === -1.0 && App.Art.currentAnimFrame > 0) { // end of anim track
-			App.Art.currentAnim = "";
-		} else {
-			App.Art.currentAnimFrame++;
-		}
-
-		// for breathing idle anim
-		App.Art.animBreathState++;
-	}
-
-	// breathing animation
-	if (App.Art.animBreathState > App.Art.animRespRate * App.Art.fps) {
-		App.Art.animBreathState = 0;
-		App.Art.animRespRate = Math.floor(Math.random() * 4) + 8;
-	}
-
-	let breathAnimState = Math.sin((Math.PI / (App.Art.fps * (App.Art.animRespRate / 2))) * App.Art.animBreathState - (Math.PI / 2));
-
-	morphs.push(["posesInspect", (breathAnimState / (App.Art.animRespRate * 5))]); // ewwww, MATHS
-	if (breathingMorph !== "") {
-		morphs[breathingMorphIndex][1] += breathAnimState / (App.Art.animRespRate * 4);
-	} else {
-		morphs.push(["bodyShape2", (breathAnimState / (App.Art.animRespRate * 4))]);
-	}
-
-	// random blinking -- will reimplement when I have a morph to use
-	/*
-	if (Math.random() < 0.1 / App.Art.fps) {
-		if (blinkMorph !== "") {
-			morphs[blinkMorphIndex][1] = -1.0
-		}
-		else {
-			morphs.push(["eyeShapeOpen", -1.0])
 		}
 	}
-	*/
 };
 
 App.Art.applyMorphs = function(slave, scene, p, isAnimating) {
@@ -2032,50 +2108,52 @@ App.Art.applyMorphs = function(slave, scene, p, isAnimating) {
 		morphs.push(["posesExtremeHeels2", 1]);
 	}
 
-	if (slave.arm.right && slave.arm.left && slave.leg.right && slave.leg.left) {
-		if (scene.inspect) {
-			morphs.push(["posesInspect2", 1]);
-			morphs.push(["posesInspectGen2", 1]);
-		} else if (slave.devotion > 50) {
-			morphs.push(["posesHigh", 1]);
-			if (p.applyExtremeHeels || p.applyExtremeHeels2) {
-				morphs.push(["posesLegsClosed", -0.5]);
-			}
-		} else if (slave.devotion > -20) {
-			morphs.push(["posesMid", 1]);
-		} else {
-			morphs.push(["posesLow", 1]);
-		}
-
-		if (!scene.inspect) {
-			if (slave.scrotum > 20) {
-				if (slave.devotion <= 50) {
-					morphs.push(["posesArmsDown", Math.max(Math.min(-slave.weight/300/3.5, -slave.scrotum/200), -0.5)]);
-				}
-
+	if (!isAnimating) { // animation code now handles these morphs directly
+		if (slave.arm.right && slave.arm.left && slave.leg.right && slave.leg.left) {
+			if (scene.inspect) {
+				morphs.push(["posesInspect2", 1]);
+				morphs.push(["posesInspectGen2", 1]);
+			} else if (slave.devotion > 50) {
+				morphs.push(["posesHigh", 1]);
 				if (p.applyExtremeHeels || p.applyExtremeHeels2) {
-					morphs.push(["posesLegsClosed", Math.max(Math.min(-slave.weight/300/3.5 - 0.5, -slave.scrotum/20), -1.5)]);
-				} else {
-					morphs.push(["posesLegsClosed", Math.max(Math.min(-slave.weight/300/3.5, -slave.scrotum/20), -1.5)]);
+					morphs.push(["posesLegsClosed", -0.5]);
 				}
+			} else if (slave.devotion > -20) {
+				morphs.push(["posesMid", 1]);
 			} else {
-				if (slave.devotion <= 50) {
-					morphs.push(["posesArmsDown", Math.max(-slave.weight/300/3.5, -0.5)]);
-				}
-
-				if (p.applyExtremeHeels || p.applyExtremeHeels2 && !scene.inspect) {
-					morphs.push(["posesLegsClosed", Math.max(-slave.weight/300/3.5 - 0.5, -1.5)]);
+				morphs.push(["posesLow", 1]);
+			}
+	
+			if (!scene.inspect) {
+				if (slave.scrotum > 20) {
+					if (slave.devotion <= 50) {
+						morphs.push(["posesArmsDown", Math.max(Math.min(-slave.weight/300/3.5, -slave.scrotum/200), -0.5)]);
+					}
+	
+					if (p.applyExtremeHeels || p.applyExtremeHeels2) {
+						morphs.push(["posesLegsClosed", Math.max(Math.min(-slave.weight/300/3.5 - 0.5, -slave.scrotum/20), -1.5)]);
+					} else {
+						morphs.push(["posesLegsClosed", Math.max(Math.min(-slave.weight/300/3.5, -slave.scrotum/20), -1.5)]);
+					}
 				} else {
-					morphs.push(["posesLegsClosed", Math.max(-slave.weight/300/3.5, -1.5)]);
+					if (slave.devotion <= 50) {
+						morphs.push(["posesArmsDown", Math.max(-slave.weight/300/3.5, -0.5)]);
+					}
+	
+					if (p.applyExtremeHeels || p.applyExtremeHeels2 && !scene.inspect) {
+						morphs.push(["posesLegsClosed", Math.max(-slave.weight/300/3.5 - 0.5, -1.5)]);
+					} else {
+						morphs.push(["posesLegsClosed", Math.max(-slave.weight/300/3.5, -1.5)]);
+					}
 				}
 			}
 		}
-	}
-
-	if (slave.trust < 0) {
-		morphs.push(["expressionsFear", Math.abs(slave.trust)/100]);
-	} else {
-		morphs.push(["expressionsHappy", slave.trust/100]);
+	
+		if (slave.trust < 0) {
+			morphs.push(["expressionsFear", Math.abs(slave.trust)/100]);
+		} else {
+			morphs.push(["expressionsHappy", slave.trust/100]);
+		}
 	}
 
 	// used for interpolating mixed race based on slave ID
@@ -2310,7 +2388,7 @@ App.Art.applyMorphs = function(slave, scene, p, isAnimating) {
 		morphs.push([ribShape[rib], 1]);
 	}
 
-	/*
+	/* Elohiem, if you decide to reactivate this bit, note that I'm using "bodyShape2" for breathing animations --BI
 	let bodyShape = ["bodyShape0", "bodyShape1", "bodyShape2", "bodyShape3", "bodyShape4", "bodyShape5"];
 	let body = Math.floor(App.Art.random() * bodyShape.length);
 	if (body > 0) {
@@ -2699,7 +2777,7 @@ App.Art.applyMorphs = function(slave, scene, p, isAnimating) {
 	morphs.push(["offset", 2]); // only applies to clothes
 
 	if (App.Art.runningAnim) {
-		App.Art.getAnimState(morphs, isAnimating);
+		App.Art.getAnimState(slave, scene, p, morphs, isAnimating);
 	}
 
 	App.Art.resetMorphs(scene);
diff --git a/src/art/webgl/ui.js b/src/art/webgl/ui.js
index b3f32807b60b17b76c0c57a5f38fa78c4a962119..f21be9ac047321140c73e396663b96336be5b716 100644
--- a/src/art/webgl/ui.js
+++ b/src/art/webgl/ui.js
@@ -283,8 +283,8 @@ App.Art.startAnim = function(slave, scene, view, p, cvs) {
 		App.Art.applyMorphs(slave, scene, p, true);
 		App.Art.engine.render(scene, cvs);
 	}
-	App.Art.currentAnim = ""; // clear existing animation state
-	App.Art.runningAnim = setInterval(updateFrame, 1000 / App.Art.fps);
+	App.Art.currentAnim = ["", "", "", "", "", ""]; // clear existing animation state
+	App.Art.runningAnim = setInterval(updateFrame, 1000 / V.animFPS);
 };
 
 App.Art.GetCanvasResolution = function(artSize) {
diff --git a/src/budget/costsBudget.js b/src/budget/costsBudget.js
index 03bb29fb5c79d997c79a694dc99c317ee74fc144..e17815aba0ca5c86efcbbd4a36acbe8464a105a4 100644
--- a/src/budget/costsBudget.js
+++ b/src/budget/costsBudget.js
@@ -75,7 +75,7 @@ App.Budget.costs = function() {
 
 		const p = document.createElement("p");
 
-		App.UI.DOM.appendNewElement("div", p, `The Local Economy score effects some prices in your ecology. The lower the score, the higher the prices. The base score is 100.`, ["scene-intro"]);
+		App.UI.DOM.appendNewElement("div", p, `The Local Economy score effects some prices in your ecology. The lower the score, the higher the prices. The base score is 100.`, ["detail"]);
 
 		const grid = document.createElement("div");
 		grid.className = "grid-2columns-auto";
@@ -129,7 +129,7 @@ App.Budget.costs = function() {
 	 */
 	function settings() {
 		const p = document.createElement("p");
-		App.UI.DOM.appendNewElement("div", p, "Your weekly costs are as follows:", ["detail"]);
+		App.UI.DOM.appendNewElement("h2", p, `Weekly costs`);
 
 		let options = new App.UI.OptionsGroup();
 		options.addOption("", "costsBudget", V.showAllEntries)
diff --git a/src/budget/loans.js b/src/budget/loans.js
index 5234f2eac176ad7b628c4a5e82b8cc14aed5e7b4..855278661f8a2fb0ae63c7d6d694ead5b0f1d60d 100644
--- a/src/budget/loans.js
+++ b/src/budget/loans.js
@@ -23,7 +23,18 @@ App.Budget.loans = function() {
 		const links = [];
 		const text = [];
 
-		text.push(`You can pay off a loan here.`);
+		text.push(`You`);
+		if (loan('bank')) {
+			text.push(`still owe the bank ${cashFormat(Math.trunc(loan('bank').full))}`);
+			if (loan('shark')) {
+				text.push(`and`);
+			}
+		}
+		if (loan('shark')) {
+			text.push(`have ${years(loan('shark').deadline - V.week)} to pay the shark back ${cashFormat(Math.trunc(loan('shark').full))}`);
+		}
+		text.push(text.pop() + `.`);
+		text.push(`You can pay off your loans here.`);
 
 		if (loan('bank')) {
 			const bank = loan('bank');
@@ -33,7 +44,7 @@ App.Budget.loans = function() {
 					V.loans.delete(bank);
 
 					App.UI.reload();
-				}, [], '', `You have a remaining balance of ${cashFormat(Math.trunc(bank.full))}.`));
+				}));
 			} else {
 				links.push(App.UI.DOM.disabledLink(`Pay off your bank loan`, [
 					`You lack the necessary funds to pay off this loan`,
@@ -48,7 +59,7 @@ App.Budget.loans = function() {
 					V.loans.delete(shark);
 
 					App.UI.reload();
-				}, [], '', `You have ${years(loan('shark').deadline - V.week || 1)} until the shark comes to collect.`));
+				}));
 			} else {
 				links.push(App.UI.DOM.disabledLink(`Pay off the loanshark`, [
 					`You lack the necessary funds to pay off this loan`,
diff --git a/src/data/backwardsCompatibility/backwardsCompatibility.js b/src/data/backwardsCompatibility/backwardsCompatibility.js
index dd2e299abf013d5562f1087786b0740f63635e1b..e5a404219016f570c37765c9e1f55bd9cd027fd5 100644
--- a/src/data/backwardsCompatibility/backwardsCompatibility.js
+++ b/src/data/backwardsCompatibility/backwardsCompatibility.js
@@ -86,7 +86,7 @@ App.Update.backwardsCompatibility = function() {
 	const f = document.createDocumentFragment();
 	let div;
 	try {
-		div = App.UI.DOM.appendNewElement("div", f, `Check for old version... `);
+		div = App.UI.DOM.appendNewElement("div", f, `Checking for old versions... `);
 		App.Update.oldVersions(div);
 
 		div = App.UI.DOM.appendNewElement("div", f, `Updating gene pool records... `);
@@ -436,7 +436,7 @@ App.Update.globalVariables = function(node) {
 	// Pit
 	App.Facilities.Pit.BC();
 
-	App.Mods.SecExp.generalBC();
+	App.Mods.SecExp.object("BC");
 	App.Mods.SF.BC();
 
 	// FS
@@ -1441,6 +1441,13 @@ App.Update.globalVariables = function(node) {
 		}
 	}
 
+	if (V.facility.farmyard) {
+		V.facility.farmyard.whoreIncome = V.facility.farmyard.farmhandIncome;
+		V.facility.farmyard.whoreCosts = V.facility.farmyard.farmhandCosts;
+		delete V.facility.farmyard.farmhandIncome;
+		delete V.facility.farmyard.farmhandCosts;
+	}
+
 	node.append(`Done!`);
 };
 
diff --git a/src/data/backwardsCompatibility/datatypeCleanup.js b/src/data/backwardsCompatibility/datatypeCleanup.js
index af14361979dfaa92ceca64a05095bf32b9010935..6c747999a1efdcf08bf950f35cb13c77f66a18a0 100644
--- a/src/data/backwardsCompatibility/datatypeCleanup.js
+++ b/src/data/backwardsCompatibility/datatypeCleanup.js
@@ -2305,6 +2305,10 @@ App.Entity.Utils.RARuleDatatypeCleanup = function() {
 			};
 			return jobs[assignment];
 		}
+
+		if (!cond.hasOwnProperty("advancedMode")) {
+			cond.advancedMode = true;
+		}
 	}
 
 	/** @param {object} o */
diff --git a/src/data/backwardsCompatibility/farmyardBC.js b/src/data/backwardsCompatibility/farmyardBC.js
index 0774ab9ee51c51b108accff12f0851ab787761d2..6f47035f5eb34831a695b9b71118b40414f98241 100644
--- a/src/data/backwardsCompatibility/farmyardBC.js
+++ b/src/data/backwardsCompatibility/farmyardBC.js
@@ -32,28 +32,21 @@ App.Facilities.Farmyard.BC = function() {
 		delete V.feline;
 	}
 
-	if (V.animals.canine.some(animal => typeof animal !== "string")) {
-		V.animals.canine = V.animals.canine.filter(animal => typeof animal === "string");
-		V.active.canine = V.animals.canine || null;
-	}
-	if (V.animals.hooved.some(animal => typeof animal !== "string")) {
-		V.animals.hooved = V.animals.hooved.filter(animal => typeof animal === "string");
-		V.active.hooved = V.animals.hooved || null;
-	}
-	if (V.animals.feline.some(animal => typeof animal !== "string")) {
-		V.animals.feline = V.animals.feline.filter(animal => typeof animal === "string");
-		V.active.feline = V.animals.feline || null;
+	if (!V.animals || typeof V.animals !== "object") {
+		V.animals = {
+			canine: [],
+			hooved: [],
+			feline: [],
+		};
+	} else {
+		V.animals.canine = V.animals.canine.filter(canine => !!getAnimal(canine));
+		V.animals.hooved = V.animals.hooved.filter(hooved => !!getAnimal(hooved));
+		V.animals.feline = V.animals.feline.filter(feline => !!getAnimal(feline));
 	}
 
-	if (V.active.canine && typeof V.active.canine !== "string") {
-		V.active.canine = V.active.canine.name;
-	}
-	if (V.active.hooved && typeof V.active.hooved !== "string") {
-		V.active.hooved = V.active.hooved.name;
-	}
-	if (V.active.feline && typeof V.active.feline !== "string") {
-		V.active.feline = V.active.feline.name;
-	}
+	if (V.active.canine && typeof getAnimal(V.active.canine) === "undefined") { V.active.canine = null; }
+	if (V.active.hooved && typeof getAnimal(V.active.hooved) === "undefined") { V.active.hooved = null; }
+	if (V.active.feline && typeof getAnimal(V.active.feline) === "undefined") { V.active.feline = null; }
 
 	if (V.farmyardShowgirls) {
 		delete V.farmyardShowgirls;
diff --git a/src/endWeek/endWeek.js b/src/endWeek/endWeek.js
index c89e7c90f63cc67feac142aab4152544489d876a..014fa1b38e922efcf08d60eb073b9e2a42f68e0b 100644
--- a/src/endWeek/endWeek.js
+++ b/src/endWeek/endWeek.js
@@ -17,9 +17,6 @@ globalThis.endWeek = (function() {
 		}
 		setUseWeights();
 		saveWeekTotals();
-		if (V.secExpEnabled > 0) {
-			V.SecExp.war = {foughtThisWeek: 0, type: ""};
-		}
 
 		// pass time for objects that need it
 		weather();
diff --git a/src/endWeek/facilityLeaderSex.js b/src/endWeek/facilityLeaderSex.js
index bc82fd9e9d2e8a3fa0a51d907594bc587745b69c..cc397cf952a06ae247ef9e0ad9a27d51ff39e520 100644
--- a/src/endWeek/facilityLeaderSex.js
+++ b/src/endWeek/facilityLeaderSex.js
@@ -37,7 +37,7 @@ App.EndWeek.getFLSex = function(facility) {
 	/** @type {Set<number>} */
 	const employeeSex = new Set();
 	const fl = facility.manager ? facility.manager.currentEmployee : null;
-	if (fl && App.Data.misc.sexFromDevelopmentLeaders.includes[fl.assignment]) {
+	if (fl && App.Data.misc.sexFromDevelopmentLeaders.includes(fl.assignment)) {
 		facility.employees().filter(s => flWillFuck(s)).forEach(s => employeeSex.add(s.ID));
 	}
 	return employeeSex;
diff --git a/src/endWeek/nextWeek/nextWeek.js b/src/endWeek/nextWeek/nextWeek.js
index b57ff0991a1f164f3400e9381a4fed2c7bb35f25..fb6d28411b122aaba13f8db3000a9465e0057f6a 100644
--- a/src/endWeek/nextWeek/nextWeek.js
+++ b/src/endWeek/nextWeek/nextWeek.js
@@ -323,7 +323,7 @@ App.EndWeek.nextWeek = function() {
 			V.SecExp.buildings.riotCenter.sentUnitCooldown = Math.max(V.SecExp.buildings.riotCenter.sentUnitCooldown - 1, 0);
 		}
 		V.SecExp.proclamation.cooldown = Math.max(V.SecExp.proclamation.cooldown - 1, 0);
-		V.SecExp.war = {foughtThisWeek: 0, type: ""};
+		V.SecExp.war = {};
 	}
 
 	App.EndWeek.weather();
diff --git a/src/endWeek/player/prInflation.js b/src/endWeek/player/prInflation.js
index 94afe36a6874bade19da95c42c00a647a2b3030d..8d61ebdfbf079470c36d66c64f84106d2d0f6019 100644
--- a/src/endWeek/player/prInflation.js
+++ b/src/endWeek/player/prInflation.js
@@ -45,8 +45,12 @@ App.EndWeek.Player.inflation = function(PC = V.PC) {
 			deflate(PC);
 		} else if (PC.bellyImplant >= 1500 || PC.bellyPreg >= 1500) {
 			if (PC.inflationType === "undigested food") {
-				r.push(`You were already feeling full before your diet started backing up inside you; <span class="health dec">now it's just agonizing.</span>`);
-				healthDamage(PC, 5);
+				if (PC.diet !== "weaning") {
+					deflate(PC);
+				} else {
+					r.push(`You were already feeling full before your diet started backing up inside you; <span class="health dec">now it's just agonizing.</span>`);
+					healthDamage(PC, 5);
+				}
 			} else if (PC.inflation > 1) {
 				r.push(`You feel a bit too full already to inflate yourself as large as you'd like, so <span class="yellow">you'll have to settle for a lesser filling.</span>`);
 				PC.inflation = 1;
@@ -75,6 +79,10 @@ App.EndWeek.Player.inflation = function(PC = V.PC) {
 			} else if (PC.inflation === 1 && harvest < 2) {
 				r.push(`you at all. <span class="yellow">You are unable continue to inflate yourself by this means.</span>`);
 			}
+		} else if (PC.inflationType === "undigested food" && PC.diet !== "weaning") {
+			r.push(`Since you started eating slave food again, the food backing up in your system has broken down, once again <span class="yellow">leaving you with a flat belly.</span>`);
+			deflate(PC);
+			PC.weaningDuration = 0;
 		}
 	}
 
diff --git a/src/endWeek/player/prLongTermPhysicalEffects.js b/src/endWeek/player/prLongTermPhysicalEffects.js
index 91475a85b6dd34a6388c99b079e191565671fe5d..2692c449a2aec41f6f5963407cb33df486983cc1 100644
--- a/src/endWeek/player/prLongTermPhysicalEffects.js
+++ b/src/endWeek/player/prLongTermPhysicalEffects.js
@@ -802,6 +802,7 @@ App.EndWeek.Player.longTermPhysicalEffects = function(PC = V.PC) {
 			PC.rules.lactation = "none";
 		} else if (PC.rules.lactation === "maintain") {
 			r.push(`You regularly see to your breasts to make sure your milk production doesn't dry up; be it by hand, milker, or mouth, you keep yourself comfortably drained.`);
+			PC.lactationDuration = 2;
 		} else if (PC.rules.lactation === "sell") {
 			const milk = milkAmount(PC);
 			let milkSale;
@@ -818,6 +819,7 @@ App.EndWeek.Player.longTermPhysicalEffects = function(PC = V.PC) {
 				milkSale = milk * 8;
 				r.push(`Your milk is sold for <span class="yellowgreen">${cashFormat(milkSale)}.</span>`);
 			}
+			PC.lactationDuration = 2;
 			cashX(milkSale, "personalBusiness");
 		}
 		if (PC.lactation === 1) {
diff --git a/src/endWeek/reports/farmyardReport.js b/src/endWeek/reports/farmyardReport.js
index d3ee19f721ff34fbc465be2d0c2ef0ef3d8fd560..9258268fa64e3ea4aadd1124a21a77e708252bcc 100644
--- a/src/endWeek/reports/farmyardReport.js
+++ b/src/endWeek/reports/farmyardReport.js
@@ -1,26 +1,29 @@
 App.EndWeek.farmyardReport = function farmyardReport() {
 	const frag = new DocumentFragment();
+	const text = new SpacedTextAccumulator(frag);
 
 	const slaves = App.Utils.sortedEmployees(App.Entity.facilities.farmyard);
 	const devBonus = (V.farmyardDecoration !== "standard") ? 1 : 0;
 	const Farmer = S.Farmer ? App.SlaveAssignment.reportSlave(S.Farmer) : undefined;
-
-	let profits = 0;
-	let foodWeek = 0;
-
-	const statsSpan = document.createElement("span");
-	frag.append(statsSpan);
+	const profits = getProfits();
+	const food = getFood();
 
 	// Statistics gathering
 	V.facility = V.facility || {};
 	V.facility.farmyard = initFacilityStatistics(V.facility.farmyard);
 
-	farmyardStatsRecords();
+	const statsSpan = document.createElement("span");
+	frag.append(statsSpan);
+
+	text.push(
+		farmyardDecoration(),
+		farmyardMultipliers(),
+		farmyardProfit(),
+	);
 
-	farmyardDecoration();
-	farmyardProfit(profits, foodWeek);
+	text.toParagraph();
 
-	V.mods.food.amount += foodWeek;
+	V.mods.food.amount += food;
 
 	if (Farmer) {
 		const farmerEffects = App.UI.DOM.appendNewElement("p", frag, null, ["indent"]);
@@ -69,8 +72,6 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 				farmhandEnergy(slave);
 				farmhandFood(slave);
 
-				profits += farmhandProfit(slave);
-
 				const farmhandContent = App.UI.DOM.appendNewElement("div", slaveEntry, null, ["indent"]);
 
 				$(farmhandContent).append(App.SlaveAssignment.workTheFarm(slave));
@@ -81,28 +82,8 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 				App.SlaveAssignment.standardSlaveReport(slave, true);
 			}
 		}
-	}
-
-	if (V.farmMenials) {
-		let farmMenialProductivity = 9;
-
-		if (V.farmyardUpgrades.pump) {
-			farmMenialProductivity += 1;
-		}
-
-		if (V.farmyardUpgrades.fertilizer) {
-			farmMenialProductivity += 2;
-		}
-
-		if (V.farmyardUpgrades.seeds) {
-			farmMenialProductivity += 3;
-		}
 
-		if (V.farmyardUpgrades.machinery) {
-			farmMenialProductivity += 3;
-		}
-
-		foodWeek += (V.farmMenials * farmMenialProductivity);
+		farmyardStatsRecords();
 	}
 
 	frag.append(App.Facilities.Farmyard.Stats(false));
@@ -356,7 +337,7 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 	}
 
 	function farmerIntro(slave) {
-		return `<span class="indent">${SlaveFullName(slave)} is serving as the Farmer</span>.`;
+		return `<span class="indent">${SlaveFullName(slave)} is serving as the Farmer.</span>`;
 	}
 
 	// Farmhands
@@ -439,24 +420,26 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 			return;
 		}
 
-		f.farmhandIncome = 0;
+		f.whoreIncome = 0;
 		f.customers = 0;
-		f.farmhandCosts = 0;
+		f.whoreCosts = 0;
 		f.rep = 0;
+		f.food = 0;
 		for (const si of f.income.values()) {
-			f.farmhandIncome += si.income + si.adsIncome;
+			f.whoreIncome += si.income + si.adsIncome;
 			f.customers += si.customers;
-			f.farmhandCosts += si.cost;
+			f.whoreCosts += si.cost;
 			f.rep += si.rep;
+			f.food += si.food;
 		}
 		f.maintenance = V.farmyard * V.facilityCost;
-		f.totalIncome = f.farmhandIncome + f.adsIncome;
-		f.totalExpenses = f.farmhandCosts + f.maintenance;
+		f.totalIncome = f.whoreIncome + f.adsIncome;
+		f.totalExpenses = f.whoreCosts + f.maintenance;
 		f.profit = f.totalIncome - f.totalExpenses;
 	}
 
 	function farmyardDecoration() {
-		const text = new SpacedTextAccumulator(frag);
+		const text = [];
 
 		// TODO: add checks for the different FSs
 		if (V.farmyardDecoration !== 'standard') {
@@ -473,21 +456,51 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 			}
 		}
 
-		return text.toParagraph();
+		return text.join(' ');
+	}
+
+	function farmyardMultipliers() {
+		const total = V.animals.canine.length +
+			V.animals.hooved.length +
+			V.animals.feline.length;
+		const text = [];
+		const animals = [];
+
+		text.push(`Having a ${total > 6 ? `wide` : ``} variety of`);
+		if (V.animals.canine.length > 0) {
+			if (V.animals.canine.every(c => getAnimal(c).species === "dog")) {
+				animals.push(`dogs`);
+			} else {
+				animals.push(`canines`);
+			}
+		}
+		if (V.animals.hooved.length > 0) {
+			animals.push(`hooved animals`);
+		}
+		if (V.animals.feline.length > 0) {
+			if (V.animals.feline.every(f => getAnimal(f).species === "cat")) {
+				animals.push(`cats`);
+			} else {
+				animals.push(`felines`);
+			}
+		}
+		text.push(`${toSentence(animals)} keeps the guests of ${V.farmyardName} more entertained than they would have been otherwise, <span class="cash inc">earning you more.</span>`);
+
+		return text.join(' ');
 	}
 
-	function farmyardProfit(profit, food) {
-		const text = new SpacedTextAccumulator(frag);
+	function farmyardProfit() {
+		const text = [];
 
-		if (profit || food) {
+		if (profits || food) {
 			text.push(capFirstChar(V.farmyardName));
 
-			if (profit) {
-				text.push(`makes you <span class="cash">${cashFormat(Math.trunc(profit))}</span>`);
+			if (profits) {
+				text.push(`makes you <span class="cash">${cashFormat(Math.trunc(profits))}</span>`);
 			}
 
 			if (V.mods.food.market) {
-				if (profit && food) {
+				if (profits && food) {
 					text.push(`and`);
 				}
 				if (food) {
@@ -497,6 +510,48 @@ App.EndWeek.farmyardReport = function farmyardReport() {
 			text.push(`this week.`);
 		}
 
-		return text.toParagraph();
+		return text.join(' ');
+	}
+
+	function getProfits() {
+		let total = 0;
+
+		for (const slave of slaves) {
+			total += farmhandProfit(slave);
+		}
+
+		return total;
+	}
+
+	function getFood() {
+		let total = 0;
+
+		if (V.farmMenials) {
+			let farmMenialProductivity = 9;
+
+			if (V.farmyardUpgrades.pump) {
+				farmMenialProductivity += 1;
+			}
+
+			if (V.farmyardUpgrades.fertilizer) {
+				farmMenialProductivity += 2;
+			}
+
+			if (V.farmyardUpgrades.seeds) {
+				farmMenialProductivity += 3;
+			}
+
+			if (V.farmyardUpgrades.machinery) {
+				farmMenialProductivity += 3;
+			}
+
+			total += V.farmMenials * farmMenialProductivity;
+		}
+
+		for (const slave of slaves) {
+			total += App.Facilities.Farmyard.foodAmount(slave);
+		}
+
+		return total;
 	}
 };
diff --git a/src/endWeek/saClothes.js b/src/endWeek/saClothes.js
index a68558cd20e3eba3ce45195a79f2532f2b6d0d1f..48331e8692ef4dfa2ea0dedbc0b40d1108cedf61 100644
--- a/src/endWeek/saClothes.js
+++ b/src/endWeek/saClothes.js
@@ -664,6 +664,10 @@ App.SlaveAssignment.clothes = function saClothes(slave) {
 	 */
 	function bellyAccessories(slave) {
 		if (slave.bellyAccessory === "an extreme corset") {
+			if (slave.inflation > 0) {
+				r.push(`The pressure of ${his} corsetage <span class="change negative">renders ${him} unable to keep filling ${his} guts with ${slave.inflationType}.</span>`);
+				deflate(slave);
+			}
 			if (slave.belly >= 100000) {
 				r.push(`${His} straining corset finally gives in to ${his} giant stomach and bursts, freeing ${his} belly.`);
 				slave.bellyAccessory = "none";
@@ -743,6 +747,10 @@ App.SlaveAssignment.clothes = function saClothes(slave) {
 				}
 			}
 		} else if (slave.bellyAccessory === "a corset") {
+			if (slave.inflation > 0) {
+				r.push(`The pressure of ${his} corsetage <span class="change negative">renders ${him} unable to keep filling ${his} guts with ${slave.inflationType}.</span>`);
+				deflate(slave);
+			}
 			if (slave.bellyPreg >= 1500) {
 				r.push(`${His} corset lets ${his} growing belly protrude comfortably, preventing any danger to ${his} pregnancy but preventing any effect on ${his} waist.`);
 			} else if (slave.belly >= 1500) {
diff --git a/src/endWeek/saRelationships.js b/src/endWeek/saRelationships.js
index 252c5c85f3964836da9dc60b8e2616891a3b5d29..72cc36b7bab3fd6a871d3926fa9f600e6866e879 100644
--- a/src/endWeek/saRelationships.js
+++ b/src/endWeek/saRelationships.js
@@ -1288,7 +1288,7 @@ App.SlaveAssignment.relationships = function saRelationships(slave) {
 					r.push(`${slave.slaveName} knows that ${his} ${relativeTerm(slave, singleRelative)} ${singleRelative.slaveName} loves being your sex slave, and is <span class="devotion inc">happy</span> for ${him2}.`);
 				} else if (devotedRelatives.size > 0) {
 					const groups = relativeMapToGroupArray(devotedRelatives);
-					r.push(`${slave.slaveName} knows that ${toSentence(groups)} all love being your sex slaves, and is <span class="devotion inc">happy</span> for them.`);
+					r.push(`${slave.slaveName} knows that ${toSentence(groups)} ${devotedRelatives.size === 2 ? `both` : `all`} love being your sex slaves, and is <span class="devotion inc">happy</span> for them.`);
 				}
 				if (relativeMapTotalSize(devotedRelatives) > overwhelmed) {
 					r.push(`${He} has so many relatives that love being your slaves that ${he} is sometimes overwhelmed with joy and <span class="devotion dec">neglects ${his} duties.</span>`);
@@ -1310,7 +1310,7 @@ App.SlaveAssignment.relationships = function saRelationships(slave) {
 					r.push(`${slave.slaveName} knows that ${his} ${relativeTerm(slave, singleRelative)} ${singleRelative.slaveName} hates being a sex slave, and is <span class="trust dec">afraid</span> for ${him2}.`);
 				} else if (hatefulRelatives.size > 0) {
 					const groups = relativeMapToGroupArray(hatefulRelatives);
-					r.push(`${slave.slaveName} knows that ${toSentence(groups)} all hate being sex slaves, and is <span class="trust dec">afraid</span> for them.`);
+					r.push(`${slave.slaveName} knows that ${toSentence(groups)} ${hatefulRelatives.size === 2 ? `both` : `all`} hate being sex slaves, and is <span class="trust dec">afraid</span> for them.`);
 				}
 				if (relativeMapTotalSize(hatefulRelatives) > overwhelmed) {
 					r.push(`${He} has so many relatives that hate being your sex slaves that ${he} is overwhelmed with fear and <span class="trust inc">just has to trust you to take care of them.</span>`);
diff --git a/src/endWeek/saRules.js b/src/endWeek/saRules.js
index 0773271fe34b427805e4760aa16f361c65234451..9f23049d3d874555ebd2ce96eeb1a5f60c677bd0 100644
--- a/src/endWeek/saRules.js
+++ b/src/endWeek/saRules.js
@@ -15,9 +15,7 @@ App.SlaveAssignment.rules = function(slave) {
 			he, his, him, himself, girl, wife
 		} = getPronouns(slave);
 		const hands = (hasBothArms(slave)) ? `hands` : `hand`;
-		let wife2;
 		let milkResult;
-		let wardenFunTimes;
 		r.push(`${He}`);
 		if (slave.fetish === "mindbroken") {
 			r.push(`is mentally broken so none of the rules have any impact.`);
@@ -573,9 +571,6 @@ App.SlaveAssignment.rules = function(slave) {
 								}
 								break;
 							case "lover":
-								({
-									wife2
-								} = getPronouns(partner.slave).appendSuffix("2"));
 								slave.need = 0;
 								r.push(`is well taken care of during ${his} stay in ${V.clinicName}; ${his}`);
 								if (slave.relationship === 3) {
@@ -583,7 +578,7 @@ App.SlaveAssignment.rules = function(slave) {
 								} else if (slave.relationship === 4) {
 									r.push(`sweetheart`);
 								} else {
-									r.push(wife2);
+									r.push(getPronouns(partner.slave).wife);
 								}
 								r.push(`frequently stops by when ${he} gets the chance to make sure ${his} sexual needs are properly handled.`);
 								seX(partner.slave, "oral", slave, "penetrative", 14);
@@ -875,17 +870,32 @@ App.SlaveAssignment.rules = function(slave) {
 
 					r.push(App.SlaveAssignment.rewardAndPunishment(slave));
 					break;
-				case "be confined in the cellblock":
-					wardenFunTimes = 0;
+				case "be confined in the cellblock": {
+					let wardenFunTimes = 0;
+					let pregNotice = ``;
 					if (App.EndWeek.saVars.flSex.has(slave.ID)) {
 						wardenFunTimes = random(0, 5);
 						slave.need -= (10 * wardenFunTimes);
+						SimpleSexAct.Slaves(slave, S.Wardeness, wardenFunTimes);
+						if (canImpreg(slave, S.Wardeness) && (V.cellblockWardenCumsInside === 1 || S.Wardeness.fetish === "mindbroken")) {
+							pregNotice = knockMeUp(slave, 3 * wardenFunTimes, 2, V.WardenessID);
+						}
 					}
 					if (slave.devotion < -50) {
 						r.push(`is so unhappy that ${he} has little interest in getting off, making the rule restricting ${his} sexual outlets superfluous.`);
+						if (wardenFunTimes > 0) {
+							r.push(`${His} unhappiness doesn't stop ${S.Wardeness.slaveName} from raping ${him}, of course, which <span class="trust dec">contributes to ${his} growing fear.</span>`);
+							r.push(pregNotice);
+							slave.trust--;
+						}
 						slave.need = 0;
 					} else if (slave.energy <= 20) {
 						r.push(`is frigid and has little interest in getting off, making the rule restricting ${his} sexual outlets superfluous.`);
+						if (wardenFunTimes > 0) {
+							r.push(`${His} disinterest doesn't stop ${S.Wardeness.slaveName} from raping ${him}, of course, which <span class="trust dec">contributes to ${his} growing fear.</span>`);
+							r.push(pregNotice);
+							slave.trust--;
+						}
 						slave.need = 0;
 					} else if (slave.relationship === -3) {
 						r.push(`You make sure your troublesome ${wife}'s sexual needs are handled, openly, in the middle of ${V.cellblockName}, where everyone can see, hear, and smell your dominance.`);
@@ -905,35 +915,28 @@ App.SlaveAssignment.rules = function(slave) {
 						}
 					} else {
 						if (wardenFunTimes > 0) {
-							SimpleSexAct.Slaves(slave, S.Wardeness, wardenFunTimes);
-							if (wardenFunTimes > 0 && canImpreg(slave, S.Wardeness) && (V.cellblockWardenCumsInside === 1 || S.Wardeness.fetish === "mindbroken")) {
-								if (canDoVaginal(slave) && slave.vagina > 0 && slave.ovaries === 1) {
-									knockMeUp(slave, 10, 0, V.WardenessID);
-								} else if (canDoAnal(slave) && slave.anus > 0 && slave.mpreg === 1) {
-									knockMeUp(slave, 10, 1, V.WardenessID);
-								}
-							}
+							r.push(`is regularly raped to climax by ${S.Wardeness.slaveName}.`);
+							r.push(pregNotice);
 						}
-						if (slave.need < App.EndWeek.saVars.needCapPerSlave[slave.ID] * 0.5) {
-							if (slave.devotion <= 20) {
-								r.push(`gets off despite ${his} reluctance, <span class="hotpink">habituating ${him} to sexual slavery.</span>`);
-								slave.devotion += 1;
-								if (slave.trust >= -20 && slave.devotion <= 20) {
-									r.push(`${He} hates ${himself} for climaxing, and knows the mild aphrodisiacs in the food are forcing ${his} arousal, <span class="gold">frightening ${him}.</span>`);
-									slave.trust -= 1;
-								}
-								slave.need -= 20;
+						if (slave.need < App.EndWeek.saVars.needCapPerSlave[slave.ID] * 0.5 && wardenFunTimes > 0) {
+							r.push(`${He} gets off despite ${his} reluctance, <span class="hotpink">habituating ${him} to sexual slavery.</span>`);
+							slave.devotion += 1;
+							if (slave.trust >= -20 && slave.devotion <= 20) {
+								r.push(`${He} hates ${himself} for climaxing, and knows the mild aphrodisiacs in the food are forcing ${his} arousal, <span class="gold">frightening ${him}.</span>`);
+								slave.trust -= 1;
 							}
+							slave.need -= 20;
 						} else {
+							if (wardenFunTimes > 0) {
+								r.push(`It's not enough to satisfy ${his} needs, and ${he}`);
+							}
 							if (random(-100, 0) > slave.devotion) {
 								r.push(`refuses to not touch ${himself} and is <span class="gold">severely punished</span> for illicit masturbation.`);
 								slave.trust -= 2;
 								slave.need -= 10;
 							} else {
 								r.push(`<span class="gold">fears</span> trying to`);
-								if (slave.chastityPenis) {
-									r.push(`touch ${himself}`);
-								} else if (canAchieveErection(slave)) {
+								if (canAchieveErection(slave) && !slave.chastityPenis) {
 									r.push(`jack off`);
 								} else {
 									r.push(`touch ${himself}`);
@@ -1002,6 +1005,7 @@ App.SlaveAssignment.rules = function(slave) {
 
 					r.push(App.SlaveAssignment.rewardAndPunishment(slave));
 					break;
+				}
 				case "be the Attendant":
 					slave.need -= App.EndWeek.saVars.flSex.size * 3;
 					if (slave.energy <= 20) {
diff --git a/src/endWeek/saServeYourOtherSlaves.js b/src/endWeek/saServeYourOtherSlaves.js
index 0a9250478c9c4ed40648615a08f5d44a90fb8138..3cd1fb74e31342bf283f40e679f385ec54579482 100644
--- a/src/endWeek/saServeYourOtherSlaves.js
+++ b/src/endWeek/saServeYourOtherSlaves.js
@@ -826,7 +826,7 @@ App.SlaveAssignment.serveYourOtherSlaves = function saServeYourOtherSlaves(slave
 					domSlave.fetishKnown = 1;
 				}
 				stimulateSlaveProstate(slave, domSlave);
-				r.push(`to force ${him} to climax so ${domName} can plant ${his2} ${domRace} lips overs ${subName}'s ${subRace}`);
+				r.push(`to force ${him} to climax so ${domName} can plant ${his2} ${domRace} lips over ${subName}'s ${subRace}`);
 				if (slave.vagina >= 0) {
 					r.push(`urethra`);
 				} else {
diff --git a/src/endWeek/saSharedVariables.js b/src/endWeek/saSharedVariables.js
index 3bd4691282a027cf9f6cf3ee829f53d6654e3e15..3b7255854e87076ded393192b5e12fc77c9852b0 100644
--- a/src/endWeek/saSharedVariables.js
+++ b/src/endWeek/saSharedVariables.js
@@ -35,9 +35,10 @@ App.EndWeek.SASharedVariables = class {
 		/** Need cap per slave. Array indices are the slave IDs (resulting in a sparse array, but that's ok, because we never save this array) */
 		this.needCapPerSlave = [];
 		/** Which employees the leader of the currently processed facility is having sex with this week
+		 *  @type {Set<number>}
 		 *  @see App.EndWeek.getFLSex
 		 */
-		this.flSex = 0;
+		this.flSex = new Set();
 	}
 
 	/** Compute shared subslave ratio (subslaves per ordinary slave) */
diff --git a/src/endWeek/saWorkTheFarm.js b/src/endWeek/saWorkTheFarm.js
index bc5d56aa3274bf1c5226ebed6ef9f5d9bb784814..b4b15afad14b8ded7c24ad7498bf4e3b33213cdc 100644
--- a/src/endWeek/saWorkTheFarm.js
+++ b/src/endWeek/saWorkTheFarm.js
@@ -59,7 +59,9 @@ App.SlaveAssignment.workTheFarm = function(slave) {
 			V.mods.food.total += foodAmount;
 			incomeStats.food += foodAmount;
 
-			return App.Facilities.Farmyard.produceFood(slave);
+			if (V.farmyardShows !== 2) {
+				return App.Facilities.Farmyard.produceFood(slave);
+			}
 		}
 	}
 
diff --git a/src/endWeek/standardSlaveReport.js b/src/endWeek/standardSlaveReport.js
index 5de0aa6debf72c9e549b7faebe5db282e841eada..9faa88abd3379699f31a845e2c4aee823546fbd2 100644
--- a/src/endWeek/standardSlaveReport.js
+++ b/src/endWeek/standardSlaveReport.js
@@ -41,8 +41,8 @@ App.SlaveAssignment.individualSlaveReport = function(slave) {
  * @param {App.Entity.SlaveState} slave
  */
 App.SlaveAssignment.appendSlaveArt = function(node, slave) {
-	if (V.seeImages && V.seeReportImages) {
-		App.UI.DOM.appendNewElement("div", node, App.EndWeek.saVars.slaveArt.render(slave), ["imageRef", "tinyImg"]);
+	if (V.seeImages && V.seeReportImages && (!V.seeCustomImagesOnly || (V.seeCustomImagesOnly && slave.custom.image))) {
+		App.UI.DOM.appendNewElement("div", node, App.EndWeek.saVars.slaveArt.render(slave), ["imageRef", "tinyImg", "margin-right"]);
 	}
 };
 
diff --git a/src/events/PE/foodplay.js b/src/events/PE/foodplay.js
new file mode 100644
index 0000000000000000000000000000000000000000..512371f58de5db63b621032ac68d453c63f89693
--- /dev/null
+++ b/src/events/PE/foodplay.js
@@ -0,0 +1,290 @@
+App.Events.PEFoodplay = class PEFoodplay extends App.Events.BaseEvent {
+	eventPrerequisites() {
+		return [
+			() => ((V.rep > 10000) || (V.debugMode > 0 && V.debugModeEventSelection > 0)),
+			() => ((V.HeadGirlID !== 0) || (V.ConcubineID !== 0) || (V.BodyguardID !==0))
+		];
+	}
+
+	execute(node) {
+		let eventSlave = undefined;
+		App.Events.addParagraph(node, [`You are relaxing in the Penthouse after a day of hard work when your PA alerts you to an incoming shipment. One of the aristocrats in your arcology was able to get their hands on a shipment of fresh, wild-caught fish and has sent you a few prime cuts as a sign of goodwill. Such a delicacy is rare to come across, given the rapidly deteriorating global climate.`]);
+		App.Events.addParagraph(node, [`As the leader of a well-established and renowned arcology, it isn't uncommon for you to receive these gestures of friendship and goodwill on a semi-regular basis. Perhaps it wouldn't be such a bad idea to enjoy this latest gift with one of your slaves.`]);
+
+		App.Events.addResponses(node, [
+			(V.HeadGirlID !== 0)
+				? new App.Events.Result(`Accept the gift and invite your Head Girl to join you `, () => scene(S.HeadGirl))
+				: new App.Events.Result(),
+			(V.ConcubineID !== 0)
+				? new App.Events.Result(`Accept the gift and share it with your Concubine`, () => scene(S.Concubine))
+				: new App.Events.Result(),
+			(V.BodyguardID !== 0)
+				? new App.Events.Result(`Accept the gift, and have your Bodyguard join you`, () => scene(S.Bodyguard))
+				: new App.Events.Result(),
+			new App.Events.Result(`Decline the gift`, decline)
+		]);
+
+		function decline() {
+			const r = new SpacedTextAccumulator();
+			r.push(`You politely decline the shipment of seafood. You receive plenty of gifts, and can't spend time entertaining each individual that wishes to gain your favor.`);
+			return r.container();
+		}
+
+		function scene(slave){
+			const r = new SpacedTextAccumulator();
+			eventSlave = slave;
+			const {
+				He, he, his, him
+			} = getPronouns(eventSlave);
+			const {title: Master} = getEnunciation(eventSlave);
+
+			App.Events.drawEventArt(node, eventSlave, "no clothing");
+
+			r.push(`You summon`);
+			r.push(contextualIntro(V.PC, eventSlave, true));
+			r.push(`to your office and order her to lie down on your desk.`);
+			if (hasAnyLegs(eventSlave)){
+				if (eventSlave.devotion > 50){
+					r.push(`${He} complies with a smile, excited to see what you have in store for ${him}.`);
+				} else if (eventSlave.devotion > 20){
+					r.push(`${He} complies with a smile, curious to see what you have in store for ${him}.`);
+				} else if (eventSlave.trust < 20 && eventSlave.devotion > -20){
+					r.push(`${He} nervously complies, curious to see what you have in store for ${him}.`);
+				} else if (eventSlave.trust < -50) {
+					r.push(`Terrified of what you have in store for ${him}, ${he} nervously complies, dreading what you have in store for ${him}.`);
+				} else {
+					r.push(`${He} nervously complies, and lays down on the desk.`);
+				}
+			} else {
+				r.push(`${He} is laid onto your desk with the help of other slaves.`);
+			}
+
+			r.push(`After ${he} is situated, you go over to ${him} and being to peel off ${his} clothing, ${(eventSlave.trust > 20) ? `to which ${he} gives you a soft smile.` : `the slave shivering against your touch.`}`);
+			r.push(`You take a seat at your desk, resuming your work while enjoying the sight of ${eventSlave.slaveName}'s naked body.`);
+			r.push(`Another slave brings a pair of chopsticks and several pieces of sushi, prepared from the seafood that was just delivered. She begins placing them along ${eventSlave.slaveName}'s`);
+			if (eventSlave.weight > 190) {
+				r.push(`immense`);
+			} else if (eventSlave.weight > 160) {
+				r.push(`massive`);
+			} else if (eventSlave.weight > 130) {
+				r.push(`huge`);
+			} else if (eventSlave.weight > 95) {
+				r.push(`thick`);
+			} else if (eventSlave.weight > 10) {
+				r.push(`ample`);
+			} else if (eventSlave.weight >= -10) {
+				r.push(`trim`);
+			}
+			r.push(`body. ${He} shivers as the cold food comes into contact with ${his} skin`);
+			if (eventSlave.devotion < -20){
+				r.push(`and wriggles on the desk, nearly causing the carefully placed food to fall off of ${him}.`);
+			} else {
+				r.push(`but diligently remains still so as to make sure none of the precious delicacy falls off ${his} body.`);
+			}
+
+			r.toParagraph();
+
+			r.push(`Two pieces are laid onto her`);
+			if (eventSlave.boobs > 40000) {
+				r.push(`gargantuan`);
+			} else if (eventSlave.boobs > 25000) {
+				r.push(`immense`);
+			} else if (eventSlave.boobs > 10000) {
+				r.push(`ridiculous`);
+			} else if (eventSlave.boobs > 5000) {
+				r.push(`enormous`);
+			} else if (eventSlave.boobs > 3200) {
+				r.push(`giant`);
+			} else if (eventSlave.boobs > 1600) {
+				r.push(`huge`);
+			} else if (eventSlave.boobs > 800) {
+				r.push(`big`);
+			} else if (eventSlave.boobs > 300) {
+				r.push(`modest`);
+			} else {
+				r.push(`flat`);
+			}
+			if (eventSlave.boobs > 300) {
+				r.push(`tits`);
+			} else {
+				r.push(`chest`);
+			}
+
+			if (eventSlave.areolae > 2){
+				r.push(`, barely covering her huge areolas`);
+			}
+
+			r.push(`and ${eventSlave.nipples} nipples.`);
+
+			if (eventSlave.boobs > 1600){
+				r.push(`The size of ${his} breasts makes it appear as if the delicate piece of food is about to swallowed by an ocean of undulating flesh.`);
+			}
+
+			r.push(`Four pieces of the sliced seafood are laid out on ${his}`);
+
+			if (eventSlave.belly >= 750000) {
+				if (eventSlave.bellyPreg > 0) {
+					r.push(`grotesquely pregnant`);
+				} else {
+					r.push(`grotesquely inflated`);
+				}
+			} else if (eventSlave.belly >= 600000) {
+				if (eventSlave.bellyPreg > 0) {
+					r.push(`dangerously pregnant`);
+				} else {
+					r.push(`dangerously distended`);
+				}
+			} else if (eventSlave.belly >= 450000) {
+				if (eventSlave.bellyPreg > 0) {
+					r.push(`immensely pregnant`);
+				} else {
+					r.push(`immensely distended`);
+				}
+			} else if (eventSlave.belly >= 150000) {
+				if (eventSlave.bellyPreg > 0) {
+					r.push(`massively pregnant`);
+				} else {
+					r.push(`massively distended`);
+				}
+			} else if (eventSlave.belly >= 120000) {
+				if (eventSlave.bellyPreg > 0) {
+					r.push(`enormously pregnant`);
+				} else {
+					r.push(`greatly gravid`);
+				}
+			} else if (eventSlave.belly >= 10000) {
+				if (eventSlave.bellyPreg > 3000) {
+					r.push(`heavily pregnant`);
+				} else if (eventSlave.bellyImplant > 3000) {
+					r.push(`very gravid`);
+				} else {
+					r.push(`taut`);
+				}
+			} else if (eventSlave.belly >= 5000) {
+				if (eventSlave.bellyPreg > 3000) {
+					r.push(`very pregnant`);
+				} else if (eventSlave.bellyImplant > 3000) {
+					r.push(`gravid`);
+				} else {
+					r.push(`distended`);
+				}
+			} else if (eventSlave.belly >= 1500) {
+				if (eventSlave.bellyPreg > 0) {
+					r.push(`slightly pregnant`);
+				} else if (eventSlave.bellyImplant > 0) {
+					r.push(`slightly distended`);
+				} else {
+					r.push(`bloated`);
+				}
+			}
+
+			r.push(`belly, with one over ${his} navel, hiding it from sight.`);
+			r.push(`Your eyes trace over the`);
+
+			if (eventSlave.weight > 10){
+				r.push(`curves of ${his} soft`);
+			} else if (eventSlave.muscles > 6){
+				r.push(`lines of ${his} toned`);
+			} else {
+				r.push(`line of ${his} flat`);
+			}
+
+			r.push(`midriff, and down towards ${his}`);
+
+			if (eventSlave.vagina !== -1){
+				r.push(`pussy`);
+			} else if (eventSlave.dick !== 0){
+				r.push('cock');
+			} else {
+				r.push(`groin`);
+			}
+
+			r.push(`as a final piece of fish is placed right above it.`);
+
+			r.toParagraph();
+
+			r.push(`As you resume your work, you begin plucking pieces of the prepared fish off of the slave's vulnerable body, savoring the freshness and mouth-watering flavor of this rare food. Starting at ${his}`);
+
+			if (eventSlave.boobs > 40000) {
+				r.push(`beanbag-sized`);
+			} else if (eventSlave.boobs > 25000) {
+				r.push(`torso-covering`);
+			} else if (eventSlave.boobs > 10000) {
+				r.push(`obscenely massive`);
+			} else if (eventSlave.boobs > 5000) {
+				r.push(`beachball-sized`);
+			} else if (eventSlave.boobs > 3200) {
+				r.push(`arm-filling`);
+			} else if (eventSlave.boobs > 1600) {
+				r.push(`head-sized`);
+			} else if (eventSlave.boobs > 800) {
+				r.push(`big`);
+			} else if (eventSlave.boobs > 300) {
+				r.push(`modest`);
+			}
+			if (eventSlave.boobs > 300) {
+				r.push(`tits`);
+			} else {
+				r.push(`chest`);
+			}
+
+			r.push(`you pluck at ${his} ${eventSlave.nipples} nipples, eliciting a moan as ${eventSlave.slaveName} helplessly squirms under your teasing. You calmly remind ${him} that such a delicacy is hard to come by, and warn ${him} against dropping any of the pieces. Otherwise, there will be consequences.`);
+
+			if (eventSlave.trust > 50){
+				r.push(`${eventSlave.slaveName} pokes ${his} tongue out at you playfully and shakes ${his} body, confident that any punishment you can bring forth will only mean more time that ${he} can spend in your presence.`);
+			} else {
+				r.push(`Fear flashes across the slave's face as they will their body to be still. ${eventSlave.slaveName} imagines the punishment that could possibly result from ruining ${his} ${Master}'s meal and shudders at the thought, causing the remaining pieces of sushi to precariously teeter atop ${his} body.`);
+			}
+
+			r.push(`You work your way down ${his} belly, and arrive at the final piece above ${his}`);
+
+			if (eventSlave.vagina !== -1){
+				r.push(`wet pussy.`);
+			} else if (eventSlave.dick !== 0){
+				r.push('throbbing cock.');
+			} else {
+				r.push(`groin.`);
+			}
+
+			r.push(`Eyeing the piece of food, as well as the last piece of sushi, you decide to play with it for a little.`);
+
+			if (eventSlave.piercing.genitals.weight > 0){
+				r.push(`You wrap your chopsticks around the glinting piercing at your slave's waist and give it a sharp tug, causing ${eventSlave.slaveName} to scream out in equal parts pain and pleasure.`);
+			} else if (eventSlave.vagina !== -1){
+				r.push(`You use the chopsticks to fondle with ${his} clit roughly, causing ${eventSlave.slaveName} to gasp out in surprise. Spreading ${him} open, you use your tongue to edge ${him} towards climax.`);
+			} else if (eventSlave.dick > 0){
+				r.push(`You use the chopsticks to grip with ${his} dick roughly, causing ${eventSlave.slaveName} to gasp out in surprise. Using the utensils to tease and stroke ${his}`);
+
+				if (eventSlave.dick > 4) {
+					r.push(`gigantic cock,`);
+				} else if (eventSlave.dick > 2) {
+					r.push(`impressive erection,`);
+				} else if (eventSlave.dick > 0) {
+					r.push(`little penis,`);
+				}
+
+				r.push(`you skillfully work ${him} towards climax, and he shoots ${his} seed in ropes across his body.`);
+			} else {
+				r.push(`You use the chopsticks to tease ${his} needy hole, causing ${eventSlave.slaveName} to gasp out in surprise. Spreading ${him} open, you use your tongue to edge ${him} towards climax.`);
+			}
+
+			r.toParagraph();
+
+			r.push(`Under your eager attention, ${eventSlave.slaveName} collapses in a moaning, writhing puddle on your desk. You clean your mouth with a handkerchief and tell her to get back to her assignment before calling in another slave to clean up the mess.`);
+
+			r.toParagraph();
+
+			if (eventSlave.trust > 20 || eventSlave.devotion > 20) {
+				r.push(`As ${he} goes about the rest of ${his} day, ${eventSlave.slaveName} recalls the events of the morning and smiles. ${He} <span class = "trust inc">enjoyed</span> the attention that you lavished on ${him}, and wonders if such an opportunity will ever arise again.`);
+				eventSlave.trust += 5;
+			} else {
+				r.push(`After being carried out and cleaned up, ${eventSlave.slaveName} avoids walking past your office for the remainder of the day, <span class = "trust dec">worried</span> that ${he} might catch your eye and be called to entertain you again.`);
+				eventSlave.trust -= 5;
+			}
+
+			r.toParagraph();
+
+			return r.container();
+		}
+	}
+};
diff --git a/src/events/RE/reArcologyInspection.js b/src/events/RE/reArcologyInspection.js
index 672c62c8bccb55bb30c2d03b90b42676d84ef51c..92dab5de0dc2e4bcb871cd2fdf63a4ed5b064320 100644
--- a/src/events/RE/reArcologyInspection.js
+++ b/src/events/RE/reArcologyInspection.js
@@ -454,7 +454,7 @@ App.Events.REArcologyInspection = class REArcologyInspection extends App.Events.
 
 		function discipline() {
 			t = [];
-			t.push(`Every arcology has its share of dissidents; it's one of the inevitable results of the semi-anarchic nature of the Free Cities. You have an opportunity to build your own <span class="reputation inc">reputation</span> and also help secure ${agent ? `${agent.slaveName}'s` : `your indirect`} <span class="darkviolet">authority</span> over ${arcology.name}, and it would be a shame to let it pass unheeded. You spend the rest of the day helping pass judgement, and even administer a few whippings and assfuckings yourself, just for good measure.`);
+			t.push(`Every arcology has its share of dissidents; it's one of the inevitable results of the semi-anarchic nature of the Free Cities. You have an opportunity to build your own <span class="reputation inc">reputation</span> and also help secure ${agent ? `${agent.slaveName}'s` : `your indirect`} ${V.secExpEnabled ? `<span class="darkviolet">authority</span>` : `authority`} over ${arcology.name}, and it would be a shame to let it pass unheeded. You spend the rest of the day helping pass judgement, and even administer a few whippings and assfuckings yourself, just for good measure.`);
 			repX(100, "event");
 			if (V.secExpEnabled) {
 				App.Mods.SecExp.authorityX(250);
diff --git a/src/events/RE/reMaleArcologyOwner.js b/src/events/RE/reMaleArcologyOwner.js
index d30b527a5ac085996a7cb9d5fe631e465ac22f02..0fd623dd6cff5b63db51ecaae6c9d67854c17e91 100644
--- a/src/events/RE/reMaleArcologyOwner.js
+++ b/src/events/RE/reMaleArcologyOwner.js
@@ -3,6 +3,7 @@ App.Events.REMaleArcologyOwner = class REMaleArcologyOwner extends App.Events.Ba
 		return [
 			() => V.policies.regularParties === 1,
 			() => V.PC.vagina > 0,
+			() => V.PC.dick === 0,
 			() => V.PC.title === 0,
 			() => (V.rep-10000 > random(1, 10000) && random(0, 99) < V.seeDicks) || (V.debugMode > 0 && V.debugModeEventSelection > 0)
 		];
diff --git a/src/events/RE/reMaleCitizenHookup.js b/src/events/RE/reMaleCitizenHookup.js
index 080a5e7ee85f7a0f9505ac55572119cf1e137dfa..3ffd9bedb758d162824b4b418c30578a18af8ee1 100644
--- a/src/events/RE/reMaleCitizenHookup.js
+++ b/src/events/RE/reMaleCitizenHookup.js
@@ -3,6 +3,7 @@ App.Events.REMaleCitizenHookup = class REMaleCitizenHookup extends App.Events.Ba
 		return [
 			() => V.policies.regularParties === 1,
 			() => V.PC.vagina > 0,
+			() => V.PC.dick === 0,
 			() => V.PC.title === 0,
 		];
 	}
diff --git a/src/events/RESS/review/gorging.js b/src/events/RESS/review/gorging.js
index da6a3ee46443eebc4f0befb1da8c2edb4ba31593..3d98b349b1d2187e79e6027031c628f174159e28 100644
--- a/src/events/RESS/review/gorging.js
+++ b/src/events/RESS/review/gorging.js
@@ -216,7 +216,6 @@ App.Events.RESSGorging = class RESSGorging extends App.Events.BaseEvent {
 			eventSlave.inflation = 3;
 			SetBellySize(eventSlave);
 			App.Events.refreshEventArt(eventSlave);
-			deflate(eventSlave);
 			return r;
 		}
 
diff --git a/src/events/RETS/reInterslaveBegging.js b/src/events/RETS/reInterslaveBegging.js
index 2326a0cab54f265556ce8ba05b8394391d5aab8b..abc922d0d21f458331c37336a30d5a017c759e83 100644
--- a/src/events/RETS/reInterslaveBegging.js
+++ b/src/events/RETS/reInterslaveBegging.js
@@ -56,7 +56,7 @@ App.Events.RETSInterslaveBegging = class RETSInterslaveBegging extends App.Event
 		let t = [];
 
 		t.push(`Passing the slave quarters late at night, you hear`);
-		t.push(App.UI.DOM.combineNodes(contextualIntro(V.PC, eventSlave, true), "'s'"));
+		t.push(App.UI.DOM.combineNodes(contextualIntro(V.PC, eventSlave, true), "'s"));
 		if (eventSlave.voice > 2) {
 			t.push(`girly voice raised in`);
 		} else if (eventSlave.voice > 1) {
diff --git a/src/events/intro/acquisition.js b/src/events/intro/acquisition.js
index 19e6afd9fb78d5a0463d697cd7ad1b5ad1b619e9..9a59c6ba9643b1d2ee35900987fabd81ba9a31ba 100644
--- a/src/events/intro/acquisition.js
+++ b/src/events/intro/acquisition.js
@@ -32,7 +32,6 @@ App.Intro.acquisition = function() {
 
 	r.push(`The previous owner seems to have left in something of a hurry.`);
 	let valueGiven = 0;
-	const heroSlaves = App.Utils.buildHeroArray().shuffle();
 	if (V.cheatMode === 1) {
 		r.push(`Since you've elected to take over an arcology with special advantages, you've acquired a very special group of slaves.`);
 		r.push(App.Intro.cheatModeSlaves());
@@ -152,6 +151,7 @@ App.Intro.acquisition = function() {
 			r.push(`did not have the time in control of the arcology to develop a specific stable of sex slaves,`);
 		}
 		r.push(`their slaves were quite varied.`);
+		const heroSlaves = App.Utils.buildHeroArray().shuffle();
 		for (let j = 0; j < heroSlaves.length; j++) {
 			if (valueOwed - valueGiven <= 5000) {
 				break;
diff --git a/src/events/intro/initNationalities.js b/src/events/intro/initNationalities.js
index 4ddc3e8ef7d462bbc5cb61fffdbda0a69d38f41f..31bda02e9747c18797e6c06c1a1864391e952de7 100644
--- a/src/events/intro/initNationalities.js
+++ b/src/events/intro/initNationalities.js
@@ -422,7 +422,7 @@ App.Intro.initNationalities = function() {
 	const random12 = jsRandomMany(sellable, 12);
 	random12.forEach(cell => { cell.owner = 0; });
 
-	App.Mods.SecExp.generalInit();
+	App.Mods.SecExp.object("init");
 
 	if (V.localEcon > 100) {
 		V.mods.food.cost = Math.max(5 / (1 + (Math.trunc(1000-100000/V.localEcon)/10)/100), 3.125);
diff --git a/src/events/nonRandom/daughters/pUndergroundRailroad.js b/src/events/nonRandom/daughters/pUndergroundRailroad.js
index adffa438b3c93839ea31129dcc695722887f81f2..557a22fb03b6146ac118cbbaf123ed19c72f125a 100644
--- a/src/events/nonRandom/daughters/pUndergroundRailroad.js
+++ b/src/events/nonRandom/daughters/pUndergroundRailroad.js
@@ -191,8 +191,8 @@ App.Events.PUndergroundRailroad = class PUndergroundRailroad extends App.Events.
 				} else {
 					r.push(`shakily gestures an apology, and admits that ${he} does.`);
 				}
-				App.Events.addParagraph(node, r);
 			}
+			App.Events.addParagraph(node, r);
 
 			const responses = [
 				new App.Events.Result(`Free ${him}`, free),
diff --git a/src/events/nonRandomEvent.js b/src/events/nonRandomEvent.js
index 099becebf49a6b1e683879ba2605dca226488b07..47b8cecae690e6498619c3c29d399f6cf9c555c9 100644
--- a/src/events/nonRandomEvent.js
+++ b/src/events/nonRandomEvent.js
@@ -55,9 +55,6 @@ App.Events.getNonrandomEvents = function() {
 
 		// secExp
 		new App.Events.secExpSmilingMan0(),
-		new App.Events.secExpSmilingMan1(),
-		new App.Events.secExpSmilingMan2(),
-		new App.Events.secExpSmilingMan3(),
 
 		new App.Events.PMercsHelpCorp(),
 		new App.Events.PMercenaryRomeo(),
diff --git a/src/events/randomEvent.js b/src/events/randomEvent.js
index fa1f6c97e466ad63080ab7e94e1d98aad42b3e8e..f47e6e1b0b8353b330ba416b53fef1da02353eb9 100644
--- a/src/events/randomEvent.js
+++ b/src/events/randomEvent.js
@@ -223,6 +223,7 @@ App.Events.getNonindividualEvents = function() {
 		new App.Events.PECombatTraining(),
 		new App.Events.PELonelyBodyguard(),
 		new App.Events.PEAssociatesPublicSlut(),
+		new App.Events.PEFoodplay(),
 
 		new App.Events.REDevotees(),
 		new App.Events.RERelativeRecruiter(),
diff --git a/src/events/recETS/recetsIdenticalHermPair.js b/src/events/recETS/recetsIdenticalHermPair.js
index dec8a9432dac3116e71bc2e5371a96b9d5435d6e..2128d10917c6a8068df18a68a01719b792d54858 100644
--- a/src/events/recETS/recetsIdenticalHermPair.js
+++ b/src/events/recETS/recetsIdenticalHermPair.js
@@ -111,7 +111,7 @@ App.Events.recetsIdenticalHermPair = class recetsIdenticalHermPair extends App.E
 
 		App.Events.addParagraph(node, [
 			`They pull themselves together, bringing their ${V.seePreg ? `gravid middles` : `unique bodies`} in tight contact with one another. One of them speaks up.`,
-			Spoken(thing1, `"We're twins, ${(V.PC.title !== 0) ? "sir" : "ma'am"}. Identical twins. We've also been trained ${(thing2.actualAge > V.minimumSlaveAge) ? `ever since we turned ${V.minimumSlaveAge}` : ``} to be completely obedient, ${(V.PC.title !== 0) ? "sir" : "ma'am"}, in everything, and sexually proficient."`)
+			Spoken(thing1, `"We're twins, ${(V.PC.title !== 0) ? "sir" : "ma'am"}. Identical twins. We've also been trained ${(thing2.actualAge > V.minimumSlaveAge) ? `ever since we turned ${num(V.minimumSlaveAge)}` : ``} to be completely obedient, ${(V.PC.title !== 0) ? "sir" : "ma'am"}, in everything, and sexually proficient."`)
 		]);
 
 		if (V.seePreg) {
diff --git a/src/events/recETS/recetsIdenticalPair.js b/src/events/recETS/recetsIdenticalPair.js
index 8467412741688b15be462974433f36a1dbc32fb0..d47deb0310eeea3bdccb4417211d012f6bcf0372 100644
--- a/src/events/recETS/recetsIdenticalPair.js
+++ b/src/events/recETS/recetsIdenticalPair.js
@@ -73,7 +73,7 @@ App.Events.recetsIdenticalPair = class recetsIdenticalPair extends App.Events.Ba
 
 		App.Events.addParagraph(node, [
 			`One of them speaks up.`,
-			Spoken(thing2, `"We're twins, ${(V.PC.title !== 0) ? "sir" : "ma'am"}. Identical twins. We've also been trained ${(thing2.actualAge > V.minimumSlaveAge) ? `ever since we turned ${V.minimumSlaveAge}` : ``} to be completely obedient, ${(V.PC.title !== 0) ? "sir" : "ma'am"}, in everything, and sexually proficient."`)
+			Spoken(thing2, `"We're twins, ${(V.PC.title !== 0) ? "sir" : "ma'am"}. Identical twins. We've also been trained ${(thing2.actualAge > V.minimumSlaveAge) ? `ever since we turned ${num(V.minimumSlaveAge)}` : ``} to be completely obedient, ${(V.PC.title !== 0) ? "sir" : "ma'am"}, in everything, and sexually proficient."`)
 		]);
 
 		App.Events.addParagraph(node, [Spoken(thing2, `"We cost ${cashFormat(contractCost)}, ${(V.PC.title !== 0) ? "sir" : "ma'am"}."`)]);
diff --git a/src/events/scheduled/pitFight.js b/src/events/scheduled/pitFight.js
index 934149bb4335ba54d84fd4c17fd64510d95b2eaf..51a81718b4b5f027b3c79792f19b5a5375012369 100644
--- a/src/events/scheduled/pitFight.js
+++ b/src/events/scheduled/pitFight.js
@@ -66,7 +66,7 @@ App.Events.SEPitFight = class SEPitFight extends App.Events.BaseEvent {
 				if (V.active.canine || V.active.hooved || V.active.feline) {
 					fightDelegates.push(getAnimalFight);
 				}
-				if (S.Bodyguard) {						
+				if (S.Bodyguard) {
 					fightDelegates.push(getBodyguardFight);
 				}
 				if (available.length > 1) {
diff --git a/src/events/scheduled/seFCNNstation.js b/src/events/scheduled/seFCNNstation.js
index 8f87cfd72c76afcb23ee9cca054a6cac212e4b34..8a80674f28fa36779bd74b162f7ecd81236f4e8f 100644
--- a/src/events/scheduled/seFCNNstation.js
+++ b/src/events/scheduled/seFCNNstation.js
@@ -16,7 +16,7 @@ App.Events.SEFcnnStation = class SEFcnnStation extends App.Events.BaseEvent {
 
 		const cost = 100000;
 		const {girlP} = getPronouns(V.PC).appendSuffix("P");
-		App.Events.addParagraph(node, [`One of the first groups to take advantage of the Free Cities' nearly nonexistent regulations for media and communications was the Free Cities News Network. As one of the few stations covering news within the Free Cities, and the only one doing so without any form of censorship, FCNN quickly became one the most popular news networks in the world. Presently, however, the network's future looks grim. Its reluctance on portraying explicitly pornographic content has lead to plummeting audience figures, especially in comparison to the upstart 8HGG Inc. media empire. In addition, governments within and outside the Free Cities have become increasingly restrictive towards the press, to the point that many FCNN branches have been effectively silenced.`]);
+		App.Events.addParagraph(node, [`One of the first groups to take advantage of the Free Cities' nearly nonexistent regulations for media and communications was the Free Cities News Network. As one of the few stations covering news within the Free Cities, and the only one doing so without any form of censorship, FCNN quickly became one of the most popular news networks in the world. Presently, however, the network's future looks grim. Its reluctance on portraying explicitly pornographic content has led to plummeting audience figures, especially in comparison to the upstart 8HGG Inc. media empire. In addition, governments within and outside the Free Cities have become increasingly restrictive towards the press, to the point that many FCNN branches have been effectively silenced.`]);
 
 		App.Events.addParagraph(node, [`This is the situation when you receive a personal video call from the network's beleaguered president. The former FCNN headquarters has been outright destroyed for reporting on its host nation's human rights abuses, and they're hoping to relocate to ${V.arcologies[0].name}. "We are, of course, in dire financial straits," the president nervously explains, "So we'll need a small subsidy to establish our new headquarters. Probably, oh, let's say... <span class="yellowgreen">${cashFormat(cost)}</span> or so?" He flinches while forcing a grin.`]);
 
diff --git a/src/events/scheduled/seFCTVinstall.js b/src/events/scheduled/seFCTVinstall.js
index e3986a75f43f1f5342775e95bbb4247a977c43a0..e7952257769cead67ee73703f7a2d9bc6d060353 100644
--- a/src/events/scheduled/seFCTVinstall.js
+++ b/src/events/scheduled/seFCTVinstall.js
@@ -9,7 +9,7 @@ App.Events.SEFctvInstall = class SEFctvInstall extends App.Events.BaseEvent {
 	execute(node) {
 		V.encyclopedia = "FCTV";
 		V.FCTV.receiver = 0;
-		App.Events.addParagraph(node, [`You've been sitting in your office into the early afternoon going over bothersome lease documents that need your approval. When you take a break to look out the window, ${V.assistant.name} speaks up. "${properTitle()}, you have received an approval welcome packet from 8HGG Inc. in regards to Free Cities TV. It seems that they've determined that ${V.arcologies[0].name} is now sufficiently developed enough to warrant a FCTV-Citizen connection. All the details and contracts necessary are included in the packet. From there, a receiver will need to be built onto ${V.arcologies[0].name} in order to access FCTV."`]);
+		App.Events.addParagraph(node, [`You've been sitting in your office into the early afternoon, going over bothersome lease documents that need your approval. When you take a break to look out the window, ${V.assistant.name} speaks up. "${properTitle()}, you have received an approval welcome packet from 8HGG Inc. in regards to Free Cities TV. It seems that they've determined that ${V.arcologies[0].name} is now sufficiently developed enough to warrant an FCTV-Citizen connection. All the details and contracts necessary are included in the packet. From there, a receiver will need to be built onto ${V.arcologies[0].name} in order to access FCTV."`]);
 
 		App.Events.addParagraph(node, [`You browse the guide: home shopping networks, random dramas, how-to shows and a myriad of other things. Of more interest are some of the programs showing glimpses into foreign arcologies and how they are using the service to help mold society.`]);
 
diff --git a/src/facilities/arcade/arcade.js b/src/facilities/arcade/arcade.js
index c559c2327e9760c250ce85690525cddd5a31f23f..cb309e04f6e3517a483d098a1841de302d886690 100644
--- a/src/facilities/arcade/arcade.js
+++ b/src/facilities/arcade/arcade.js
@@ -115,7 +115,7 @@ App.Facilities.Arcade.arcade = class Arcade extends App.Facilities.Facility {
 							`is mutually exclusive with the collectors`,
 						],
 						prereqs: [
-							() => V.arcadeUpgradeCollectors < 1,
+							V.arcadeUpgradeCollectors < 1,
 						],
 					},
 					{
@@ -125,7 +125,7 @@ App.Facilities.Arcade.arcade = class Arcade extends App.Facilities.Facility {
 						link: `Apply aphrodisiacs`,
 						handler: () => V.PC.skill.engineering += .1,
 						prereqs: [
-							() => V.arcadeUpgradeCollectors < 1,
+							V.arcadeUpgradeCollectors < 1,
 						],
 					},
 					{
@@ -153,7 +153,7 @@ App.Facilities.Arcade.arcade = class Arcade extends App.Facilities.Facility {
 							`is mutually exclusive with the injectors`,
 						],
 						prereqs: [
-							() => V.arcadeUpgradeInjectors < 1,
+							V.arcadeUpgradeInjectors < 1,
 						],
 					},
 					{
@@ -207,8 +207,8 @@ App.Facilities.Arcade.arcade = class Arcade extends App.Facilities.Facility {
 			{
 				property: "arcadeUpgradeFuckdolls",
 				prereqs: [
-					() => V.arcadeUpgradeFuckdolls > 0,
-					() => App.Entity.facilities.arcade.hostedSlaves > 0,
+					V.arcadeUpgradeFuckdolls > 0,
+					App.Entity.facilities.arcade.hostedSlaves > 0,
 				],
 				options: [
 					{
@@ -237,7 +237,7 @@ App.Facilities.Arcade.arcade = class Arcade extends App.Facilities.Facility {
 			{
 				property: "arcadeUpgradeHealth",
 				prereqs: [
-					() => V.arcadeUpgradeHealth > -1,
+					V.arcadeUpgradeHealth > -1,
 				],
 				options: [
 					{
@@ -266,7 +266,7 @@ App.Facilities.Arcade.arcade = class Arcade extends App.Facilities.Facility {
 			{
 				property: "arcadeUpgradeFuckdolls",
 				prereqs: [
-					() => V.arcadeUpgradeFuckdolls > 0,
+					V.arcadeUpgradeFuckdolls > 0,
 				],
 				options: [
 					{
diff --git a/src/facilities/brothel/brothel.js b/src/facilities/brothel/brothel.js
index f1807bb98c678ade01573a225701205239d9d6e4..541bbc8ef47c856298404af038c670ab5db09ae7 100644
--- a/src/facilities/brothel/brothel.js
+++ b/src/facilities/brothel/brothel.js
@@ -219,7 +219,7 @@ App.Facilities.Brothel.brothel = class Brothel extends App.Facilities.Facility {
 			{
 				property: "brothelUpgradeDrugs",
 				prereqs: [
-					() => V.brothelUpgradeDrugs > 0,
+					V.brothelUpgradeDrugs > 0,
 				],
 				options: [
 					{
@@ -248,7 +248,7 @@ App.Facilities.Brothel.brothel = class Brothel extends App.Facilities.Facility {
 			{
 				property: "MadamIgnoresFlaws",
 				prereqs: [
-					() => !!S.Madam,
+					!!S.Madam,
 				],
 				options: [
 					{
@@ -272,7 +272,7 @@ App.Facilities.Brothel.brothel = class Brothel extends App.Facilities.Facility {
 			{
 				property: "MadamNoSex",
 				prereqs: [
-					() => !!S.Madam,
+					!!S.Madam,
 				],
 				options: [
 					{
diff --git a/src/facilities/cellblock/cellblock.js b/src/facilities/cellblock/cellblock.js
index 5240c175c7fe8ec142b51f38924df1a8f5a72999..a42b6f6b587b500b1284331659278314048b8fdd 100644
--- a/src/facilities/cellblock/cellblock.js
+++ b/src/facilities/cellblock/cellblock.js
@@ -123,8 +123,8 @@ App.Facilities.Cellblock.cellblock = class Cellblock extends App.Facilities.Faci
 			{
 				property: "cellblockWardenCumsInside",
 				prereqs: [
-					() => !!S.Wardeness,
-					() => !!S.Wardeness && canPenetrate(S.Wardeness),
+					!!S.Wardeness,
+					!!S.Wardeness && canPenetrate(S.Wardeness),
 				],
 				options: [
 					{
diff --git a/src/facilities/clinic/clinic.js b/src/facilities/clinic/clinic.js
index ffa099a63148740ca1504f37953e1681fbaf9f5c..72ac69dedb26ebe27bfd5b141c4fde7e07cf04a6 100644
--- a/src/facilities/clinic/clinic.js
+++ b/src/facilities/clinic/clinic.js
@@ -147,7 +147,7 @@ App.Facilities.Clinic.clinic = class Clinic extends App.Facilities.Facility {
 						cost: 30000 * V.upgradeMultiplierArcology * Math.min(V.upgradeMultiplierMedicine, V.HackingSkillMultiplier),
 						notes: [`helps prevent and fight illness in large slave populations`],
 						prereqs: [
-							() => V.geneticMappingUpgrade > 0
+							V.geneticMappingUpgrade > 0
 						]
 					},
 					{
@@ -171,7 +171,7 @@ App.Facilities.Clinic.clinic = class Clinic extends App.Facilities.Facility {
 						handler: () => V.PC.skill.hacking += 0.1,
 						notes: [`may cause health problems in slaves`],
 						prereqs: [
-							() => V.clinicUpgradeFilters > 0,
+							V.clinicUpgradeFilters > 0,
 						],
 					},
 					{
@@ -201,7 +201,7 @@ App.Facilities.Clinic.clinic = class Clinic extends App.Facilities.Facility {
 			{
 				property: "clinicInflateBelly",
 				prereqs: [
-					() => !!S.Nurse,
+					!!S.Nurse,
 				],
 				options: [
 					{
@@ -235,7 +235,7 @@ App.Facilities.Clinic.clinic = class Clinic extends App.Facilities.Facility {
 			{
 				property: "clinicRegularCheckups",
 				prereqs: [
-					() => !!S.Nurse,
+					!!S.Nurse,
 				],
 				options: [
 					{
@@ -253,7 +253,7 @@ App.Facilities.Clinic.clinic = class Clinic extends App.Facilities.Facility {
 			{
 				property: "clinicSpeedGestation",
 				prereqs: [
-					() => !!S.Nurse,
+					!!S.Nurse,
 				],
 				options: [
 					{
diff --git a/src/facilities/club/club.js b/src/facilities/club/club.js
index bccf3b33b65a38649dfa25da4342803251215ecf..5281ad5941352891ad6e049d70bd52c6431e1ed6 100644
--- a/src/facilities/club/club.js
+++ b/src/facilities/club/club.js
@@ -291,7 +291,7 @@ App.Facilities.Club.club = class Club extends App.Facilities.Facility {
 			{
 				property: "DJignoresFlaws",
 				prereqs: [
-					() => !!S.DJ,
+					!!S.DJ,
 				],
 				options: [
 					{
@@ -313,7 +313,7 @@ App.Facilities.Club.club = class Club extends App.Facilities.Facility {
 			{
 				property: "DJnoSex",
 				prereqs: [
-					() => !!S.DJ,
+					!!S.DJ,
 				],
 				options: [
 					{
diff --git a/src/facilities/dairy/dairy.js b/src/facilities/dairy/dairy.js
index c340f700bc9815f8794a72188ad7638af5d3c01f..121df95f2a121733b05c45ded8e0929e3c15963e 100644
--- a/src/facilities/dairy/dairy.js
+++ b/src/facilities/dairy/dairy.js
@@ -274,7 +274,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 						cost: 5000 * V.upgradeMultiplierArcology,
 						handler: () => V.PC.skill.engineering += 0.1,
 						prereqs: [
-							() => (V.dairyPregSetting === 2 || V.dairyStimulatorsSetting === 2)
+							(V.dairyPregSetting === 2 || V.dairyStimulatorsSetting === 2)
 						],
 					},
 					{
@@ -311,11 +311,11 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 						cost: 10000 * V.upgradeMultiplierArcology,
 						handler: () => V.PC.skill.engineering += 0.1,
 						prereqs: [
-							() => !!V.seeHyperPreg,
-							() => V.dairyRestraintsSetting === 2,
-							() => V.dairyStimulatorsSetting === 2,
-							() => V.dairyFeedersSetting === 2,
-							() => V.dairyPregSetting > 0,
+							!!V.seeHyperPreg,
+							V.dairyRestraintsSetting === 2,
+							V.dairyStimulatorsSetting === 2,
+							V.dairyFeedersSetting === 2,
+							V.dairyPregSetting > 0,
 						],
 					},
 					{
@@ -338,7 +338,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 							V.dairySlimMaintain = 1;
 						},
 						prereqs: [
-							() => V.arcologies[0].FSSlimnessEnthusiast > 80,
+							V.arcologies[0].FSSlimnessEnthusiast > 80,
 						],
 					},
 					{
@@ -352,8 +352,8 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 							V.dairySlimMaintain = 1;
 						},
 						prereqs: [
-							() => V.arcologies[0].FSSlimnessEnthusiast > 20,
-							() => V.arcologies[0].FSSlimnessEnthusiast <= 80,
+							V.arcologies[0].FSSlimnessEnthusiast > 20,
+							V.arcologies[0].FSSlimnessEnthusiast <= 80,
 						],
 					},
 					{
@@ -375,7 +375,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 						cost: 5000 * V.upgradeMultiplierArcology,
 						handler: () => V.PC.skill.engineering += 0.1,
 						prereqs: [
-							() => V.arcologies[0].FSPaternalist === "unset",
+							V.arcologies[0].FSPaternalist === "unset",
 						],
 					},
 					{
@@ -395,7 +395,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 			{
 				property: "dairyFeedersSetting",
 				prereqs: [
-					() => V.dairyFeedersUpgrade > 0,
+					 V.dairyFeedersUpgrade > 0,
 				],
 				options: [
 					{
@@ -416,7 +416,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 						value: 2,
 						handler: App.UI.DialogHandler(() => this._getEffect("feeders")),
 						prereqs: [
-							() => V.dairyRestraintsSetting > 1,
+							V.dairyRestraintsSetting > 1,
 						],
 					},
 				],
@@ -424,7 +424,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 			{
 				property: "dairyPregSetting",
 				prereqs: [
-					() => V.dairyPregUpgrade > 0,
+					V.dairyPregUpgrade > 0,
 				],
 				options: [
 					{
@@ -445,7 +445,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 						value: 2,
 						handler: App.UI.DialogHandler(() => this._getEffect("preg")),
 						prereqs: [
-							() => V.dairyRestraintsSetting > 1,
+							V.dairyRestraintsSetting > 1,
 						],
 					},
 					{
@@ -454,10 +454,10 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 						value: 3,
 						handler: App.UI.DialogHandler(() => this._getEffect("preg")),
 						prereqs: [
-							() => V.seeExtreme > 0,
-							() => V.seeHyperPreg > 0,
-							() => V.dairyRestraintsSetting > 1,
-							() => V.dairyHyperPregRemodel === 1,
+							V.seeExtreme > 0,
+							V.seeHyperPreg > 0,
+							V.dairyRestraintsSetting > 1,
+							V.dairyHyperPregRemodel === 1,
 						],
 					},
 				],
@@ -465,7 +465,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 			{
 				property: "dairyStimulatorsSetting",
 				prereqs: [
-					() => V.dairyStimulatorsUpgrade > 0,
+					 V.dairyStimulatorsUpgrade > 0,
 				],
 				options: [
 					{
@@ -486,8 +486,8 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 						value: 2,
 						handler: App.UI.DialogHandler(() => this._getEffect("stimulators")),
 						prereqs: [
-							() => !!V.seeExtreme,
-							() => V.dairyRestraintsSetting > 1,
+							!!V.seeExtreme,
+							V.dairyRestraintsSetting > 1,
 						],
 					},
 				],
@@ -495,7 +495,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 			{
 				property: "dairyRestraintsSetting",
 				prereqs: [
-					() => V.dairyFeedersUpgrade > 0,
+					 V.dairyFeedersUpgrade > 0,
 				],
 				options: [
 					{
@@ -521,10 +521,10 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 			{
 				property: "createBioreactors",
 				prereqs: [
-					() => V.bioreactorsAnnounced !== 0,
-					() => V.dairyRestraintsSetting === 2,
-					() => V.dairyStimulatorsSetting === 2,
-					() => V.dairyFeedersSetting === 2,
+					V.bioreactorsAnnounced !== 0,
+					V.dairyRestraintsSetting === 2,
+					V.dairyStimulatorsSetting === 2,
+					V.dairyFeedersSetting === 2,
 				],
 				options: [
 					{
@@ -543,7 +543,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 			{
 				property: "dairySlimMaintain",
 				prereqs: [
-					() => !!V.dairySlimMaintainUpgrade,
+					 !!V.dairySlimMaintainUpgrade,
 				],
 				options: [
 					{
@@ -563,7 +563,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 			{
 				property: "dairyImplantsSetting",
 				prereqs: [
-					() => V.dairySlimMaintain === 0,
+					 V.dairySlimMaintain === 0,
 				],
 				options: [
 					{
@@ -642,7 +642,7 @@ App.Facilities.Dairy.dairy = class Dairy extends App.Facilities.Facility {
 			{
 				property: "milkmaidImpregnates",
 				prereqs: [
-					() => !!S.Milkmaid,
+					 !!S.Milkmaid,
 				],
 				options: [
 					{
diff --git a/src/facilities/facilityRetrievalWorkaround.js b/src/facilities/facilityRetrievalWorkaround.js
index 864638388abd43dd3485abac205ebe5804441876..992825e8a280710423d93ea130400d7ec2df57aa 100644
--- a/src/facilities/facilityRetrievalWorkaround.js
+++ b/src/facilities/facilityRetrievalWorkaround.js
@@ -115,15 +115,12 @@ App.UI.facilityRetrievalWorkaround = function(facility) {
 	}
 
 	function checkOrgans(slave) {
-		if (V.incubator.organs.length > 0) {
-			for (const organ of V.incubator.organs.filter(o => o.ID === slave.ID)) {
-				const newOrgan = {type: organ.type, weeksToCompletion: organ.weeksToCompletion, ID: slave.ID};
-				if (newOrgan.weeksToCompletion <= 0) {
-					V.completedOrgans.push(organ);
-				} else {
-					V.organs.push(newOrgan);
-				}
-				V.incubator.organs.deleteAt(organ);
+		const movedOrgans = V.incubator.organs.deleteWith(o => o.ID === slave.ID)
+		for (const organ of movedOrgans) {
+			if (organ.weeksToCompletion <= 0) {
+				V.completedOrgans.push(organ);
+			} else {
+				V.organs.push(organ);
 			}
 		}
 	}
diff --git a/src/facilities/farmyard/farmyard.js b/src/facilities/farmyard/farmyard.js
index ef13c786155f9f80f1ea2b45bca68ffbef9e880f..5ffd5c219c0af54ece832539a0473643b2096edc 100644
--- a/src/facilities/farmyard/farmyard.js
+++ b/src/facilities/farmyard/farmyard.js
@@ -185,7 +185,7 @@ App.Facilities.Farmyard.farmyard = class Farmyard extends App.Facilities.Facilit
 							`slightly increases upkeep costs`,
 						],
 						prereqs: [
-							() => V.farmyardUpgrades.pump > 0,
+							V.farmyardUpgrades.pump > 0,
 						],
 					},
 					{
@@ -213,7 +213,7 @@ App.Facilities.Farmyard.farmyard = class Farmyard extends App.Facilities.Facilit
 							`moderately decreases upkeep costs`,
 						],
 						prereqs: [
-							() => V.farmyardUpgrades.fertilizer > 0,
+							V.farmyardUpgrades.fertilizer > 0,
 						],
 					},
 					{
@@ -242,7 +242,7 @@ App.Facilities.Farmyard.farmyard = class Farmyard extends App.Facilities.Facilit
 							`slightly increases upkeep costs`,
 						],
 						prereqs: [
-							() => V.farmyardUpgrades.hydroponics > 0,
+							V.farmyardUpgrades.hydroponics > 0,
 						],
 					},
 					{
@@ -271,7 +271,7 @@ App.Facilities.Farmyard.farmyard = class Farmyard extends App.Facilities.Facilit
 							`slightly increases upkeep costs`,
 						],
 						prereqs: [
-							() => V.farmyardUpgrades.seeds > 0
+							V.farmyardUpgrades.seeds > 0
 						],
 					},
 					{
@@ -290,8 +290,8 @@ App.Facilities.Farmyard.farmyard = class Farmyard extends App.Facilities.Facilit
 			{
 				property: "farmyardShows",
 				prereqs: [
-					() => this.facility.hostedSlaves > 0,
-					() => V.farmyardKennels > 0 || V.farmyardStables > 0 || V.farmyardCages > 0,
+					this.facility.hostedSlaves > 0,
+					V.farmyardKennels > 0 || V.farmyardStables > 0 || V.farmyardCages > 0,
 				],
 				options: [
 					{
@@ -314,9 +314,9 @@ App.Facilities.Farmyard.farmyard = class Farmyard extends App.Facilities.Facilit
 			{
 				property: "farmyardBreeding",
 				prereqs: [
-					() => !!V.seeBestiality,
-					() => !!V.farmyardShows,
-					() => !!V.animals.canine || !!V.animals.hooved || !!V.animals.feline,
+					!!V.seeBestiality,
+					!!V.farmyardShows,
+					!!V.animals.canine || !!V.animals.hooved || !!V.animals.feline,
 				],
 				options: [
 					{
@@ -334,8 +334,8 @@ App.Facilities.Farmyard.farmyard = class Farmyard extends App.Facilities.Facilit
 			{
 				property: "farmyardRestraints",
 				prereqs: [
-					() => !!V.farmyardBreeding,
-					() => V.farmyardShows !== 0,
+					!!V.farmyardBreeding,
+					V.farmyardShows !== 0,
 				],
 				options: [
 					{
diff --git a/src/facilities/farmyard/food/food.js b/src/facilities/farmyard/food/food.js
index 50d0c3b770b882e764671af8c398f79bd7f1eb35..e7e2a9e55f7af9d33f5fb15b08220f208223e23a 100644
--- a/src/facilities/farmyard/food/food.js
+++ b/src/facilities/farmyard/food/food.js
@@ -6,6 +6,8 @@
  * @returns {number}
  */
 App.Facilities.Farmyard.foodAmount = function(slave) {
+	if (slave && V.farmyardShows === 2) { return 0; }
+
 	let food = 100;
 
 	if (V.farmyardUpgrades.pump) {
diff --git a/src/facilities/farmyard/food/saProduceFood.js b/src/facilities/farmyard/food/saProduceFood.js
index d5e89f19b891d8ab4d4a6289e0ec380fb9fbef8e..26fe219c3ba808d73ab2772e1d905ba8fa94e844 100644
--- a/src/facilities/farmyard/food/saProduceFood.js
+++ b/src/facilities/farmyard/food/saProduceFood.js
@@ -123,7 +123,7 @@ App.Facilities.Farmyard.produceFood = function(slave) {
 	}
 
 	function shows() {
-		if (V.farmyardShows > 0) {
+		if (V.farmyardShows === 1) {
 			return `Since ${he} also has to put on shows for your citizens, ${he} can only work on food production for half of ${his} shift, cutting down on the amount of food ${he} would have otherwise produced.`;
 		}
 	}
diff --git a/src/facilities/farmyard/shows/farmShowsIncome.js b/src/facilities/farmyard/shows/farmShowsIncome.js
index ee6d2b6b21027f2531e7e918f20a101f9c48613b..b4a11f8c303b0017eeb138e5f9170e507ae0c755 100644
--- a/src/facilities/farmyard/shows/farmShowsIncome.js
+++ b/src/facilities/farmyard/shows/farmShowsIncome.js
@@ -461,6 +461,18 @@ App.Facilities.Farmyard.farmShowsIncome = function(slave) {
 			cash *= 0.5;
 		}
 
+		// Multipliers
+
+		if (V.animals.canine.length > 0) {
+			cash *= (1 + (V.animals.canine.length * 0.05));
+		}
+		if (V.animals.hooved.length > 0) {
+			cash *= (1 + (V.animals.hooved.length * 0.05));
+		}
+		if (V.animals.feline.length > 0) {
+			cash *= (1 + (V.animals.feline.length * 0.05));
+		}
+
 		setSlaveDevotion();
 		setSlaveTrust();
 
diff --git a/src/facilities/farmyard/shows/saFarmyardShows.js b/src/facilities/farmyard/shows/saFarmyardShows.js
index 556140b72adee13453f069874f439507667757da..99d5431d120ea3503f8dcdf387774b4a8ae949eb 100644
--- a/src/facilities/farmyard/shows/saFarmyardShows.js
+++ b/src/facilities/farmyard/shows/saFarmyardShows.js
@@ -385,18 +385,20 @@ App.Facilities.Farmyard.putOnShows = function(slave) {
 	}
 
 	function energy() {
-		if (slave.energy > 95) {
-			return `The fact that ${he} is a nymphomaniac helps ${him} to go for longer, allowing ${him} to really put on an amazing show.`;
-		} else if (slave.energy > 80) {
-			return `The fact that ${his} sex drive is so powerful helps ${him} to really put on good shows.`;
-		} else if (slave.energy > 60) {
-			return `The fact that ${his} sex drive is so good helps ${him} to put on good shows.`;
-		} else if (slave.energy > 40) {
-			return `${His} average sex drive allows ${him} to put on a decent show.`;
-		} else if (slave.energy > 20) {
-			return `The fact that ${his} sex drive is so poor affects ${his} performance.`;
-		} else {
-			return `The fact that ${his} sex drive is nonexistent really hinders ${his} ability to put on a decent show.`;
+		if (V.seeBestiality) {
+			if (slave.energy > 95) {
+				return `The fact that ${he} is a nymphomaniac helps ${him} to go for longer, allowing ${him} to really put on an amazing show.`;
+			} else if (slave.energy > 80) {
+				return `The fact that ${his} sex drive is so powerful helps ${him} to really put on good shows.`;
+			} else if (slave.energy > 60) {
+				return `The fact that ${his} sex drive is so good helps ${him} to put on good shows.`;
+			} else if (slave.energy > 40) {
+				return `${His} average sex drive allows ${him} to put on a decent show.`;
+			} else if (slave.energy > 20) {
+				return `The fact that ${his} sex drive is so poor affects ${his} performance.`;
+			} else {
+				return `The fact that ${his} sex drive is nonexistent really hinders ${his} ability to put on a decent show.`;
+			}
 		}
 	}
 
@@ -419,7 +421,7 @@ App.Facilities.Farmyard.putOnShows = function(slave) {
 			case "humiliation":
 				if (V.seeBestiality) {
 					if (slave.fetishKnown) {
-						return `${slave.slaveName} uses the most of this humiliating experience to really put on a show, to <span class="reputation inc">the approval of ${his} audience</span>.`;
+						return `${slave.slaveName} uses the most of this humiliating experience to really put on a show, to <span class="reputation inc">the approval of ${his} audience.</span>`;
 					}
 				}
 		}
diff --git a/src/facilities/headGirlSuite/headGirlSuite.js b/src/facilities/headGirlSuite/headGirlSuite.js
index c47653f56f4b2d04c799f39daee4debf10729d97..1a5abf715089c41b5d550660ba05e49b36fedc4c 100644
--- a/src/facilities/headGirlSuite/headGirlSuite.js
+++ b/src/facilities/headGirlSuite/headGirlSuite.js
@@ -78,7 +78,7 @@ App.Facilities.HGSuite.headGirlSuite = class HeadGirlSuite extends App.Facilitie
 				{
 					property: "HGSuiteSurgery",
 					prereqs: [
-						() => !V.HGSuiteEquality,
+						!V.HGSuiteEquality,
 					],
 					options: [
 						{
@@ -96,7 +96,7 @@ App.Facilities.HGSuite.headGirlSuite = class HeadGirlSuite extends App.Facilitie
 				{
 					property: "HGSuiteAbortion",
 					prereqs: [
-						() => !V.HGSuiteEquality,
+						!V.HGSuiteEquality,
 					],
 					options: [
 						{
@@ -114,7 +114,7 @@ App.Facilities.HGSuite.headGirlSuite = class HeadGirlSuite extends App.Facilitie
 				{
 					property: "HGSuiteDrugs",
 					prereqs: [
-						() => !V.HGSuiteEquality,
+						!V.HGSuiteEquality,
 					],
 					options: [
 						{
@@ -132,7 +132,7 @@ App.Facilities.HGSuite.headGirlSuite = class HeadGirlSuite extends App.Facilitie
 				{
 					property: "HGSuiteHormones",
 					prereqs: [
-						() => !V.HGSuiteEquality,
+						!V.HGSuiteEquality,
 					],
 					options: [
 						{
diff --git a/src/facilities/incubator/incubatorInteract.js b/src/facilities/incubator/incubatorInteract.js
index b97f065d16fc52366bdc05c7e139697cf685f8f8..35c944eec283e712bf07240f7df69a546ae3e7d1 100644
--- a/src/facilities/incubator/incubatorInteract.js
+++ b/src/facilities/incubator/incubatorInteract.js
@@ -46,6 +46,8 @@ App.UI.incubator = function() {
 		const incubatorSlaves = V.incubator.tanks.length;
 		const freeTanks = V.incubator.capacity - incubatorSlaves;
 		const reservedChildren = FetusGlobalReserveCount("incubator");
+		el.append(App.UI.DOM.makeElement("h1", incubatorNameCaps));
+
 		r.push(`${incubatorNameCaps} is a clean, cold hall designed to be lined with tanks and their connected monitoring systems.`);
 
 		if (incubatorSlaves > 2) {
@@ -64,7 +66,7 @@ App.UI.incubator = function() {
 				)
 			);
 		}
-		App.Events.addNode(el, r, "p");
+		App.Events.addNode(el, r, "div", ["scene-intro"]);
 
 		const tankP = document.createElement("p");
 		r = [];
@@ -1029,9 +1031,9 @@ App.UI.incubator = function() {
 
 	function tankSettings() {
 		const el = new DocumentFragment();
-		let p;
+		let div;
 		let r = [];
-		let row;
+		let section;
 		let linkArray;
 		r.push("Target age for release:");
 		r.push(
@@ -1086,10 +1088,10 @@ App.UI.incubator = function() {
 		r.push(App.UI.DOM.makeElement("span", `Setting will not be applied to tanks in use.`, "note"));
 		App.Events.addNode(el, r, "p");
 
-		row = document.createElement("p");
+		section = document.createElement("p");
 		if (V.incubator.setting.bulkRelease === 1) {
-			row.append(`Released children will be handled in bulk and not receive personal attention. `);
-			row.append(
+			section.append(`Released children will be handled in bulk and not receive personal attention. `);
+			section.append(
 				App.UI.DOM.link(
 					`Individual release`,
 					() => {
@@ -1099,8 +1101,8 @@ App.UI.incubator = function() {
 				)
 			);
 		} else {
-			row.append(`Released children will be seen to personally. `);
-			row.append(
+			section.append(`Released children will be seen to personally. `);
+			section.append(
 				App.UI.DOM.link(
 					`Bulk release`,
 					() => {
@@ -1110,404 +1112,374 @@ App.UI.incubator = function() {
 				)
 			);
 		}
-		el.append(row);
+		el.append(section);
 
-		row = document.createElement("p");
+		section = document.createElement("div");
 
 		if (V.incubator.upgrade.speed === 52) {
-			row.append(`It has been upgraded with perfected growth accelerants; children grow at the rate of 1 week to 1 year.`);
+			section.append(`It has been upgraded with perfected growth accelerants; children grow at the rate of 1 week to 1 year.`);
 		} else if (V.incubator.upgrade.speed === 18) {
 			const cost = Math.trunc(500000 * V.upgradeMultiplierArcology);
-			row.append(`It has been upgraded with advanced experimental growth accelerants; children grow at the rate of 3 weeks to 1 year. `);
-			row.append(
-				choice(
-					`Fund speculative research into maximizing growth rate`,
-					() => {
-						cashX(forceNeg(cost), "capEx");
+			section.append(`It has been upgraded with advanced experimental growth accelerants; children grow at the rate of 3 weeks to 1 year.`);
+			section.append(
+				makePurchase(`Fund speculative research into maximizing growth rate`, cost, "capEx", {
+					handler: () => {
 						V.incubator.upgrade.speed = 52;
 						refresh();
 					},
-					"",
-					`Costs ${cashFormat(cost)} and will increase upkeep costs`
-				)
+					notes: [`will increase upkeep costs`]
+				})
 			);
 		} else if (V.incubator.upgrade.speed === 9) {
 			const cost = Math.trunc(75000 * V.upgradeMultiplierArcology);
-			row.append(`It has been upgraded with advanced growth accelerants; children grow at the rate of 6 weeks to 1 year. `);
-			row.append(
-				choice(
-					`Fund research into increasing growth rate even further`,
-					() => {
-						cashX(forceNeg(cost), "capEx");
+			section.append(`It has been upgraded with advanced growth accelerants; children grow at the rate of 6 weeks to 1 year.`);
+			section.append(
+				makePurchase(`Fund research into increasing growth rate even further`, cost, "capEx", {
+					handler: () => {
 						V.incubator.upgrade.speed = 18;
 						refresh();
 					},
-					"",
-					`Costs ${cashFormat(cost)} and will increase upkeep costs`
-				)
+					notes: [`will increase upkeep costs`]
+				})
 			);
 		} else if (V.incubator.upgrade.speed === 6) {
 			const cost = Math.trunc(30000 * V.upgradeMultiplierArcology);
-			row.append(`It has been upgraded with growth accelerants; children grow at the rate of 9 weeks to 1 year. `);
-			row.append(
-				choice(
-					`Further upgrade the incubators with specialized stem cells to speed growth`,
-					() => {
-						cashX(forceNeg(cost), "capEx");
+			section.append(`It has been upgraded with growth accelerants; children grow at the rate of 9 weeks to 1 year.`);
+			section.append(
+				makePurchase(`Further upgrade the incubators with specialized stem cells to speed growth`, cost, "capEx", {
+					handler: () => {
 						V.incubator.upgrade.speed = 9;
 						refresh();
 					},
-					"",
-					`Costs ${cashFormat(cost)} and will increase upkeep costs`
-				)
+					notes: [`will increase upkeep costs`]
+				})
 			);
 		} else if (V.incubator.upgrade.speed === 5) {
 			const cost = Math.trunc(30000 * V.upgradeMultiplierArcology);
-			row.append(`The incubation tanks are basic; children grow at the rate of 12 weeks to 1 year. `);
-			row.append(
-				choice(
-					`Upgrade the incubators with growth accelerating drugs`,
-					() => {
-						cashX(forceNeg(cost), "capEx");
+			section.append(`The incubation tanks are basic; children grow at the rate of 12 weeks to 1 year.`);
+			section.append(
+				makePurchase(`Upgrade the incubators with growth accelerating drugs`, cost, "capEx", {
+					handler: () => {
 						V.incubator.upgrade.speed = 6;
 						refresh();
 					},
-					"",
-					`Costs ${cashFormat(cost)} and will increase upkeep costs`
-				)
+					notes: [`will increase upkeep costs`]
+				})
 			);
 		}
 
-		el.append(row);
+		el.append(section);
 
-		p = document.createElement("p");
-		row = document.createElement("div");
+		div = document.createElement("div");
+		section = document.createElement("div");
 		if (V.incubator.upgrade.weight === 1) {
-			row.append(`Advanced caloric monitoring systems have been installed in the tanks to monitor and maintain a developing child's weight.`);
-			p.append(row);
-			row = document.createElement("div");
+			section.append(`Advanced caloric monitoring systems have been installed in the tanks to monitor and maintain a developing child's weight.`);
+			div.append(section);
+			section = document.createElement("div");
 			linkArray = [];
 			if (V.incubator.setting.weight === 1) {
-				row.append(`Weight is not being properly managed; excessive weight gain is likely. `);
+				section.append(`Weight is not being properly managed; excessive weight gain is likely.`);
 			} else {
 				linkArray.push(makeLink(`Estimate only`, () => { V.incubator.setting.weight = 1; }, refresh));
 			}
 
 			if (V.incubator.setting.weight === 2) {
-				row.append(`Weight is being carefully managed; children will be released at a healthy weight. `);
+				section.append(`Weight is being carefully managed; children will be released at a healthy weight.`);
 			} else {
 				linkArray.push(makeLink(`Activate`, () => { V.incubator.setting.weight = 2; }, refresh));
 			}
 
 			if (V.incubator.setting.weight === 0) {
-				row.append(`Weight management systems are offline; children will likely be malnourished. `);
+				section.append(`Weight management systems are offline; children will likely be malnourished.`);
 			} else {
 				linkArray.push(makeLink(`Disable`, () => { V.incubator.setting.weight = 0; }, refresh));
 			}
-			row.append(App.UI.DOM.generateLinksStrip(linkArray));
+			section.append(App.UI.DOM.generateLinksStrip(linkArray));
 		} else {
 			const cost = Math.trunc(20000 * V.upgradeMultiplierArcology);
-			row.append(`There are no systems in place to control a growing child's weight; they will likely come out emaciated from the rapid growth. `);
-			row.append(
-				choice(
-					`Upgrade the growth tanks with weight monitoring systems`,
-					() => {
-						cashX(forceNeg(cost), "capEx");
+			section.append(`There are no systems in place to control a growing child's weight; they will likely come out emaciated from the rapid growth.`);
+			section.append(
+				makePurchase(`Upgrade the growth tanks with weight monitoring systems`, cost, "capEx", {
+					handler: () => {
 						V.incubator.upgrade.weight = 1;
 						refresh();
 					},
-					"",
-					`Costs ${cashFormat(cost)} and will increase upkeep costs`
-				)
+					notes: [`will increase upkeep costs`]
+				})
 			);
 		}
 
-		p.append(row);
-		el.append(p);
+		div.append(section);
+		el.append(div);
 
-		p = document.createElement("p");
-		row = document.createElement("div");
+		div = document.createElement("div");
+		section = document.createElement("div");
 
 		if (V.incubator.upgrade.muscles === 1) {
-			row.append(`Advanced monitoring and steroid injection systems have been installed in the tanks to monitor and maintain a developing child's musculature.`);
-			p.append(row);
-			row = document.createElement("div");
+			section.append(`Advanced monitoring and steroid injection systems have been installed in the tanks to monitor and maintain a developing child's musculature.`);
+			div.append(section);
+			section = document.createElement("div");
 			linkArray = [];
 			if (V.incubator.setting.muscles === 2) {
-				row.append(`Strength levels are purposefully set higher than recommended; excessive muscle gain is likely. `);
+				section.append(`Strength levels are purposefully set higher than recommended; excessive muscle gain is likely.`);
 			} else {
 				linkArray.push(makeLink(`Overload`, () => { V.incubator.setting.muscles = 2; }, refresh));
 			}
 
 			if (V.incubator.setting.muscles === 1) {
-				row.append(`Musculature is being carefully managed; children will be released with near normal strength. `);
+				section.append(`Musculature is being carefully managed; children will be released with near normal strength.`);
 			} else {
 				linkArray.push(makeLink(`Activate`, () => { V.incubator.setting.muscles = 1; }, refresh));
 			}
 
 			if (V.incubator.setting.muscles === 0) {
-				row.append(`Strength management systems are offline; children will likely be released extremely weak. `);
+				section.append(`Strength management systems are offline; children will likely be released extremely weak.`);
 			} else {
 				linkArray.push(makeLink(`Disable`, () => { V.incubator.setting.muscles = 0; }, refresh));
 			}
 
-			row.append(App.UI.DOM.generateLinksStrip(linkArray));
+			section.append(App.UI.DOM.generateLinksStrip(linkArray));
 		} else {
 			const cost = Math.trunc(20000 * V.upgradeMultiplierArcology);
-			row.append(`There are no systems in place to control a growing child's musculature; they will likely come out frail and weak from the rapid growth. `);
-			row.append(
-				choice(
-					`Upgrade the growth tanks with muscle monitoring systems`,
-					() => {
-						cashX(forceNeg(cost), "capEx");
+			section.append(`There are no systems in place to control a growing child's musculature; they will likely come out frail and weak from the rapid growth.`);
+			section.append(
+				makePurchase(`Upgrade the growth tanks with muscle monitoring systems`, cost, "capEx", {
+					handler: () => {
 						V.incubator.upgrade.muscles = 1;
 						refresh();
 					},
-					"",
-					`Costs ${cashFormat(cost)} and will increase upkeep costs`
-				)
+					notes: [`will increase upkeep costs`]
+				})
 			);
 		}
 
-		p.append(row);
-		el.append(p);
+		div.append(section);
+		el.append(div);
 
-		p = document.createElement("p");
-		row = document.createElement("div");
+		div = document.createElement("div");
+		section = document.createElement("div");
 
 		if (V.incubator.upgrade.reproduction === 1) {
-			row.append(`Advanced monitoring and hormone injection systems have been installed in the tanks to influence a developing child's reproductive organs.`);
-			p.append(row);
-			row = document.createElement("div");
+			section.append(`Advanced monitoring and hormone injection systems have been installed in the tanks to influence a developing child's reproductive organs.`);
+			div.append(section);
+			section = document.createElement("div");
 			linkArray = [];
 			if (V.incubator.setting.reproduction === 2) {
-				row.append(`Hormone levels are purposefully set higher than recommended; over-active reproductive systems are likely. `);
+				section.append(`Hormone levels are purposefully set higher than recommended; over-active reproductive systems are likely.`);
 			} else {
 				linkArray.push(makeLink(`Overload`, () => { V.incubator.setting.reproduction = 2; }, refresh));
 			}
 
 			if (V.incubator.setting.reproduction === 1) {
-				row.append(`Hormone levels are being carefully managed; children will be released with fully functional reproductive organs. `);
+				section.append(`Hormone levels are being carefully managed; children will be released with fully functional reproductive organs.`);
 			} else {
 				linkArray.push(makeLink(`Limit`, () => { V.incubator.setting.reproduction = 1; }, refresh));
 			}
 
 			if (V.incubator.setting.reproduction === 0) {
-				row.append(`Reproduction management systems are offline; children will undergo normal puberty. `);
+				section.append(`Reproduction management systems are offline; children will undergo normal puberty.`);
 			} else {
 				linkArray.push(makeLink(`Disable`, () => { V.incubator.setting.reproduction = 0; }, refresh));
 			}
-			row.append(App.UI.DOM.generateLinksStrip(linkArray));
-			p.append(row);
-			el.append(p);
+			section.append(App.UI.DOM.generateLinksStrip(linkArray));
+			div.append(section);
+			el.append(div);
 
 			if (V.incubator.upgrade.pregAdaptation === 1) {
 				// Should be visible only after incubator.upgrade.reproduction is installed
-				p = document.createElement("p");
-				row = document.createElement("div");
+				div = document.createElement("div");
+				section = document.createElement("div");
 				linkArray = [];
 				if (V.incubator.setting.pregAdaptation === 3) {
-					row.append(`Pregnancy adaptation system online: All. `);
+					section.append(`Pregnancy adaptation system online: All.`);
 				} else {
 					linkArray.push(makeLink(`All`, () => { V.incubator.setting.pregAdaptation = 3; }, refresh));
 				}
 
 				if (V.incubator.setting.pregAdaptation === 2) {
-					row.append(`Pregnancy adaptation system online: Males only. `);
+					section.append(`Pregnancy adaptation system online: Males only.`);
 				} else {
 					linkArray.push(makeLink(`Males`, () => { V.incubator.setting.pregAdaptation = 2; }, refresh));
 				}
 
 				if (V.incubator.setting.pregAdaptation === 1) {
-					row.append(`Pregnancy adaptation system online: Females only. `);
+					section.append(`Pregnancy adaptation system online: Females only.`);
 				} else {
 					linkArray.push(makeLink(`Females`, () => { V.incubator.setting.pregAdaptation = 1; }, refresh));
 				}
 
 				if (V.incubator.setting.pregAdaptation === 0) {
-					row.append(`Pregnancy adaptation system offline. `);
+					section.append(`Pregnancy adaptation system offline.`);
 				} else {
 					linkArray.push(makeLink(`Disable`, () => { V.incubator.setting.pregAdaptation = 0; }, refresh));
 				}
-				row.append(App.UI.DOM.generateLinksStrip(linkArray));
+				section.append(App.UI.DOM.generateLinksStrip(linkArray));
 
 				if (V.incubator.upgrade.pregAdaptation === 1 && V.incubator.setting.pregAdaptation > 0) {
 					// Should be visible only after incubator.upgrade.reproduction is installed and turned on
-					p.append(row);
-					row = document.createElement("div");
+					div.append(section);
+					section = document.createElement("div");
 					linkArray = [];
 					if (V.incubator.setting.pregAdaptationPower === 1) {
-						row.append(`Pregnancy adaptation programmed to advanced procedures. Up to triplet pregnancy should be safe for the subjects. `);
+						section.append(`Pregnancy adaptation programmed to advanced procedures. Up to triplet pregnancy should be safe for the subjects.`);
 					} else {
 						linkArray.push(makeLink(`Advanced`, () => { V.incubator.setting.pregAdaptationPower = 1; }, refresh));
 					}
 
 					if (V.incubator.setting.pregAdaptationPower === 2) {
-						row.append(`Pregnancy adaptation programmed to intensive procedures. Up to octuplet pregnancy should be possible for the subjects. Warning! Side effects may occur to health and mental condition. `);
+						section.append(`Pregnancy adaptation programmed to intensive procedures. Up to octuplet pregnancy should be possible for the subjects. Warning! Side effects may occur to health and mental condition.`);
 					} else {
 						linkArray.push(makeLink(`Intensive`, () => { V.incubator.setting.pregAdaptationPower = 2; }, refresh));
 					}
 
 					if (V.incubator.setting.pregAdaptationPower === 3) {
-						row.append(`Pregnancy adaptation programmed to extreme procedures. Normally unsustainable pregnancies may be possible for some subjects. Actual capacity will vary with genetic and other individual conditions. WARNING! Extreme side effects may occur to health and mental condition! `);
+						section.append(`Pregnancy adaptation programmed to extreme procedures. Normally unsustainable pregnancies may be possible for some subjects. Actual capacity will vary with genetic and other individual conditions. WARNING! Extreme side effects may occur to health and mental condition! `);
 					} else {
 						linkArray.push(makeLink(`Extreme`, () => { V.incubator.setting.pregAdaptationPower = 3; }, refresh));
 					}
 
 					if (V.incubator.setting.pregAdaptationPower === 0) {
-						row.append(`Pregnancy adaptation programmed to standard procedures. Normal pregnancy should be safe for subjects. `);
+						section.append(`Pregnancy adaptation programmed to standard procedures. Normal pregnancy should be safe for subjects.`);
 					} else {
 						linkArray.push(makeLink(`Standard`, () => { V.incubator.setting.pregAdaptationPower = 0; }, refresh));
 					}
-					row.append(App.UI.DOM.generateLinksStrip(linkArray));
-					p.append(row);
+					section.append(App.UI.DOM.generateLinksStrip(linkArray));
+					div.append(section);
 
-					row = document.createElement("div");
-					App.UI.DOM.appendNewElement("span", row, `Due to the high complexity and steep risks of the procedure, settings will not be changed on tanks in use.`, "note");
+					section = document.createElement("div");
+					App.UI.DOM.appendNewElement("span", section, `Due to the high complexity and steep risks of the procedure, settings will not be changed on tanks in use.`, "note");
 				}
 			}
-			p.append(row);
-			el.append(p);
+			div.append(section);
+			el.append(div);
 		} else {
 			const cost = Math.trunc(50000 * V.upgradeMultiplierArcology);
-			row.append(`There are no systems in place to control a growing child's reproductive capability. `);
-			row.append(
-				choice(
-					`Upgrade the growth tanks with hormone monitoring systems`,
-					() => {
-						cashX(forceNeg(cost), "capEx");
+			section.append(`There are no systems in place to control a growing child's reproductive capability.`);
+			section.append(
+				makePurchase(`Upgrade the growth tanks with hormone monitoring systems`, cost, "capEx", {
+					handler: () => {
 						V.incubator.upgrade.reproduction = 1;
 						refresh();
 					},
-					"",
-					`Costs ${cashFormat(cost)} and will increase upkeep costs`
-				)
+					notes: [`will increase upkeep costs`]
+				})
 			);
-			p.append(row);
-			el.append(p);
+			div.append(section);
+			el.append(div);
 		}
 
 
-		row = document.createElement("div");
+		section = section = App.UI.DOM.makeElement("div", null, ["margin-top"]);
 
 		if (V.incubator.upgrade.organs === 1) {
-			row.append(`Surgical tools have been added to the tank to be able to extract tissue samples from the occupant.`);
+			section.append(`Surgical tools have been added to the tank to be able to extract tissue samples from the occupant.`);
 		} else if (V.organFarmUpgrade >= 1) {
 			const cost = Math.trunc(10000 * V.upgradeMultiplierArcology);
-			row.append(`The tanks lack the ability to extract tissue samples to be used by the organ fabricator. `);
-			row.append(
-				choice(
-					`Upgrade the growth tanks with surgical extraction tools`,
-					() => {
-						cashX(forceNeg(cost), "capEx");
+			section.append(`The tanks lack the ability to extract tissue samples to be used by the organ fabricator.`);
+			section.append(
+				makePurchase(`Upgrade the growth tanks with surgical extraction tools`, cost, "capEx", {
+					handler: () => {
 						V.incubator.upgrade.organs = 1;
 						refresh();
 					},
-					"",
-					`Costs ${cashFormat(cost)} and will increase upkeep costs`
-				)
+					notes: [`will increase upkeep costs`]
+				})
 			);
 		} else {
-			row.append(`The tanks lack the ability to extract tissue samples and the dispensary lacks the ability to make use of them to fabricate organs.`);
+			App.UI.DOM.appendNewElement("span", section, `The tanks lack the ability to extract tissue samples and the dispensary lacks the ability to make use of them to fabricate organs.`, ["note"]);
 		}
 
-		el.append(row);
+		el.append(section);
 
-		p = document.createElement("p");
-		row = document.createElement("div");
+		div = document.createElement("div");
+		section = document.createElement("div");
 
 		if (V.incubator.upgrade.growthStims === 1) {
-			row.append(`Advanced monitoring and stimulant injection systems have been installed in the tanks to monitor and maintain a developing child's height.`);
-			row = document.createElement("div");
+			section.append(`Advanced monitoring and stimulant injection systems have been installed in the tanks to monitor and maintain a developing child's height.`);
+			section = document.createElement("div");
 			linkArray = [];
 			if (V.incubator.setting.growthStims === 2) {
-				row.append(`Children are injected with higher than recommended doses of stimulants; exceeding expected final height is likely. `);
+				section.append(`Children are injected with higher than recommended doses of stimulants; exceeding expected final height is likely.`);
 			} else {
 				linkArray.push(makeLink(`Overload`, () => { V.incubator.setting.growthStims = 2; }, refresh));
 			}
 
 			if (V.incubator.setting.growthStims === 1) {
-				row.append(`Children are injected with the recommended dosage of stimulants; they will grow to their full expected height. `);
+				section.append(`Children are injected with the recommended dosage of stimulants; they will grow to their full expected height.`);
 			} else {
 				linkArray.push(makeLink(`Limit`, () => { V.incubator.setting.growthStims = 1; }, refresh));
 			}
 
 			if (V.incubator.setting.growthStims === 0) {
-				row.append(`Growth stimulant injection systems are offline; children will develop normally. `);
+				section.append(`Growth stimulant injection systems are offline; children will develop normally.`);
 			} else {
 				linkArray.push(makeLink(`Disable`, () => { V.incubator.setting.growthStims = 0; }, refresh));
 			}
-			row.append(App.UI.DOM.generateLinksStrip(linkArray));
+			section.append(App.UI.DOM.generateLinksStrip(linkArray));
 		} else if (V.growthStim === 1) {
 			const cost = Math.trunc(20000 * V.upgradeMultiplierArcology);
-			row.append(`There are no systems in place to control a growing child's height. `);
-			row.append(
-				choice(
-					`Upgrade the growth tanks with stimulants injection systems`,
-					() => {
-						cashX(forceNeg(cost), "capEx");
+			section.append(`There are no systems in place to control a growing child's height.`);
+			section.append(
+				makePurchase(`Upgrade the growth tanks with stimulants injection systems`, cost, "capEx", {
+					handler: () => {
 						V.incubator.upgrade.growthStims = 1;
 						refresh();
 					},
-					"",
-					`Costs ${cashFormat(cost)} and will increase upkeep costs`
-				)
+					notes: [`will increase upkeep costs`]
+				})
 			);
 		} else {
-			row.append(`There are no systems in place to control a growing child's height and you lack the capability to fabricate growth stimulants.`);
+			App.UI.DOM.appendNewElement("span", section, `There are no systems in place to control a growing child's height and you lack the capability to fabricate growth stimulants.`, ["note"]);
 		}
-		p.append(row);
-		el.append(p);
+		div.append(section);
+		el.append(div);
 
 		if (V.minimumSlaveAge <= 6 && (V.arcologies[0].FSRepopulationFocus >= 60 || V.BlackmarketPregAdaptation === 1)) {
 			/* Main prerequisite - stable repopulation FS OR documentation purchased from black market. And age gate. */
-			p = document.createElement("p");
-			row = document.createElement("div");
+			div = document.createElement("div");
+			section = document.createElement("div");
 			if (V.incubator.upgrade.pregAdaptation === 1) {
-				row.append(`The incubators have been upgraded with special set of manipulators, probes, nozzles and syringes coupled together with specific programs to take advantage of the accelerated growth to heighten viable reproductive capacity. These include injections of specialized serums and mechanical manipulation of the reproductive system and associated tissues, organs, muscles and bones.`);
+				section.append(`The incubators have been upgraded with special set of manipulators, probes, nozzles and syringes coupled together with specific programs to take advantage of the accelerated growth to heighten viable reproductive capacity. These include injections of specialized serums and mechanical manipulation of the reproductive system and associated tissues, organs, muscles and bones.`);
 			} else {
-				row.append(`The highly controlled environment inside incubation tube coupled with the greatly accelerated growth process is the perfect opportunity to push the boundaries of a body's ability to sustain pregnancy. This will include injections of specialized serums and mechanical manipulation of their reproductive system through a special set of manipulators, probes, nozzles and syringes supervised by a powerful monitoring program. Costly to maintain.`);
-				p.append(row);
+				section.append(`The highly controlled environment inside incubation tube coupled with the greatly accelerated growth process is the perfect opportunity to push the boundaries of a body's ability to sustain pregnancy. This will include injections of specialized serums and mechanical manipulation of their reproductive system through a special set of manipulators, probes, nozzles and syringes supervised by a powerful monitoring program. Costly to maintain.`);
+				div.append(section);
 
-				row = document.createElement("div");
+				section = document.createElement("div");
 				if (V.incubator.upgrade.reproduction < 1) {
 					/* Now with reports - what is lacking for construction */
-					row.append(`${incubatorNameCaps} lacks advanced monitoring and hormone injection systems. Construction not possible.`);
+					section.append(`${incubatorNameCaps} lacks advanced monitoring and hormone injection systems. Construction not possible.`);
 				} else if (V.incubator.upgrade.organs < 1) {
-					row.append(`${incubatorNameCaps} lacks the ability to extract tissue samples. Construction not possible.`);
+					section.append(`${incubatorNameCaps} lacks the ability to extract tissue samples. Construction not possible.`);
 				} else if (V.dispensaryUpgrade < 1) {
-					row.append(`${incubatorNameCaps} lacks a connection to an advanced pharmaceutical fabricator. Cutting-edge targeted serums production needed as integral part. Construction not possible.`);
+					section.append(`${incubatorNameCaps} lacks a connection to an advanced pharmaceutical fabricator. Cutting-edge targeted serums production needed as integral part. Construction not possible.`);
 				} else if (V.bellyImplants < 1) {
-					row.append(`${incubatorNameCaps} lacks a connection with an implant manufacturing to construct fillable abdominal implants to simulate expansion. Construction not possible.`);
+					section.append(`${incubatorNameCaps} lacks a connection with an implant manufacturing to construct fillable abdominal implants to simulate expansion. Construction not possible.`);
 				} else if (V.incubator.upgrade.growthStims < 1) {
-					row.append(`${incubatorNameCaps} lacks advanced monitoring and stimulant injection systems. Construction not possible.`);
+					section.append(`${incubatorNameCaps} lacks advanced monitoring and stimulant injection systems. Construction not possible.`);
 				} else {
 					const cost = Math.trunc(2000000 * V.upgradeMultiplierArcology);
-					row.append(
-						choice(
-							`Manufacture and install this subsystem`,
-							() => {
-								cashX(forceNeg(cost), "capEx");
+					section.append(
+						makePurchase(`Manufacture and install this subsystem`, cost, "capEx", {
+							handler: () => {
 								V.incubator.upgrade.pregAdaptation = 1;
 								refresh();
 							},
-							"",
-							`Costs ${cashFormat(cost)} and will increase upkeep costs`
-						)
+							notes: [`will increase upkeep costs`]
+						})
 					);
 				}
 			}
-			p.append(row);
-			el.append(p);
+			div.append(section);
+			el.append(div);
 		}
 
-		p = document.createElement("p");
-		row = document.createElement("div");
+		div = document.createElement("div");
+		section = App.UI.DOM.makeElement("div", null, ["margin-top"]);
 		if (V.incubator.setting.imprint === "terror") {
-			row.append(`The imprinting system is currently focused on making them devoted but fearful of you. The imprinting cycle is locked upon incubation start. `);
-			App.UI.DOM.appendNewElement("span", row, `Only affects new infants`, "note");
+			section.append(`The imprinting system is currently focused on making them devoted but fearful of you. The imprinting cycle is locked upon incubation start. `);
+			App.UI.DOM.appendNewElement("span", section, `Only affects new infants`, ["note"]);
 			if (V.bodyswapAnnounced === 1) {
-				row.append(
+				section.append(
 					choice(
 						`Switch the system to focus on preparation for body-swapping`,
 						() => {
@@ -1517,7 +1489,7 @@ App.UI.incubator = function() {
 					)
 				);
 			}
-			row.append(
+			section.append(
 				choice(
 					`Switch the system to focus on attachment`,
 					() => {
@@ -1527,9 +1499,9 @@ App.UI.incubator = function() {
 				)
 			);
 		} else if (V.incubator.setting.imprint === "trust") {
-			row.append(`The imprinting system is currently focused on making them devoted and trusting of you. The imprinting cycle is locked upon incubation start.`);
+			section.append(`The imprinting system is currently focused on making them devoted and trusting of you. The imprinting cycle is locked upon incubation start.`);
 			if (V.bodyswapAnnounced === 1) {
-				row.append(
+				section.append(
 					choice(
 						`Switch the system to focus preparation for body-swapping`,
 						() => {
@@ -1539,7 +1511,7 @@ App.UI.incubator = function() {
 					)
 				);
 			}
-			row.append(
+			section.append(
 				choice(
 					`Switch the system to focus on dependence`,
 					() => {
@@ -1549,8 +1521,8 @@ App.UI.incubator = function() {
 				)
 			);
 		} else {
-			row.append(`The imprinting system is currently focused on producing complete vegetables ready to be used as hosts for body swapping. The imprinting cycle is locked upon incubation start.`);
-			row.append(
+			section.append(`The imprinting system is currently focused on producing complete vegetables ready to be used as hosts for body swapping. The imprinting cycle is locked upon incubation start.`);
+			section.append(
 				choice(
 					`Switch the system to focus on dependence`,
 					() => {
@@ -1559,7 +1531,7 @@ App.UI.incubator = function() {
 					}
 				)
 			);
-			row.append(
+			section.append(
 				choice(
 					`Switch the system to focus on attachment`,
 					() => {
@@ -1569,12 +1541,12 @@ App.UI.incubator = function() {
 				)
 			);
 		}
-		p.append(row);
-		el.append(p);
+		div.append(section);
+		el.append(div);
 
-		row = document.createElement("div");
-		row.append(App.Facilities.rename(App.Entity.facilities.incubator, () => refresh()));
-		el.append(row);
+		section = document.createElement("div");
+		section.append(App.Facilities.rename(App.Entity.facilities.incubator, () => refresh()));
+		el.append(section);
 
 		return el;
 
diff --git a/src/facilities/masterSuite/masterSuite.js b/src/facilities/masterSuite/masterSuite.js
index d9b7c76cb11c4ece1d2812bc5c67c4bb3421c95b..54755e170d68b5b9b408a50dce8eb07810b5960f 100644
--- a/src/facilities/masterSuite/masterSuite.js
+++ b/src/facilities/masterSuite/masterSuite.js
@@ -325,7 +325,7 @@ App.Facilities.MasterSuite.masterSuite = class MasterSuite extends App.Facilitie
 							App.UI.reload();
 						},
 						prereqs: [
-							() => !!V.seePreg,
+							!!V.seePreg,
 						],
 					},
 					{
@@ -343,7 +343,7 @@ App.Facilities.MasterSuite.masterSuite = class MasterSuite extends App.Facilitie
 			{
 				property: "masterSuitePregnancySlaveLuxuries",
 				prereqs: [
-					() => V.masterSuiteUpgradePregnancy > 0,
+					V.masterSuiteUpgradePregnancy > 0,
 				],
 				options: [
 					{
@@ -385,7 +385,7 @@ App.Facilities.MasterSuite.masterSuite = class MasterSuite extends App.Facilitie
 			{
 				property: "masterSuiteHyperPregnancy",
 				prereqs: [
-					() => V.masterSuitePregnancyFertilityDrugs > 0,
+					V.masterSuitePregnancyFertilityDrugs > 0,
 				],
 				options: [
 					{
@@ -407,7 +407,7 @@ App.Facilities.MasterSuite.masterSuite = class MasterSuite extends App.Facilitie
 			{
 				property: "masterSuitePregnancyFertilitySupplements",
 				prereqs: [
-					() => V.masterSuitePregnancyFertilityDrugs === 1 || V.masterSuiteHyperPregnancy === 1,
+					V.masterSuitePregnancyFertilityDrugs === 1 || V.masterSuiteHyperPregnancy === 1,
 				],
 				options: [
 					{
diff --git a/src/facilities/nursery/nursery.js b/src/facilities/nursery/nursery.js
index c8723e569509e44c892cf9278086fecf671e86dd..aa752ec3675204657df8a320e01915174077bfd8 100644
--- a/src/facilities/nursery/nursery.js
+++ b/src/facilities/nursery/nursery.js
@@ -162,7 +162,7 @@ App.Facilities.Nursery.nursery = class Nursery extends App.Facilities.Facility {
 			{
 				property: "MatronIgnoresFlaws",
 				prereqs: [
-					() => !!S.Matron,
+					!!S.Matron,
 				],
 				options: [
 					{
@@ -180,7 +180,7 @@ App.Facilities.Nursery.nursery = class Nursery extends App.Facilities.Facility {
 			{
 				property: "nurserySex",
 				prereqs: [
-					() => !!V.extremeUnderage,
+					!!V.extremeUnderage,
 				],
 				options: [
 					{
@@ -199,7 +199,7 @@ App.Facilities.Nursery.nursery = class Nursery extends App.Facilities.Facility {
 			{
 				property: "nurseryWeightSetting",
 				prereqs: [
-					() => !!V.nurseryWeight,
+					!!V.nurseryWeight,
 				],
 				options: [
 					{
@@ -217,7 +217,7 @@ App.Facilities.Nursery.nursery = class Nursery extends App.Facilities.Facility {
 			{
 				property: "nurseryMusclesSetting",
 				prereqs: [
-					() => !!V.nurseryMuscles,
+					!!V.nurseryMuscles,
 				],
 				options: [
 					{
@@ -235,7 +235,7 @@ App.Facilities.Nursery.nursery = class Nursery extends App.Facilities.Facility {
 			{
 				property: "nurseryHormonesSetting",
 				prereqs: [
-					() => !!V.nurseryHormones,
+					!!V.nurseryHormones,
 				],
 				options: [
 					{
diff --git a/src/facilities/pit/pit.js b/src/facilities/pit/pit.js
index a4efa0f2f0e0814a6ee1a6b540fd303facbfc9e3..1d0e0dcf2bc7528b061f1e20525622d3bfa5ffc3 100644
--- a/src/facilities/pit/pit.js
+++ b/src/facilities/pit/pit.js
@@ -172,7 +172,7 @@ App.Facilities.Pit.pit = class Pit extends App.Facilities.Facility {
 							link: `Bodyguard`,
 							value: 1,
 							prereqs: [
-								() => !!S.Bodyguard,
+								!!S.Bodyguard,
 							],
 						},
 						{
@@ -180,7 +180,7 @@ App.Facilities.Pit.pit = class Pit extends App.Facilities.Facility {
 							link: `Animal`,
 							value: 2,
 							prereqs: [
-								() => !!animal,
+								!!animal,
 							],
 							handler: () => {
 								if (!V.pit.animal) {
@@ -195,7 +195,7 @@ App.Facilities.Pit.pit = class Pit extends App.Facilities.Facility {
 							link: `Random`,
 							value: 3,
 							prereqs: [
-								() => !!S.Bodyguard || !!animal,
+								!!S.Bodyguard || !!animal,
 							],
 						},
 						{
@@ -218,8 +218,8 @@ App.Facilities.Pit.pit = class Pit extends App.Facilities.Facility {
 				{
 					property: "animal",
 					prereqs: [
-						() => V.pit.fighters === 2 || V.pit.fighters === 3,
-						() => !!animal,
+						V.pit.fighters === 2 || V.pit.fighters === 3,
+						!!animal,
 					],
 					options: [
 						{
@@ -227,8 +227,8 @@ App.Facilities.Pit.pit = class Pit extends App.Facilities.Facility {
 							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),
+								!!V.active.canine,
+								!["beagle", "French bulldog", "poodle", "Yorkshire terrier"].includes(V.active.canine),
 							],
 						},
 						{
@@ -236,7 +236,7 @@ App.Facilities.Pit.pit = class Pit extends App.Facilities.Facility {
 							get link() { return capFirstChar(V.active.hooved); },
 							value: V.active.hooved,
 							prereqs: [
-								() => !!V.active.hooved,
+								!!V.active.hooved,
 							],
 						},
 						{
@@ -244,8 +244,8 @@ App.Facilities.Pit.pit = class Pit extends App.Facilities.Facility {
 							get link() { return capFirstChar(V.active.feline); },
 							value: V.active.feline,
 							prereqs: [
-								() => !!V.active.feline,
-								() => getAnimal(V.active.feline).species !== "cat",
+								!!V.active.feline,
+								getAnimal(V.active.feline).species !== "cat",
 							],
 						},
 						{
@@ -253,7 +253,7 @@ App.Facilities.Pit.pit = class Pit extends App.Facilities.Facility {
 							link: `Random`,
 							value: 'random',
 							prereqs: [
-								() => (!!V.active.canine && !!V.active.hooved) ||
+								(!!V.active.canine && !!V.active.hooved) ||
 									(!!V.active.canine && !!V.active.feline) ||
 									(!!V.active.hooved && !!V.active.feline),
 							],
@@ -289,8 +289,8 @@ App.Facilities.Pit.pit = class Pit extends App.Facilities.Facility {
 				{
 					property: "virginities",
 					prereqs: [
-						() => V.pit.fighters !== 2,
-						() => !V.pit.lethal,
+						V.pit.fighters !== 2,
+						!V.pit.lethal,
 					],
 					options: [
 						{
diff --git a/src/facilities/schoolroom/schoolroom.js b/src/facilities/schoolroom/schoolroom.js
index f095f86ecb3e856846841feba6b2af4897745496..1c28db4fa9c2460ed6083bf75a603ff96ff5d1f5 100644
--- a/src/facilities/schoolroom/schoolroom.js
+++ b/src/facilities/schoolroom/schoolroom.js
@@ -144,7 +144,7 @@ App.Facilities.Schoolroom.schoolroom = class Schoolroom extends App.Facilities.F
 							App.UI.reload();
 						},
 						prereqs: [
-							() => V.arcologies[0].FSIntellectualDependency > 80,
+							V.arcologies[0].FSIntellectualDependency > 80,
 						],
 					},
 					{
@@ -172,14 +172,14 @@ App.Facilities.Schoolroom.schoolroom = class Schoolroom extends App.Facilities.F
 						cost: 5000 * V.upgradeMultiplierArcology * V.HackingSkillMultiplier,
 						notes: [`increases the effectiveness of ${V.schoolroomName}`],
 						prereqs: [
-							() => V.schoolroomRemodelBimbo > 0,
+							V.schoolroomRemodelBimbo > 0,
 						],
 					},
 					{
 						value: 1,
 						text: `${this.facility.nameCaps} has been upgraded with advanced teaching tools to help even the smartest slave learn at an acceptable pace. Dumb slaves won't learn much faster as a result, but smarties will benefit a great deal.`,
 						prereqs: [
-							() => V.schoolroomRemodelBimbo > 0,
+							V.schoolroomRemodelBimbo > 0,
 						],
 					},
 					{
@@ -191,14 +191,14 @@ App.Facilities.Schoolroom.schoolroom = class Schoolroom extends App.Facilities.F
 						handler: () => V.schoolroomRemodelBimbo = 0,
 						notes: [`increases the effectiveness of ${V.schoolroomName}`],
 						prereqs: [
-							() => V.schoolroomRemodelBimbo === 0,
+							V.schoolroomRemodelBimbo === 0,
 						],
 					},
 					{
 						value: 1,
 						text: `${this.facility.nameCaps} has been upgraded with advanced teaching tools to help even the stupidest slave learn at an acceptable pace. Intelligent slaves won't learn much faster as a result, but idiots will benefit a great deal.`,
 						prereqs: [
-							() => V.schoolroomRemodelBimbo === 0,
+							V.schoolroomRemodelBimbo === 0,
 						],
 					},
 				],
diff --git a/src/facilities/servantsQuarters/servantsQuarters.js b/src/facilities/servantsQuarters/servantsQuarters.js
index 2179d22eb5075ccc85de405d26df16291a12a08b..7e0ffc0837ff1ff43d104e00a5bc4d5a7b1c5092 100644
--- a/src/facilities/servantsQuarters/servantsQuarters.js
+++ b/src/facilities/servantsQuarters/servantsQuarters.js
@@ -119,9 +119,9 @@ App.Facilities.ServantsQuarters.servantsQuarters = class ServantsQuarters extend
 			{
 				property: "stewardessImpregnates",
 				prereqs: [
-					() => !!S.Stewardess,
-					() => !!canAchieveErection(S.Stewardess) && S.Stewardess.pubertyXY === 1,
-					() => !!V.seePreg,
+					!!S.Stewardess,
+					!!canAchieveErection(S.Stewardess) && S.Stewardess.pubertyXY === 1,
+					!!V.seePreg,
 				],
 				options: [
 					{
diff --git a/src/facilities/spa/spa.js b/src/facilities/spa/spa.js
index e44076a07eec71cb1edab06d85b18d05edbe5fa8..25f4d577abd6d405b08a315f84df17b5af1b7354 100644
--- a/src/facilities/spa/spa.js
+++ b/src/facilities/spa/spa.js
@@ -123,7 +123,7 @@ App.Facilities.Spa.spa = class Spa extends App.Facilities.Facility {
 			{
 				property: "spaFix",
 				prereqs: [
-					() => !!S.Attendant,
+					!!S.Attendant,
 				],
 				options: [
 					{
diff --git a/src/facilities/statistics.js b/src/facilities/statistics.js
index 68bb2ea1b83dbb8c9313a1d2347928d5b6508ca3..ebf343ebe360e2f7b80066a3225cab80cd94f783 100644
--- a/src/facilities/statistics.js
+++ b/src/facilities/statistics.js
@@ -7,11 +7,11 @@ App.Facilities.StatsHelper = class {
 		const table = document.createElement("table");
 		table.border = "1";
 		table.className = "facility-stats";
-		const header = App.UI.DOM.appendNewElement("tr", table, "", "header");
+		const header = App.UI.DOM.appendNewElement("tr", table, null, ["header"]);
 		App.UI.DOM.appendNewElement("th", header, "Items"); // first column, flexible width
-		App.UI.DOM.appendNewElement("th", header, columns[0], "wide"); // "revenue" column, wider
-		for (let i = 1; i < 4; ++i) {
-			App.UI.DOM.appendNewElement("th", header, columns[i], "narrow"); // three additional narrow columns
+		App.UI.DOM.appendNewElement("th", header, columns[0], ["wide"]); // "revenue" column, wider
+		for (let i = 1; i < columns.length; ++i) {
+			App.UI.DOM.appendNewElement("th", header, columns[i], ["narrow"]); // additional narrow columns
 		}
 		return table;
 	}
@@ -51,7 +51,7 @@ App.Facilities.StatsHelper = class {
 	}
 
 	/** Makes a value cell
-	 * @param {string} type - "reputation" or "cash"
+	 * @param {"reputation"|"cash"|"food"} type
 	 * @param {number} value - numeric value
 	 * @param {object} [flags]
 	 * @param {boolean} [flags.forceNeg] - treat nonzero positive values as negative
@@ -79,9 +79,13 @@ App.Facilities.StatsHelper = class {
 
 			// set contents
 			let prefix = '';
+			let suffix = '';
 			if (type === "cash") {
 				prefix += '¤';
 			}
+			if (type === "food") {
+				suffix += 'kg';
+			}
 			if (flags.showSign) {
 				if (flags.forceNeg) { // if the real value is negative, - sign will come from value.toFixed
 					prefix += '-';
@@ -91,10 +95,19 @@ App.Facilities.StatsHelper = class {
 					prefix += '±';
 				}
 			}
-			const fixedPrecision = type === "cash" ? 2 : 1;
+			let fixedPrecision = 1;
+			if (type === "cash") {
+				fixedPrecision = 2;
+			} else if (type === "food") {
+				fixedPrecision = 0;
+			}
 			const parts = value.toFixed(fixedPrecision).split('.');
-			cell.appendChild(document.createTextNode(prefix + parts[0]));
-			App.UI.DOM.appendNewElement("span", cell, '.' + parts[1], /^0+$/.test(parts[1]) ? "decimalZero" : undefined);
+			cell.appendChild(document.createTextNode(prefix + parts[0] + suffix));
+			if (fixedPrecision > 0) {
+				App.UI.DOM.appendNewElement("span", cell, '.' + parts[1], /^0+$/.test(parts[1]) ? ["decimalZero"] : undefined);
+			} else {
+				App.UI.DOM.appendNewElement("span", cell);
+			}
 		}
 
 		return cell;
@@ -149,7 +162,7 @@ App.Facilities.StatsHelper = class {
 	makeSlaveStatsTable(statsTable, caption, columns) {
 		const row = App.UI.DOM.appendNewElement("tr", statsTable);
 		const bigCell = document.createElement("td");
-		bigCell.colSpan = 5;
+		bigCell.colSpan = columns.length;
 		const label = App.UI.DOM.appendNewElement("span", bigCell, caption);
 		label.style.fontWeight = "bold";
 		row.appendChild(bigCell);
@@ -160,8 +173,8 @@ App.Facilities.StatsHelper = class {
 		App.UI.DOM.appendNewElement("th", header, columns[0]); // first column, flexible width
 		App.UI.DOM.appendNewElement("th", header, columns[1], "narrow"); // facility-specific output details
 		App.UI.DOM.appendNewElement("th", header, columns[2], "wide"); // "revenue" column, wider
-		for (let i = 3; i < 6; ++i) {
-			App.UI.DOM.appendNewElement("th", header, columns[i], "narrow"); // three additional narrow columns
+		for (let i = 3; i < columns.length; ++i) {
+			App.UI.DOM.appendNewElement("th", header, columns[i], "narrow"); // additional narrow columns
 		}
 		bigCell.appendChild(table);
 		statsTable.appendChild(bigCell);
@@ -505,7 +518,7 @@ App.Facilities.Dairy.Stats = (function() {
 
 App.Facilities.Farmyard.Stats = (function() {
 	const H = new App.Facilities.StatsHelper();
-	const assureList = [ "farmhandIncome", "farmhandCosts", "maintenance", "totalIncome", "totalExpenses", "food", "profit" ];
+	const assureList = [ "whoreIncome", "whoreCosts", "maintenance", "totalIncome", "totalExpenses", "food", "profit" ];
 
 	/** Generate the Farmyard statistics table
 	 * @param {boolean} showDetails
@@ -523,26 +536,36 @@ App.Facilities.Farmyard.Stats = (function() {
 			b[prop] = b[prop] || 0;
 		}
 
-		const stats = H.makeStatsTable(["Revenue", "Expenses", "Net Income", "Rep. Change"]);
+		const stats = H.makeStatsTable(["Revenue", "Expenses", "Food", "Net Income", "Rep. Change"]);
 		H.addValueRow(stats, "Total farmhand income", [
-			H.makeValueCell("cash", b.farmhandIncome),
+			H.makeValueCell("cash", b.whoreIncome),
 			H.makeEmptyCell(),
-			H.makeValueCell("cash", b.farmhandIncome),
+			H.makeEmptyCell(),
+			H.makeValueCell("cash", b.whoreIncome),
 			H.makeEmptyCell(),
 		]);
 		H.addValueRow(stats, "Total farmhand living costs", [
 			H.makeEmptyCell(),
-			H.makeValueCell("cash", b.farmhandCosts, {forceNeg: true}),
-			H.makeValueCell("cash", b.farmhandCosts, {forceNeg: true, showSign: true}),
+			H.makeValueCell("cash", b.whoreCosts, {forceNeg: true}),
+			H.makeEmptyCell(),
+			H.makeValueCell("cash", b.whoreCosts, {forceNeg: true, showSign: true}),
+			H.makeEmptyCell()
+		]);
+		H.addValueRow(stats, "Total food produced", [
+			H.makeEmptyCell(),
+			H.makeEmptyCell(),
+			H.makeValueCell("food", b.food),
+			H.makeValueCell("food", b.food),
 			H.makeEmptyCell()
 		]);
 		if (showDetails) {
-			const slaveStats = H.makeSlaveStatsTable(stats, "Farmhand details", ["Farmhand", "Revenue", "Expenses", "Net Income", "Rep. Change"]);
+			const slaveStats = H.makeSlaveStatsTable(stats, "Farmhand details", ["Farmhand", "Revenue", "Expenses", "Food", "Net Income", "Rep. Change"]);
 			for (const record of b.income.values()) {
 				const netIncome = record.income - record.cost;
 				H.addValueRow(slaveStats, H.makeSlaveLabel(record.slaveName, record.customLabel), [
 					H.makeValueCell("cash", record.income),
 					H.makeValueCell("cash", record.cost, {forceNeg: true}),
+					H.makeValueCell("food", record.food),
 					H.makeValueCell("cash", netIncome),
 					H.makeEmptyCell()
 				]);
@@ -551,12 +574,14 @@ App.Facilities.Farmyard.Stats = (function() {
 		H.addValueRow(stats, "Farmyard maintenance", [
 			H.makeEmptyCell(),
 			H.makeValueCell("cash", b.maintenance, {forceNeg: true}),
+			H.makeEmptyCell(),
 			H.makeValueCell("cash", b.maintenance, {forceNeg: true, showSign: true}),
 			H.makeEmptyCell()
 		]);
 		H.addValueRow(stats, "Total", [
 			H.makeValueCell("cash", b.totalIncome),
 			H.makeValueCell("cash", b.totalExpenses, {forceNeg: true}),
+			H.makeValueCell("food", b.food),
 			H.makeValueCell("cash", b.profit, {bold: true}),
 			H.makeEmptyCell()
 		], true);
diff --git a/src/facilities/surgery/analyzePlayerPregnancy.js b/src/facilities/surgery/analyzePlayerPregnancy.js
index 4812d2792430edecbf3f2fe186ca9312fd63ff32..e312f923c4dc450f9df9c33a8927deec93746810 100644
--- a/src/facilities/surgery/analyzePlayerPregnancy.js
+++ b/src/facilities/surgery/analyzePlayerPregnancy.js
@@ -73,7 +73,7 @@ App.UI.analyzePCPregnancy = function() {
 				}
 				if (nurseryReservations < WL && (reservedChildrenNursery + WL - nurseryReservations <= freeCribs)) {
 					linkArray.push(App.UI.DOM.link(
-						`Keep all of your children in ${V.incubator.name}`,
+						`Keep all of your children in ${V.nurseryName}`,
 						() => {
 							WombChangeReserveType(V.PC, "incubator", "nursery");
 							WombChangeReserveType(V.PC, "", "nursery");
diff --git a/src/facilities/surgery/analyzePregnancy.js b/src/facilities/surgery/analyzePregnancy.js
index 26d217cb4ece8dc01152b916166802db56c90713..285359e7840179d9c2228224945c5db7d00a82e5 100644
--- a/src/facilities/surgery/analyzePregnancy.js
+++ b/src/facilities/surgery/analyzePregnancy.js
@@ -326,7 +326,7 @@ App.UI.analyzePregnancy = function() {
 				}
 				if (nurseryReservations < WL && (FetusGlobalReserveCount("nursery") + WL - nurseryReservations <= freeCribs)) {
 					linkArray.push(App.UI.DOM.link(
-						`Keep all of ${his} children in ${V.incubator.name}`,
+						`Keep all of ${his} children in ${V.nurseryName}`,
 						() => {
 							WombChangeReserveType(slave, "incubator", "nursery");
 							WombChangeReserveType(slave, "", "nursery");
diff --git a/src/gui/options/options.js b/src/gui/options/options.js
index 92142329e6d5ab0c78ee6e41a003010630285fc1..bf76a673f17cacc1f439b12685dbc288625701db 100644
--- a/src/gui/options/options.js
+++ b/src/gui/options/options.js
@@ -158,7 +158,7 @@ App.UI.optionsPassage = function() {
 			.addComment("<div>This mod is triggered after week 72. It is non-canon where it conflicts with canonical updates to the base game.</div>");
 
 		options.addOption("The Security Expansion mod is", "secExpEnabled")
-			.addValue("Enabled", 1).on().addCallback(() => App.Mods.SecExp.generalInit())
+			.addValue("Enabled", 1).on().addCallback(() => App.Mods.SecExp.object("in-game"))
 			.addValue("Disabled", 0).off()
 			.addComment("<div>The mod can be activated in any moment, but it may result in unbalanced gameplay if activated very late in the game.</div>");
 
@@ -1214,6 +1214,8 @@ App.UI.artOptions = function() {
 				options.addOption("Idle Animations", "seeAnimation")
 					.addValue("Enabled", true).on().addValue("Disabled", false).off()
 					.addComment("Experimental idle animations, only visible in slave inspect screen. Will cause slowdown on some systems.");
+				options.addOption("Animation FPS", "animFPS")
+					.addValue("6", 6).off().addValue("12", 12).on().addValue("24", 24).off().addValue("32", 32).off();
 			} else if (V.imageChoice === 2) {
 				option.addComment("This art development is dead since vanilla. Since it is not embedded, requires a separate art pack to be downloaded.");
 			}
diff --git a/src/js/DefaultRules.js b/src/js/DefaultRules.js
index 6f9d03512a02cd1c0a095ea400605db0ab10584d..73c08b7a4727cfe8974467c90f3ad4387bf408a7 100644
--- a/src/js/DefaultRules.js
+++ b/src/js/DefaultRules.js
@@ -1610,17 +1610,17 @@ globalThis.DefaultRules = (function() {
 				if (((slave.weight > 95) || ((slave.weight > 30) && (slave.hips < 2)))) {
 					if (slave.diet !== "restricted") {
 						slave.diet = "restricted";
-						r += `<br>${slave.slaveName} is too fat so ${his} diet has been set to restricted.`;
+						r += `<br>${slave.slaveName} is unreasonably fat so ${his} diet has been set to restricted.`;
 						dietPills(slave);
 					}
 				} else if (((slave.weight < -95) || ((slave.weight < -30) && (slave.hips > -2)))) {
 					if (slave.diet !== "fattening") {
 						slave.diet = "fattening";
-						r += `<br>${slave.slaveName} is too skinny so ${his} diet has been set to fattening.`;
+						r += `<br>${slave.slaveName} is unreasonably skinny so ${his} diet has been set to fattening.`;
 						dietPills(slave);
 					}
 				} else if (["restricted", "fattening"].includes(slave.diet)) {
-					r += `<br>${slave.slaveName} is at the target weight, so ${his} diet has been normalized.`;
+					r += `<br>${slave.slaveName} is at an acceptable weight, so ${his} diet has been normalized.`;
 					slave.diet = "healthy";
 					dietPills(slave);
 					muscleRule(slave, rule);
diff --git a/src/js/SlaveState.js b/src/js/SlaveState.js
index 75095eb87f0af5da6859cd4a825ee9f882ea2805..497f5b99ea8e80adfc2eb7df0b3e48584370ab6d 100644
--- a/src/js/SlaveState.js
+++ b/src/js/SlaveState.js
@@ -512,6 +512,7 @@ App.Entity.LimbState = class LimbState {
 		 * * 4: advanced - Beauty
 		 * * 5: advanced - Combat
 		 * * 6: cybernetic
+		 * @type {FC.LimbType}
 		 */
 		this.type = 1;
 		/**
diff --git a/src/js/rulesAssistant.js b/src/js/rulesAssistant.js
index 66be45512f37b12852935668bed9da7d7b17b256..c247619be5f65642ac3fad48be8fef87ac24ab7f 100644
--- a/src/js/rulesAssistant.js
+++ b/src/js/rulesAssistant.js
@@ -178,6 +178,7 @@ App.RA.newRule = function() {
 	function emptyConditions() {
 		return {
 			activation: ["devotion", 20, "gt", 1, "and"],
+			advancedMode: false,
 			selectedSlaves: [],
 			excludedSlaves: [],
 			applyRuleOnce: false,
diff --git a/src/js/rulesAssistantOptions.js b/src/js/rulesAssistantOptions.js
index d47e17530bd85da037165d1c16ba5bef4abd7997..ebc47642f3788a91202122c1cd5244b7f69d6fca 100644
--- a/src/js/rulesAssistantOptions.js
+++ b/src/js/rulesAssistantOptions.js
@@ -105,7 +105,7 @@ App.RA.options = (function() {
 	 * Save the settings for this rule.
 	 */
 	function saveSettings() {
-		App.RA.Activation.Editor.save(cond => current_rule.condition.activation = cond);
+		App.RA.Activation.Editor.save(current_rule.condition);
 	}
 
 	const parse = {
@@ -1294,7 +1294,7 @@ App.RA.options = (function() {
 
 	class ConditionBuilder extends Element {
 		render() {
-			return App.RA.Activation.Editor.build(current_rule.condition.activation);
+			return App.RA.Activation.Editor.build(current_rule.condition);
 		}
 	}
 
diff --git a/src/js/upgrade.js b/src/js/upgrade.js
index 6c7300124909cc8fe83672bb5be740f09550d4e5..49ee68f797e1502d27ad914608b2bcf698909c28 100644
--- a/src/js/upgrade.js
+++ b/src/js/upgrade.js
@@ -33,7 +33,7 @@ App.Upgrade = class Upgrade {
 
 			const cost = Math.trunc(tier.cost) || 0;
 
-			if ((!prereqs || prereqs.every(prereq => prereq())) &&
+			if ((!prereqs || prereqs.every(prereq => prereq === true)) &&
 				_.isEqual(value, this._object[this._property])) {
 				App.UI.DOM.appendNewElement("div", frag, text);
 
diff --git a/src/js/utilsMisc.js b/src/js/utilsMisc.js
index 82b8a3075f1e44519cb67512ce957e48157e3306..8c79503c4fdef3b243af0aa798b83e332a76f11e 100644
--- a/src/js/utilsMisc.js
+++ b/src/js/utilsMisc.js
@@ -251,6 +251,10 @@ App.Utils.totalNetWorth = function() {
 	total += App.Mods.SF.totalNetWorth();
 	total -= App.Mods.SecExp.upkeep.cost();
 
+	if (V.loans.length > 0) {
+		V.loans.forEach(loan => total -= loan.full);
+	}
+
 	return total;
 };
 
diff --git a/src/js/utilsSlave.js b/src/js/utilsSlave.js
index d2e67f3e48a2017769a2b3e9d9924ff3f4e14091..de1afbdbb99e32a7dc88604af1429d2851132bb8 100644
--- a/src/js/utilsSlave.js
+++ b/src/js/utilsSlave.js
@@ -2177,84 +2177,88 @@ globalThis.SlaveTitle = function(slave, adjective = true, variability = true) {
 	let r;
 	if (V.newDescriptions === 1) {
 		if (slave.dick > 0 && slave.balls > 0 && slave.boobs > 300 && slave.vagina > -1 && slave.ovaries === 1) {
-			if (variability && jsRandom(1, 100) > 50) {
-				r = "futanari";
+			if (variability && random(1, 100) > 50) {
+				r = `futanari`;
 			} else {
-				r = "herm";
+				r = `herm`;
 			}
 		} else if (slave.dick > 0 && slave.balls === 0 && slave.boobs > 300 && slave.vagina > -1 && slave.ovaries === 1) {
-			r = "dickgirl";
+			r = `dickgirl`;
 		} else if (slave.dick > 0 && slave.vagina > -1 && slave.ovaries === 0) {
-			r = "shemale";
+			r = `shemale`;
 		} else if (slave.dick > 0 && slave.balls === 0 && slave.vagina === -1 && slave.ovaries === 0) {
-			r = "eunuch";
+			r = `eunuch`;
 		} else if (slave.dick > 0 && slave.balls > 0 && slave.vagina === -1 && slave.ovaries === 0) {
 			if (slave.race === "catgirl") {
-				r = "catboy";
+				r = `catboy`;
 			} else if (slave.face > 10 && slave.hips > -1 && slave.shoulders < 1 && slave.faceShape !== "masculine") {
-				r = "trap";
+				r = `trap`;
 			} else if (slave.boobs > 800) {
-				r = "tittyboy";
+				r = `tittyboy`;
 			} else if (slave.dick === 1 && slave.balls === 1) {
-				r = "sissy";
+				r = `sissy`;
 			} else if (slave.dick > 1 && slave.balls > 1 && slave.height < 165 && slave.muscles < 5 && slave.visualAge < 19 && slave.faceShape !== "masculine") {
-				r = "twink";
+				r = `twink`;
 			} else if (slave.dick > 1 && slave.balls > 1 && slave.height < 160 && slave.muscles < 5 && slave.visualAge < 19) {
-				r = "boytoy";
+				r = `boytoy`;
 			} else if (slave.muscles > 95 && slave.height >= 185) {
-				r = "titan";
+				r = `titan`;
 			} else if (slave.muscles > 30) {
-				r = "muscleboy";
+				r = `muscleboy`;
 			} else {
-				r = "slaveboy";
+				r = `slaveboy`;
 			}
 		} else if (slave.dick === 0 && slave.balls === 0 && slave.vagina > -1) {
 			if (slave.race === "catgirl") {
-				r = "catgirl";
+				r = `catgirl`;
 			} else if ((slave.shoulders > slave.hips || slave.faceShape === "masculine") && slave.boobs < 400 && slave.genes === "XY") {
-				r = "cuntboy";
+				r = `cuntboy`;
 			} else if (slave.ovaries === 0 && slave.genes === "XY") {
-				r = "tranny";
+				r = `tranny`;
 			} else if (slave.weight > 10 && slave.boobs > 800 && slave.counter.birthsTotal > 0 && slave.physicalAge > 59) {
-				r = "GMILF";
+				r = `GMILF`;
 			} else if (slave.weight > 10 && slave.boobs > 800 && slave.counter.birthsTotal > 0 && slave.physicalAge > 35) {
-				r = "MILF";
+				r = `MILF`;
 			} else if (slave.lips > 70 && slave.boobs > 2000 && slave.butt > 3) {
-				r = "bimbo";
+				r = `bimbo`;
 			} else if (slave.hips > 1 && slave.boobs > 2000 && slave.butt > 3 && slave.waist < 50) {
-				r = "hourglass";
+				r = `hourglass`;
 			} else if (slave.muscles > 95 && slave.height >= 185) {
-				r = "amazon";
+				r = `amazon`;
 			} else if (slave.muscles > 30) {
-				r = "musclegirl";
+				r = `musclegirl`;
 			} else {
-				r = "slavegirl";
+				r = `slavegirl`;
 			}
 		} else if (slave.dick === 0 && slave.balls === 0 && slave.vagina === -1) {
-			r = "neuter";
+			r = `neuter`;
 		} else if (slave.dick === 0 && slave.vagina === -1) {
-			r = "ballslave";
+			r = `ballslave`;
 		} else {
-			r = "slave";
+			r = `slave`;
 		}
 
 		if (!adjective) {
 			return r;
 		}
 
-		if (slave.visualAge < 13) {
-			if (slave.actualAge < 3) {
-				if (slave.actualAge < 1) {
-					r = "baby " + r;
+		if (slave.visualAge < 18) {
+			if (slave.visualAge < 13) {
+				if (slave.actualAge < 3) {
+					if (slave.actualAge < 1) {
+						r = `baby ${r}`;
+					} else {
+						r = `toddler ${r}`;
+					}
 				} else {
-					r = "toddler " + r;
+					if (slave.genes === "XY" && slave.vagina === -1) {
+						r = `shota ${r}`;
+					} else {
+						r = `loli ${r}`;
+					}
 				}
 			} else {
-				if (slave.genes === "XY" && slave.vagina === -1) {
-					r = "shota " + r;
-				} else {
-					r = "loli " + r;
-				}
+				r = `teen ${r}`;
 			}
 		}
 
@@ -2328,10 +2332,10 @@ globalThis.SlaveTitle = function(slave, adjective = true, variability = true) {
 			r = `${r} fuckdoll`;
 		}
 	} else {
-		r = "slave"; /* I don't think there is an 'else'? */
+		r = `slave`;
 		if ((slave.dick === 0) && (slave.vagina === -1)) {
-			/* NULLS */
-			r = "null";
+			// NULLS
+			r = `null`;
 			if ((slave.lactation > 0) && (slave.boobs > 2000)) {
 				r = `${r} cow`;
 			} else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) {
@@ -2355,15 +2359,15 @@ globalThis.SlaveTitle = function(slave, adjective = true, variability = true) {
 		}
 
 		if ((slave.dick === 0) && (slave.vagina !== -1)) {
-			/* FEMALES */
+			// FEMALES
 			if (slave.visualAge > 55) {
-				r = "GILF";
+				r = `GILF`;
 			} else if (slave.visualAge > 35) {
-				r = "MILF";
+				r = `MILF`;
 			} else if (slave.visualAge >= 25) {
-				r = "slave";
+				r = `slave`;
 			} else {
-				r = "slavegirl";
+				r = `slavegirl`;
 			}
 			if ((slave.muscles > 30) && (slave.height < 185)) {
 				r = `muscle ${r}`;
@@ -2380,11 +2384,11 @@ globalThis.SlaveTitle = function(slave, adjective = true, variability = true) {
 
 		if ((slave.dick !== 0) && (slave.vagina !== -1)) {
 			if (slave.balls > 0) {
-				/* FUTANARI: cock & balls & vagina */
-				r = "futanari ";
+				// FUTANARI: cock & balls & vagina
+				r = `futanari `;
 			} else {
-				/* FUTANARI: cock & vagina */
-				r = "futa ";
+				// FUTANARI: cock & vagina
+				r = `futa `;
 			}
 			if ((slave.lactation > 0) && (slave.boobs > 2000)) {
 				r = `${r}cow`;
@@ -2412,15 +2416,15 @@ globalThis.SlaveTitle = function(slave, adjective = true, variability = true) {
 		}
 
 		if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls > 0) && (slave.boobs > 300) && (slave.butt > 2)) {
-			/* SHEMALES: cock & balls, T&A above minimum */
+			// SHEMALES: cock & balls, T&A above minimum
 			if (slave.visualAge > 55) {
-				r = "sheGILF";
+				r = `sheGILF`;
 			} else if (slave.visualAge > 35) {
-				r = "sheMILF";
+				r = `sheMILF`;
 			} else if (slave.visualAge >= 25) {
-				r = "shemale";
+				r = `shemale`;
 			} else {
-				r = "tgirl";
+				r = `tgirl`;
 			}
 			if ((slave.muscles > 30) && (slave.height < 185)) {
 				r = `muscle${r}`;
@@ -2439,24 +2443,24 @@ globalThis.SlaveTitle = function(slave, adjective = true, variability = true) {
 			if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls > 0)) {
 				if ((slave.shoulders < 1) || (slave.muscles <= 30)) {
 					if ((slave.faceShape === "masculine") || (slave.faceShape === "androgynous")) {
-						/* SISSIES: feminine shoulders or muscles, masculine faces */
+						// SISSIES: feminine shoulders or muscles, masculine faces
 						if (slave.visualAge > 55) {
-							r = "sissyGILF";
+							r = `sissyGILF`;
 						} else if (slave.visualAge > 35) {
-							r = "sissyMILF";
+							r = `sissyMILF`;
 						} else {
-							r = "sissy";
+							r = `sissy`;
 						}
 					} else {
-						/* TRAPS: feminine shoulders or muscles, feminine faces */
+						// TRAPS: feminine shoulders or muscles, feminine faces
 						if (slave.visualAge > 55) {
-							r = "trapGILF";
+							r = `trapGILF`;
 						} else if (slave.visualAge > 35) {
-							r = "trapMILF";
+							r = `trapMILF`;
 						} else if (slave.visualAge >= 25) {
-							r = "trap";
+							r = `trap`;
 						} else {
-							r = "trapgirl";
+							r = `trapgirl`;
 						}
 					}
 					if (slave.lactation > 0) {
@@ -2471,8 +2475,8 @@ globalThis.SlaveTitle = function(slave, adjective = true, variability = true) {
 		if ((slave.boobs < 300) || (slave.butt < 2)) {
 			if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls > 0)) {
 				if ((slave.shoulders > 1) || (slave.muscles >= 30)) {
-					/* BITCHES: masculine shoulders or muscles */
-					r = "bitch";
+					// BITCHES: masculine shoulders or muscles
+					r = `bitch`;
 					if ((slave.muscles > 30) && (slave.height < 185)) {
 						r = `muscle${r}`;
 					} else if (slave.lactation > 0) {
@@ -2492,7 +2496,7 @@ globalThis.SlaveTitle = function(slave, adjective = true, variability = true) {
 		}
 
 		if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls === 0)) {
-			r = "dick";
+			r = `dick`;
 			if (slave.visualAge > 55) {
 				r = `${r}GILF`;
 			} else if (slave.visualAge > 35) {
@@ -2834,19 +2838,19 @@ globalThis.DegradingName = function(slave) {
 		} else {
 			if (slave.balls > 0) {
 				if (slave.boobs > 300 && slave.butt > 2) {
-					/* SHEMALES: cock & balls, T&A above minimum */
+					// SHEMALES: cock & balls, T&A above minimum
 					suffixes.push("Shemale");
 				} else {
 					if (slave.shoulders < 1 && slave.muscles <= 30) {
 						if (slave.faceShape === "masculine" || slave.faceShape === "androgynous") {
-							/* SISSIES: feminine shoulders or muscles, masculine faces */
+							// SISSIES: feminine shoulders or muscles, masculine faces
 							suffixes.push("Sissy");
 						} else {
-							/* TRAPS: feminine shoulders or muscles, feminine faces */
+							// TRAPS: feminine shoulders or muscles, feminine faces
 							suffixes.push("Trap");
 						}
 					} else {
-						/* BITCHES: masculine shoulders or muscles */
+						// BITCHES: masculine shoulders or muscles
 						suffixes.push("Bitch");
 					}
 				}
diff --git a/src/npc/descriptions/belly/belly.js b/src/npc/descriptions/belly/belly.js
index 0c6256017e7f85188d1f5d29803a783be02303c7..1eb9161eb2f91200429c4ee21bc32fdd1e5ddca5 100644
--- a/src/npc/descriptions/belly/belly.js
+++ b/src/npc/descriptions/belly/belly.js
@@ -7742,21 +7742,21 @@ App.Desc.belly = function(slave, descType = DescType.NORMAL) {
 						if (slave.bellyAccessory === "a huge empathy belly") {
 							r.push(`${slave.slaveName}'s monokini shows off the curvature of ${his} big pregnant belly. The swimsuit has been pushed down to just above ${his} popped navel.`);
 						} else if (isBellyFluidLargest) {
-							r.push(`${slave.slaveName}'s monokini overs less than half of ${his} jiggling ${slave.inflationType}-filled belly.`);
+							r.push(`${slave.slaveName}'s monokini covers less than half of ${his} jiggling ${slave.inflationType}-filled belly.`);
 						} else if (slave.bellyImplant > 0) {
-							r.push(`${slave.slaveName}'s monokini overs less than half of ${his} implant-filled belly.`);
+							r.push(`${slave.slaveName}'s monokini covers less than half of ${his} implant-filled belly.`);
 						} else {
 							r.push(`${slave.slaveName}'s monokini shows off every kick and movement within ${his} big pregnant belly. The swimsuit has been pushed down to just above ${his} popped navel.`);
 						}
 					} else if (slave.belly >= 10000 || (slave.bellyAccessory === "a large empathy belly")) {
 						if (slave.bellyAccessory === "a large empathy belly") {
-							r.push(`${slave.slaveName}'s monokini overs only half of ${his} pregnant belly.`);
+							r.push(`${slave.slaveName}'s monokini covers only half of ${his} pregnant belly.`);
 						} else if (isBellyFluidLargest) {
-							r.push(`${slave.slaveName}'s monokini overs only half of ${his} jiggling ${slave.inflationType}-filled belly.`);
+							r.push(`${slave.slaveName}'s monokini covers only half of ${his} jiggling ${slave.inflationType}-filled belly.`);
 						} else if (slave.bellyImplant > 0) {
-							r.push(`${slave.slaveName}'s monokini overs only half of ${his} implant-filled belly.`);
+							r.push(`${slave.slaveName}'s monokini covers only half of ${his} implant-filled belly.`);
 						} else {
-							r.push(`${slave.slaveName}'s monokini overs only half of ${his} pregnant belly.`);
+							r.push(`${slave.slaveName}'s monokini covers only half of ${his} pregnant belly.`);
 						}
 					} else if (slave.weight > 160) {
 						r.push(`${slave.slaveName}'s monokini tightly clings to ${his} hugely fat belly, clearly displaying every fold, roll and motion in its mass.`);
diff --git a/src/npc/descriptions/descriptionWidgets.js b/src/npc/descriptions/descriptionWidgets.js
index d2948e0bb7395ea70b8ebcef092ebc8f368d8652..46732c9459f6e39a3bb112e645ced181ced4ec1f 100644
--- a/src/npc/descriptions/descriptionWidgets.js
+++ b/src/npc/descriptions/descriptionWidgets.js
@@ -1111,6 +1111,14 @@ App.Desc.shortLimbs = function(slave) {
 				return limb + "Combat P-Limb ";
 			case 6:
 				return limb + "Cyber P-Limb ";
+			case 7:
+				return limb + "Quad-Feline ";
+			case 8:
+				return limb + "Quad-Canine ";
+			case 9:
+				return limb + "Combat Feline ";
+			case 10:
+				return limb + "Combat Canine ";
 			default:
 				return "unknown ID: " + id;
 		}
@@ -1240,6 +1248,18 @@ App.Desc.longLimbs = function(slave) {
 				case 6:
 					r += "cyber ";
 					break;
+				case 7:
+					r +=  "quadruped feline ";
+					break;
+				case 8:
+					r +=  "quadruped canine ";
+					break;
+				case 9:
+					r +=  "feline combat ";
+					break;
+				case 10:
+					r +=  "canine combat ";
+					break;
 			}
 			if (count > 1) {
 				r += "prosthetic limbs. ";
diff --git a/src/npc/descriptions/ears.js b/src/npc/descriptions/ears.js
index 48bfeb01cfcf6ecb4b550ab4d046ffb5a27797ed..29f4fadf1fae867e10a02ea35450c4795c54eb40 100644
--- a/src/npc/descriptions/ears.js
+++ b/src/npc/descriptions/ears.js
@@ -71,7 +71,7 @@ App.Desc.ears = function(slave) {
 		}
 		r.push(`${either(`tend to droop when ${he} is relaxed or sad`, `twitch at the slightest touch`)}.`);
 	} else if (slave.earT === "leopard") {
-		r.push(`On top of ${his} head ${he} has a pair of cute leopard ears. the ears are`);
+		r.push(`On top of ${his} head ${he} has a pair of cute leopard ears. The ears are`);
 		if (slave.earTColor === "hairless") {
 			r.push(`hairless.`);
 		} else {
diff --git a/src/npc/interaction/fFeelings.js b/src/npc/interaction/fFeelings.js
index d7934e5ce6015e92be758340fd0609e24e878c88..11e922b93b07f2039e45cce75a6b6d03b6e23cbd 100644
--- a/src/npc/interaction/fFeelings.js
+++ b/src/npc/interaction/fFeelings.js
@@ -410,7 +410,7 @@ App.Interact.fFeelings = function(slave) {
 						}
 						text.push(`cum in my belly. Oh! I like my belly, too, and that warm, sloshy feeling as it's packed full of baby juice. It's so — I'm sorry, ${Master}. I think my mouth is watering. Please give me a moment to collect myself.`);
 					} else if (V.PC.dick !== 0) {
-						text.push(`is my tummy${(slave.vagina > -1) ? ` — and my womb` : ``}! The sloshy feeling when I'm all packed full of cum in both ends gets me so incredibly horny. sometimes I wonder what it would be like if I were just a puffed up cum-balloon of a ${woman}, helpless and filled with cum, over, and over, and — I'm sorry, ${Master}. I'm being weird again, aren't I?`);
+						text.push(`is my tummy${(slave.vagina > -1) ? ` — and my womb` : ``}! The sloshy feeling when I'm all packed full of cum in both ends gets me so incredibly horny. Sometimes I wonder what it would be like if I were just a puffed up cum-balloon of a ${woman}, helpless and filled with cum, over, and over, and — I'm sorry, ${Master}. I'm being weird again, aren't I?`);
 					} else {
 						text.push(`is my mouth, I love how it feels to — to eat pussy, ${Master}. I love eating out your pussy. Especially when it's been filled up with some`);
 						if (canTaste(slave)) {
@@ -1916,13 +1916,13 @@ App.Interact.fFeelings = function(slave) {
 						if (sex > 0 && beauty > 0 && combat > 0) {
 							text.push(`${Spoken(slave, `${His2} P-Limbs do look cool and I like how strong they can make ${him2} but they scare me a little, sometimes. Though of course ${he2} disables the weapons when we're together."`)} ${He} giggles. ${Spoken(slave, `"${He2} has vibe fingers, so that's awesome.`)}`);
 						} else if (sex > 0 && beauty > 0) {
-							text.push(`${Spoken(slave, `I really like ${his2} P-Limbs. They're very pretty, but kind of cold. That's just how ${he2} is."`)} ${He} giggles. ${Spoken(slave, `" ${He2} has vibe fingers. so that's awesome.`)}`);
+							text.push(`${Spoken(slave, `I really like ${his2} P-Limbs. They're very pretty, but kind of cold. That's just how ${he2} is."`)} ${He} giggles. ${Spoken(slave, `" ${He2} has vibe fingers. So that's awesome.`)}`);
 						} else if (beauty > 0 && combat > 0) {
 							text.push(`${Spoken(slave, `${His2} P-Limbs do look cool and I like how strong they can make ${him2} but they scare me a little, sometimes. Though of course ${he2} disables the weapons when we're together.`)}`);
 						} else if (sex > 0 && combat > 0) {
-							text.push(`${Spoken(slave, `${His2} P-Limbs do scare me a little, sometimes. Though of course ${he2} disables the weapons when we're together."`)} ${He} giggles. ${Spoken(slave, `"${He2} has vibe fingers. so that's awesome.`)}`);
+							text.push(`${Spoken(slave, `${His2} P-Limbs do scare me a little, sometimes. Though of course ${he2} disables the weapons when we're together."`)} ${He} giggles. ${Spoken(slave, `"${He2} has vibe fingers. So that's awesome.`)}`);
 						} else if (sex > 0) {
-							text.push(`${Spoken(slave, `And, um."`)} ${He} giggles. ${Spoken(slave, `"${He2} has vibe fingers. so that's awesome.`)}`);
+							text.push(`${Spoken(slave, `And, um."`)} ${He} giggles. ${Spoken(slave, `"${He2} has vibe fingers. So that's awesome.`)}`);
 						} else if (beauty > 0) {
 							text.push(`${Spoken(slave, `I really like ${his2} P-Limbs. They're very pretty, but kind of cold. That's just how ${he2} is.`)}`);
 						} else if (combat > 0) {
@@ -2022,7 +2022,7 @@ App.Interact.fFeelings = function(slave) {
 					} else if (slave.devotion > 20) {
 						text.push(`${Spoken(slave, `I'm proud to be a slave of the new Pharaoh.`)}`);
 					} else {
-						text.push(`${Spoken(slave, `Being a slave in this new Egypt is a little reassuring. some of the other slavs say they used to use slaves for great things, anyway.`)}`);
+						text.push(`${Spoken(slave, `Being a slave in this new Egypt is a little reassuring. Some of the other slaves say they used to use slaves for great things, anyway.`)}`);
 					}
 				}
 				if (V.arcologies[0].FSChattelReligionist >= 10) {
diff --git a/src/npc/interaction/fillUpButt.js b/src/npc/interaction/fillUpButt.js
index f1d6526c219dec31aac8b6962ef1284e0d1ca0ca..a1d8223fc6d6461b57978732475fc350bcbdc473 100644
--- a/src/npc/interaction/fillUpButt.js
+++ b/src/npc/interaction/fillUpButt.js
@@ -12,7 +12,9 @@ App.Interact.fillUpButt = function(slave) {
 		he, his, him, himself
 	} = getPronouns(slave);
 
-	slave.bellyAccessory = "none";
+	if (slave.bellyAccessory !== "a support band") {
+		slave.bellyAccessory = "none";
+	}
 	let pregDiscovery = 0;
 	r.push(`You`);
 	switch (slave.inflationType) {
diff --git a/src/npc/interaction/fillUpFace.js b/src/npc/interaction/fillUpFace.js
index 00da0eff4ae151a8155551a214501ed11ba21346..33492ece2a35fd0a5bad69299309e87385bfc472 100644
--- a/src/npc/interaction/fillUpFace.js
+++ b/src/npc/interaction/fillUpFace.js
@@ -12,7 +12,9 @@ App.Interact.fillUpFace = function(slave) {
 		he, his, him, himself
 	} = getPronouns(slave);
 
-	slave.bellyAccessory = "none";
+	if (slave.bellyAccessory !== "a support band") {
+		slave.bellyAccessory = "none";
+	}
 	let pregDiscovery = 0;
 	const belly = bellyAdjective(slave);
 	r.push(`You attach a hose to ${V.dairyName} tap with the pipes set to pump ${slave.inflationType} and affix a special nozzle to it, one with straps useful for anchoring it to resisting slaves, before calling ${him} over so you can feel ${him} up while you force-feed ${him} ${slave.inflationType}.`);
diff --git a/src/npc/interaction/forceFeeding.js b/src/npc/interaction/forceFeeding.js
index c4826660980e499975b6809245e43fe61ed508d3..8baef5ca826052d8337ce2404bae232d5be9fa21 100644
--- a/src/npc/interaction/forceFeeding.js
+++ b/src/npc/interaction/forceFeeding.js
@@ -15,7 +15,9 @@ App.Interact.forceFeeding = function(slave) {
 	let doMe;
 
 	const belly = bellyAdjective(slave);
-	slave.bellyAccessory = "none";
+	if (slave.bellyAccessory !== "a support band") {
+		slave.bellyAccessory = "none";
+	}
 	let isDone = slave.inflation-1;
 	let pregDiscovery = 0;
 	r.push(`You call ${him} over and ask ${him} to wait patiently for a moment.`);
diff --git a/src/npc/interaction/passage/fAnimalImpreg.js b/src/npc/interaction/passage/fAnimalImpreg.js
index 3f2b9909410424d344d0b29f137f8bf03e5386ca..b798cd61ef1973eb369af16d3880ec2c9feb54df 100644
--- a/src/npc/interaction/passage/fAnimalImpreg.js
+++ b/src/npc/interaction/passage/fAnimalImpreg.js
@@ -13,34 +13,34 @@ App.Interact.fAnimalImpreg = function(slave) {
 
 	/* FIXME: this might not work */
 	for (const canine of V.animals.canine) {
-		if (canBreed(slave, canine)) {
+		if (canBreed(slave, getAnimal(canine))) {
 			App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
-				`Have a ${canine.species !== "dog" ? canine.species : canine.breed} knock ${him} up`,
+				`Have a ${getAnimal(canine).species !== "dog" ? getAnimal(canine).species : getAnimal(canine).name} knock ${him} up`,
 				() => jQuery(node).empty().append(content(canine))
 			));
 			eligibility = true;
 		}
 	}
 	for (const hooved of V.animals.hooved) {
-		if (canBreed(slave, hooved)) {
+		if (canBreed(slave, getAnimal(hooved))) {
 			App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
-				`Have a ${hooved.species} knock ${him} up`,
+				`Have a ${getAnimal(hooved).species} knock ${him} up`,
 				() => jQuery(node).empty().append(content(hooved))
 			));
 			eligibility = true;
 		}
 	}
 	for (const feline of V.animals.feline) {
-		if (canBreed(slave, feline)) {
+		if (canBreed(slave, getAnimal(feline))) {
 			App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link(
-				`Have a ${feline.species !== "cat" ? feline.species : feline.breed} knock ${him} up`,
+				`Have a ${getAnimal(feline).species !== "cat" ? getAnimal(feline).species : getAnimal(feline).name} knock ${him} up`,
 				() => jQuery(node).empty().append(content(feline))
 			));
 			eligibility = true;
 		}
 	}
 	if (!eligibility) {
-		App.UI.DOM.appendNewElement("div", node, `You have no animals capable of inseminating ${him}`, `note`);
+		App.UI.DOM.appendNewElement("div", node, `You have no animals capable of inseminating ${him}`, ['note']);
 	}
 	App.Events.addParagraph(node, r);
 	return node;
@@ -48,16 +48,16 @@ App.Interact.fAnimalImpreg = function(slave) {
 	function content(animal) {
 		const el = new DocumentFragment();
 		r.push(`You have a servant lead the`);
-		if (animal.species !== "dog" || animal.species !== "cat") {
+		if (animal.species !== "dog" && animal.species !== "cat") {
 			r.push(animal.species);
 		} else {
-			r.push(animal.breed);
+			r.push(animal.name);
 		}
 		r.push(`in on a leash and feed him a special treat, one laced with high amounts of aphrodisiacs and vasodilators. They have an effect very rapidly, and the`);
 		if (animal.species !== "dog" && animal.species !== "cat") {
 			r.push(`${animal.species}'s`);
 		} else {
-			r.push(`${animal.breed}'s`);
+			r.push(`${animal.name}'s`);
 		}
 		r.push(`${animal.dickSize} cock quickly stands at attention.`);
 
diff --git a/src/npc/interaction/slaveOnSlaveFeeding/fSlaveFeed.js b/src/npc/interaction/slaveOnSlaveFeeding/fSlaveFeed.js
index c52902c95ae7f4cd0244e331aae85130b9d56de4..6b6dd752db03c4f6639cda59e5b90427bee970ed 100644
--- a/src/npc/interaction/slaveOnSlaveFeeding/fSlaveFeed.js
+++ b/src/npc/interaction/slaveOnSlaveFeeding/fSlaveFeed.js
@@ -13,6 +13,9 @@ globalThis.FSlaveFeed = function(slave, milkTap) {
 	let incestTake;
 	let r = [];
 	const relative = relativeTerm(slave, milkTap);
+	if (slave.bellyAccessory !== "a support band") {
+		slave.bellyAccessory = "none";
+	}
 
 	App.Events.drawEventArt(el, [slave, milkTap]);
 
diff --git a/src/npc/surgery/surgery.js b/src/npc/surgery/surgery.js
index b35aaa749cd9e9d47e89c3811534bea1600bffae..b2039237b0bfdddc5bd6549cf70a0a9f800f62ca 100644
--- a/src/npc/surgery/surgery.js
+++ b/src/npc/surgery/surgery.js
@@ -620,6 +620,9 @@ globalThis.eyeSurgery = function(slave, side, action) {
 			if (eyeExists) {
 				slave.eye[side].vision = 2;
 			}
+			if (["corrective glasses", "corrective contacts"].includes(slave.eyewear)) {
+				slave.eyewear = "none";
+			}
 			return;
 		default:
 			throw Error(`${typeof action} "${action}" not found`);
diff --git a/src/pregmod/FCTV/FCTVshows.js b/src/pregmod/FCTV/FCTVshows.js
index 1d3a2dfa50b511697ba43ff8fc4ba47c5c035d28..a099f8d79bc1527157f29f65325b8f4334b721a7 100644
--- a/src/pregmod/FCTV/FCTVshows.js
+++ b/src/pregmod/FCTV/FCTVshows.js
@@ -2263,7 +2263,7 @@ App.Data.FCTV.channels = {
 
 					r.push(`<p>At this point, her stomach is so distended that the black pitch is showing around individual feathers. Annie and Dakota lock eyes and giggle, while Kate moves to where the noose is tied.</p>`);
 					r.push(`<p>"Ready?" They ask the girl. She can barely open her eyes and doesn't move her head. "Ok then, here we go!"</p>`);
-					r.push(`<p>Kate loosens the rope just as Annie and Dakota each lift a leg. With nothing else to support her, the girl's full weight comes to bear on the plug, which finally smears its tarry way home with a "pop." The Indian girl shudders with an impossible... orgasm? and screams.</p>`);
+					r.push(`<p>Kate loosens the rope just as Annie and Dakota each lift a leg. With nothing else to support her, the girl's full weight comes to bear on the plug, which finally smears its tarry way home with a "pop." The Indian girl screams and shudders with an impossible... orgasm?</p>`);
 
 					r.push(`<p>Annie releases the noose from the scaffold and shoves her over on her back. "You LIKED that? You disgust me." She is powerless to move, and lays there groaning and drooling beneath the weight of her stomach.</p>`);
 					r.push(`<p>"Better finish your drink, little chicken." Dakota wrings out the skin, and the liquid has nowhere to go but in. She neatly wraps rawhide around the bag to make sure the inflation can't reverse, and then covers the whole thing with pitch. It will not be coming undone soon.</p>`);