diff --git a/Changelog.txt b/Changelog.txt
index 2c3258812651a99a2fc8b79727ee9fe7ba704661..0829a6ba3d280a61d50931d955ee68977f204f8d 100644
--- a/Changelog.txt
+++ b/Changelog.txt
@@ -2,6 +2,13 @@ Pregmod
 
 0.10.7.1-3.8.x
 
+	-learned how to add vectors
+	-fixed nicea event chain
+	-fixed issues with the TFS
+	-clothing data overhaul
+	-description options converted to JS
+	-fixes
+
 	12/13/2020
 
 	3
diff --git a/js/003-data/slaveWearData.js b/js/003-data/slaveWearData.js
index 6065c8ee0de396a9999afdb4a8c0210d4a27f0fc..dd07624cc37beac04823fcfc5b85c0c1d3480276 100644
--- a/js/003-data/slaveWearData.js
+++ b/js/003-data/slaveWearData.js
@@ -779,7 +779,7 @@ App.Data.clothes = new Map([
 			name: "Chains",
 			fs: "FSDegradationist",
 			get requirements() { return V.boughtItem.clothing.chains === 1; },
-			exposure: 3,
+			exposure: 4,
 			harsh: true
 		}
 	],
@@ -806,7 +806,7 @@ App.Data.clothes = new Map([
 	["shibari ropes",
 		{
 			name: "Shibari ropes",
-			exposure: 3,
+			exposure: 4,
 			harsh: true
 		}
 	],
diff --git a/src/005-passages/options.js b/src/005-passages/optionsPassage.js
similarity index 100%
rename from src/005-passages/options.js
rename to src/005-passages/optionsPassage.js
diff --git a/src/endWeek/saClothes.js b/src/endWeek/saClothes.js
index 914f95a5d114e439633608ac242b6f5e80834ffd..0abf5f1e2b96472cc80935c0cbb4f286ccb32cd6 100644
--- a/src/endWeek/saClothes.js
+++ b/src/endWeek/saClothes.js
@@ -85,260 +85,298 @@ App.SlaveAssignment.clothes = (function() {
 	 *
 	 */
 	function clothingEffects(slave) {
-		switch (slave.clothes) {
-			case "no clothing":
-			case "body oil":
-				if (slave.devotion >= -20) {
-					if (slave.fetish === "humiliation" && slave.fetishKnown === 0) {
-						r.push(`${He} pretends to be embarrassed by ${his} nudity but seems to get off on it. <span class="lightcoral">${He}'s into humiliation.</span>`);
-						slave.fetishKnown = 1;
-					} else if (slave.fetish === "humiliation" && slave.fetishStrength > 60) {
-						r.push(`${He} pretends to be embarrassed by ${his} nudity but <span class="hotpink">openly gets off on it.</span>`);
-						slave.devotion += 2;
-					} else if (slave.fetish === "humiliation") {
-						r.push(`${He} pretends to be embarrassed by ${his} nudity but <span class="hotpink">secretly gets off on it.</span>`);
-						slave.devotion += 1;
-					} else if (slave.energy > 95) {
-						r.push(`${His} libido is so strong that ${he} <span class="hotpink">enjoys being naked and available.</span>`);
-						slave.devotion += 1;
-					}
-				}
-				break;
-			case "a penitent nuns habit":
-				r.push(`The mortification of the flesh ${he} endures from wearing ${his} sackcloth habit slowly and painfully <span class="hotpink">purifies ${his} mind</span> of any but devoted, <span class="gold">fearful</span> thoughts. It's also <span class="health dec">unhealthy.</span>`);
-				slave.devotion += 2;
-				slave.trust -= 2;
-				healthDamage(slave, 3);
-				if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
-					r.push(`${His} chafed skin makes sex an agonizing prospect. ${He} seems to get off on the pain; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
+		if (App.Data.clothes.get(slave.clothes) && getExposure(slave) === 4) {
+			if (slave.devotion >= -20) {
+				if (slave.fetish === "humiliation" && slave.fetishKnown === 0) {
+					r.push(`${He} pretends to be embarrassed by ${his} nudity but seems to get off on it. <span class="lightcoral">${He}'s into humiliation.</span>`);
 					slave.fetishKnown = 1;
-				} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
-					if (fetishChangeChance(slave) > jsRandom(0, 100)) {
-						r.push(`${His} chafed skin makes sex an agonizing prospect. ${He} learns to come in spite of, and then <span class="lightcoral">because of the pain.</span>`);
-						slave.fetish = "masochist";
-						slave.fetishKnown = 1;
-						slave.fetishStrength = 10;
-					}
-				}
-				break;
-			case "uncomfortable straps":
-				if (slave.devotion >= -20 && slave.fetish === "masochist" && slave.fetishKnown === 1) {
-					r.push(`The uncomfortable straps ${he}'s wearing constantly give ${him} little twinges of pain, <span class="hotpink">titillating ${him}.</span>`);
+				} else if (slave.fetish === "humiliation" && slave.fetishStrength > 60) {
+					r.push(`${He} pretends to be embarrassed by ${his} nudity but <span class="hotpink">openly gets off on it.</span>`);
 					slave.devotion += 2;
-				} else if (slave.devotion <= 20 && slave.trust >= -50) {
-					r.push(`The uncomfortable straps ${he}'s wearing keep ${him} <span class="hotpink">servile</span> and <span class="gold">afraid.</span>`);
+				} else if (slave.fetish === "humiliation") {
+					r.push(`${He} pretends to be embarrassed by ${his} nudity but <span class="hotpink">secretly gets off on it.</span>`);
 					slave.devotion += 1;
-					slave.trust -= 1;
-					if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
-						r.push(`The straps pinch and constrict ${him} whenever ${he}'s used. ${He} seems to get off on the discomfort; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
-						slave.fetishKnown = 1;
-					} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
-						if (fetishChangeChance(slave) > jsRandom(0, 100)) {
-							r.push(`The straps pinch and constrict ${him} whenever ${he}'s used. ${He} learns to come in spite of, and then <span class="lightcoral">because of the discomfort.</span>`);
-							slave.fetish = "masochist";
+				} else if (slave.energy > 95) {
+					r.push(`${His} libido is so strong that ${he} <span class="hotpink">enjoys being naked and available.</span>`);
+					slave.devotion += 1;
+				}
+			}
+		}
+		// humiliating clothing effects
+		if (slave.fetishKnown === 0 || slave.fetish === "none") {
+			if (getExposure(slave) === 3) {
+				if (fetishChangeChance(slave) > jsRandom(0, 100)) {
+					r.push(`Surprisingly, ${he} takes to ${his} extremely revealing clothing, and gets an obvious thrill from it. <span class="lightcoral">${He}'s become a humiliation fetishist!</span>`);
+					slave.fetish = "humiliation";
+					slave.fetishKnown = 1;
+					slave.fetishStrength = 10;
+				}
+			}
+		}
+
+		if (App.Data.clothes.get(slave.clothes)) {
+			if (App.Data.clothes.get(slave.clothes).harsh) {
+				switch (slave.clothes) {
+					case "a penitent nuns habit":
+						r.push(`The mortification of the flesh ${he} endures from wearing ${his} sackcloth habit slowly and painfully <span class="hotpink">purifies ${his} mind</span> of any but devoted, <span class="gold">fearful</span> thoughts. It's also <span class="health dec">unhealthy.</span>`);
+						slave.devotion += 2;
+						slave.trust -= 2;
+						healthDamage(slave, 3);
+						if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
+							r.push(`${His} chafed skin makes sex an agonizing prospect. ${He} seems to get off on the pain; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
 							slave.fetishKnown = 1;
-							slave.fetishStrength = 10;
+						} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
+							if (fetishChangeChance(slave) > jsRandom(0, 100)) {
+								r.push(`${His} chafed skin makes sex an agonizing prospect. ${He} learns to come in spite of, and then <span class="lightcoral">because of the pain.</span>`);
+								slave.fetish = "masochist";
+								slave.fetishKnown = 1;
+								slave.fetishStrength = 10;
+							}
 						}
-					}
-				} else {
-					if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
-						r.push(`${His} straps pinch and constrict ${him} whenever ${he}'s used. ${He} seems to get off on the discomfort; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
-						slave.fetishKnown = 1;
-					} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
-						if (fetishChangeChance(slave) > jsRandom(0, 100)) {
-							r.push(`${His} straps pinch and constrict ${him} whenever ${he}'s used. ${He} learns to come in spite of, and then <span class="lightcoral">because of the discomfort.</span>`);
-							slave.fetish = "masochist";
-							slave.fetishKnown = 1;
-							slave.fetishStrength = 10;
+						break;
+					case "uncomfortable straps":
+						if (slave.devotion >= -20 && slave.fetish === "masochist" && slave.fetishKnown === 1) {
+							r.push(`The uncomfortable straps ${he}'s wearing constantly give ${him} little twinges of pain, <span class="hotpink">titillating ${him}.</span>`);
+							slave.devotion += 2;
+						} else if (slave.devotion <= 20 && slave.trust >= -50) {
+							r.push(`The uncomfortable straps ${he}'s wearing keep ${him} <span class="hotpink">servile</span> and <span class="gold">afraid.</span>`);
+							slave.devotion += 1;
+							slave.trust -= 1;
+							if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
+								r.push(`The straps pinch and constrict ${him} whenever ${he}'s used. ${He} seems to get off on the discomfort; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
+								if (fetishChangeChance(slave) > jsRandom(0, 100)) {
+									r.push(`The straps pinch and constrict ${him} whenever ${he}'s used. ${He} learns to come in spite of, and then <span class="lightcoral">because of the discomfort.</span>`);
+									slave.fetish = "masochist";
+									slave.fetishKnown = 1;
+									slave.fetishStrength = 10;
+								}
+							}
+						} else {
+							if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
+								r.push(`${His} straps pinch and constrict ${him} whenever ${he}'s used. ${He} seems to get off on the discomfort; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
+								if (fetishChangeChance(slave) > jsRandom(0, 100)) {
+									r.push(`${His} straps pinch and constrict ${him} whenever ${he}'s used. ${He} learns to come in spite of, and then <span class="lightcoral">because of the discomfort.</span>`);
+									slave.fetish = "masochist";
+									slave.fetishKnown = 1;
+									slave.fetishStrength = 10;
+								}
+							}
 						}
-					}
-				}
-				break;
-			case "chains":
-				if (slave.devotion >= -20 && slave.fetish === "masochist" && slave.fetishKnown === 1) {
-					r.push(`The chains ${he}'s wearing constantly give ${him} little twinges of pain, <span class="hotpink">titillating ${him}.</span>`);
-					slave.devotion += 2;
-				} else if (slave.devotion <= 20 && slave.trust >= -50) {
-					r.push(`The chains ${he}'s wearing keep ${him} <span class="hotpink">servile</span> and <span class="gold">afraid.</span>`);
-					slave.devotion += 1;
-					slave.trust -= 1;
-					if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
-						r.push(`${His} chains pinch and constrict ${him} whenever ${he}'s used. ${He} seems to get off on the discomfort; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
-						slave.fetishKnown = 1;
-					} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
-						if (fetishChangeChance(slave) > jsRandom(0, 100)) {
-							r.push(`${His} chains pinch and constrict ${him} whenever ${he}'s used. ${He} learns to come in spite of, and then <span class="lightcoral">because of the discomfort.</span>`);
-							slave.fetish = "masochist";
-							slave.fetishKnown = 1;
-							slave.fetishStrength = 10;
+						break;
+					case "chains":
+						if (slave.devotion >= -20 && slave.fetish === "masochist" && slave.fetishKnown === 1) {
+							r.push(`The chains ${he}'s wearing constantly give ${him} little twinges of pain, <span class="hotpink">titillating ${him}.</span>`);
+							slave.devotion += 2;
+						} else if (slave.devotion <= 20 && slave.trust >= -50) {
+							r.push(`The chains ${he}'s wearing keep ${him} <span class="hotpink">servile</span> and <span class="gold">afraid.</span>`);
+							slave.devotion += 1;
+							slave.trust -= 1;
+							if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
+								r.push(`${His} chains pinch and constrict ${him} whenever ${he}'s used. ${He} seems to get off on the discomfort; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
+								if (fetishChangeChance(slave) > jsRandom(0, 100)) {
+									r.push(`${His} chains pinch and constrict ${him} whenever ${he}'s used. ${He} learns to come in spite of, and then <span class="lightcoral">because of the discomfort.</span>`);
+									slave.fetish = "masochist";
+									slave.fetishKnown = 1;
+									slave.fetishStrength = 10;
+								}
+							}
+						} else {
+							if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
+								r.push(`${His} chains pinch and constrict ${him} whenever ${he}'s used. ${He} seems to get off on the discomfort; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
+								if (fetishChangeChance(slave) > jsRandom(0, 100)) {
+									r.push(`${His} chains pinch and constrict ${him} whenever ${he}'s used. ${He} learns to come in spite of, and then <span class="lightcoral">because of the discomfort.</span>`);
+									slave.fetish = "masochist";
+									slave.fetishKnown = 1;
+									slave.fetishStrength = 10;
+								}
+							}
 						}
-					}
-				} else {
-					if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
-						r.push(`${His} chains pinch and constrict ${him} whenever ${he}'s used. ${He} seems to get off on the discomfort; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
-						slave.fetishKnown = 1;
-					} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
-						if (fetishChangeChance(slave) > jsRandom(0, 100)) {
-							r.push(`${His} chains pinch and constrict ${him} whenever ${he}'s used. ${He} learns to come in spite of, and then <span class="lightcoral">because of the discomfort.</span>`);
-							slave.fetish = "masochist";
-							slave.fetishKnown = 1;
-							slave.fetishStrength = 10;
+						break;
+					case "restrictive latex":
+						if (slave.devotion > 20 && slave.trust >= -50 && slave.fetish === "submissive") {
+							if (slave.fetishKnown === 0) {
+								r.push(`The latex ${he}'s wearing limits ${his} world to your input and control. ${He} seems to get off on the lack of control; ${he}'s a <span class="lightcoral">total submissive.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetishStrength > 60) {
+								r.push(`As a submissive ${he} <span class="hotpink">openly enjoys being immured in latex.</span>`);
+								slave.devotion += 2;
+							} else {
+								r.push(`${His} submissive tendencies help ${him} <span class="hotpink">enjoy being immured in latex.</span>`);
+								slave.devotion += 1;
+							}
+						} else if (slave.devotion < -20) {
+							r.push(`The latex ${he}'s wearing limits ${his} world to <span class="hotpink">your input and control</span> and <span class="gold">fear</span> of unexpected pain.`);
+							slave.devotion += 1;
+							slave.trust -= 1;
 						}
-					}
-				}
-				break;
-			case "restrictive latex":
-				if (slave.devotion > 20 && slave.trust >= -50 && slave.fetish === "submissive") {
-					if (slave.fetishKnown === 0) {
-						r.push(`The latex ${he}'s wearing limits ${his} world to your input and control. ${He} seems to get off on the lack of control; ${he}'s a <span class="lightcoral">total submissive.</span>`);
-						slave.fetishKnown = 1;
-					} else if (slave.fetishStrength > 60) {
-						r.push(`As a submissive ${he} <span class="hotpink">openly enjoys being immured in latex.</span>`);
-						slave.devotion += 2;
-					} else {
-						r.push(`${His} submissive tendencies help ${him} <span class="hotpink">enjoy being immured in latex.</span>`);
-						slave.devotion += 1;
-					}
-				} else if (slave.devotion < -20) {
-					r.push(`The latex ${he}'s wearing limits ${his} world to <span class="hotpink">your input and control</span> and <span class="gold">fear</span> of unexpected pain.`);
-					slave.devotion += 1;
-					slave.trust -= 1;
-				}
-				break;
-			case "shibari ropes":
-				if (slave.devotion > 20 && slave.trust >= -50 && slave.fetish === "submissive") {
-					if (slave.fetishKnown === 0) {
-						r.push(`The ropes ${he}'s wearing restrict ${him} and leave ${him} completely helpless. ${He} seems to get off on the lack of control; ${he}'s a <span class="lightcoral">natural submissive.</span>`);
-						slave.fetishKnown = 1;
-					} else if (slave.fetishStrength > 60) {
-						r.push(`As a submissive ${he} <span class="hotpink">openly enjoys wearing binding ropes as clothing.</span>`);
-						slave.devotion += 2;
-					} else {
-						r.push(`${His} submissive tendencies help ${him} <span class="hotpink">enjoy wearing binding ropes as clothing.</span>`);
-						slave.devotion += 1;
-					}
-				} else if (slave.devotion < -20) {
-					r.push(`The ropes ${he}'s wearing restrict ${him} without pain, rendering ${him} <span class="hotpink">susceptible to control</span> and <span class="gold">afraid.</span>`);
-					slave.devotion += 1;
-					slave.trust -= 1;
-				}
-				break;
-			case "an apron":
-				if (slave.fetish === "submissive") {
-					if (slave.fetishKnown === 0) {
-						r.push(`${He} pretends to be embarrassed by wearing nothing but an apron, but seems to get off on how it invites other to take control and use ${him}. <span class="lightcoral">${He}'s a natural submissive.</span>`);
-						slave.fetishKnown = 1;
-					} else {
-						r.push(`${He} pretends to be embarrassed by wearing nothing but an apron but <span class="hotpink">secretly gets off</span> on how it invites men to bend ${him} over and put ${him} in ${his} place.`);
-						slave.devotion += 1;
-					}
-				} else if (slave.fetish === "humiliation") {
-					if (slave.fetishKnown === 0) {
-						r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but seems to get off on it. <span class="lightcoral">${He}'s into humiliation.</span>`);
-						slave.fetishKnown = 1;
-					} else if (slave.fetishStrength > 60) {
-						r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but <span class="hotpink">openly gets off on it.</span>`);
-						slave.devotion += 2;
-					} else {
-						r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but <span class="hotpink">secretly gets off on it.</span>`);
-						slave.devotion += 1;
-					}
-				} else if (slave.fetish === "pregnancy" && (slave.bellyPreg >= 1500 || slave.bellyImplant >= 1500)) {
-					if (slave.fetishKnown === 0) {
-						r.push(`${He} pretends to be embarrassed over only having an apron to cover ${his} gravid swell but seems to get off on it. <span class="lightcoral">${He}'s a pregnancy fetishist.</span>`);
-						slave.fetishKnown = 1;
-					} else if (slave.fetishStrength > 60) {
-						r.push(`${He} <span class="hotpink">openly gets off</span> from how motherly ${he} looks wearing nothing but an apron over ${his}`);
-						if (slave.bellyPreg > 100) {
-							r.push(`increasingly`);
+						break;
+					case "shibari ropes":
+						if (slave.devotion > 20 && slave.trust >= -50 && slave.fetish === "submissive") {
+							if (slave.fetishKnown === 0) {
+								r.push(`The ropes ${he}'s wearing restrict ${him} and leave ${him} completely helpless. ${He} seems to get off on the lack of control; ${he}'s a <span class="lightcoral">natural submissive.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetishStrength > 60) {
+								r.push(`As a submissive ${he} <span class="hotpink">openly enjoys wearing binding ropes as clothing.</span>`);
+								slave.devotion += 2;
+							} else {
+								r.push(`${His} submissive tendencies help ${him} <span class="hotpink">enjoy wearing binding ropes as clothing.</span>`);
+								slave.devotion += 1;
+							}
+						} else if (slave.devotion < -20) {
+							r.push(`The ropes ${he}'s wearing restrict ${him} without pain, rendering ${him} <span class="hotpink">susceptible to control</span> and <span class="gold">afraid.</span>`);
+							slave.devotion += 1;
+							slave.trust -= 1;
 						}
-						r.push(`gravid frame.`);
-						slave.devotion += 2;
-					} else {
-						r.push(`${He} <span class="hotpink">secretly gets off</span> from how motherly ${he} feels wearing nothing but an apron over ${his}`);
-						if (slave.bellyPreg > 100) {
-							r.push(`increasingly`);
+						break;
+					default:
+						if (slave.devotion >= -20 && slave.fetish === "masochist" && slave.fetishKnown === 1) {
+							r.push(`The outfit ${he}'s wearing constantly give ${him} little twinges of pain, <span class="hotpink">titillating ${him}.</span>`);
+							slave.devotion += 2;
+						} else if (slave.devotion <= 20 && slave.trust >= -50) {
+							r.push(`The outfit ${he}'s wearing keep ${him} <span class="hotpink">servile</span> and <span class="gold">afraid.</span>`);
+							slave.devotion += 1;
+							slave.trust -= 1;
+							if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
+								r.push(`${His} outfit pinches and constricts ${him} whenever ${he}'s used. ${He} seems to get off on the discomfort; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
+								if (fetishChangeChance(slave) > jsRandom(0, 100)) {
+									r.push(`${His} outfit pinches and constricts ${him} whenever ${he}'s used. ${He} learns to come in spite of, and then <span class="lightcoral">because of the discomfort.</span>`);
+									slave.fetish = "masochist";
+									slave.fetishKnown = 1;
+									slave.fetishStrength = 10;
+								}
+							}
+						} else {
+							if (slave.fetish === "masochist" && slave.fetishKnown === 0) {
+								r.push(`${His} outfit pinches and constricts ${him} whenever ${he}'s used. ${He} seems to get off on the discomfort; ${he}'s a <span class="lightcoral">natural masochist.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetish === "none" || slave.fetishKnown === 0) {
+								if (fetishChangeChance(slave) > jsRandom(0, 100)) {
+									r.push(`${His} outfit pinches and constricts ${him} whenever ${he}'s used. ${He} learns to come in spite of, and then <span class="lightcoral">because of the discomfort.</span>`);
+									slave.fetish = "masochist";
+									slave.fetishKnown = 1;
+									slave.fetishStrength = 10;
+								}
+							}
 						}
-						r.push(`gravid frame.`);
-						slave.devotion += 1;
-					}
-				} else if (slave.devotion <= 20) {
-					r.push(`${He} is <span class="mediumorchid">inappropriately proud</span> of the nice apron ${he}'s wearing, <span class="mediumaquamarine">building ${his} confidence.</span>`);
-					slave.devotion -= 5;
-					slave.trust += 3;
-				} else {
-					r.push(`${He} is <span class="hotpink">proud</span> and <span class="mediumaquamarine">confident</span> of the nice apron ${he}'s wearing.`);
-					slave.devotion += 1;
-					slave.trust += 1;
 				}
-				break;
-			default:
-				if (slave.devotion <= 20) {
-					if (App.Data.clothes.get(slave.clothes).exposure === 0) {
-						r.push(`${He} is <span class="mediumorchid">inappropriately proud</span> of the modest clothes ${he}'s wearing; their decency <span class="mediumaquamarine">rapidly building ${his} confidence.</span>`);
-						slave.trust += 7;
-					} else if (App.Data.clothes.get(slave.clothes).exposure === 1) {
-						r.push(`${He} is <span class="mediumorchid">inappropriately proud</span> of the nice clothes ${he}'s wearing; their relative decency <span class="mediumaquamarine">building ${his} confidence.</span>`);
-						slave.trust += 5;
-					} else if (App.Data.clothes.get(slave.clothes).exposure <= 3) {
-						r.push(`${He} is <span class="mediumorchid">inappropriately proud</span> of the nice clothes ${he}'s wearing, <span class="mediumaquamarine">building ${his} confidence.</span>`);
-						slave.trust += 3;
-					}
-					slave.devotion -= 5;
-				} else if (slave.fetish === "boobs" && slave.clothes === "a monokini") {
-					if (slave.fetishKnown === 0) {
-						r.push(`${He} pretends to be embarrassed by how ${his} monokini draws attention to ${his} breasts but <span class="hotpink">seems to get off on it.</span>`);
-						slave.devotion += 1;
-					} else if (slave.fetishStrength > 60) {
-						r.push(`${He} pretends to be embarrassed by ${his} clearly exposed breasts but <span class="hotpink">openly gets off on it.</span>`);
-						slave.devotion += 2;
-					} else {
-						r.push(`${He} pretends to be embarrassed by ${his} clearly exposed breasts but <span class="hotpink">secretly gets off on it.</span>`);
-						slave.devotion += 1;
-					}
-				} else if (slave.fetish === "humiliation" && App.Data.clothes.get(slave.clothes).exposure === 3) {
-					if (slave.fetishKnown === 0) {
-						r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but seems to get off on it. <span class="lightcoral">${He}'s into humiliation.</span>`);
-						slave.fetishKnown = 1;
-					} else if (slave.fetishStrength > 60) {
-						r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but <span class="hotpink">openly gets off on it.</span>`);
-						slave.devotion += 2;
-					} else {
-						r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but <span class="hotpink">secretly gets off on it.</span>`);
-						slave.devotion += 1;
-					}
-				} else if (slave.dick > 0) {
-					/* males have trouble with outfit block */ /* return to with crotch description overhaul */
-					switch (slave.clothes) {
-						case "attractive lingerie":
-						case "attractive lingerie for a pregnant woman":
-							r.push(`${He} is <span class="hotpink">proud</span> of the pretty lingerie ${he}'s wearing, but ${he} constantly has to adjust ${his} g-string to cover ${his} penis.`);
-							slave.devotion += 1;
-							break;
-						case "a string bikini":
-							r.push(`${He} is <span class="hotpink">proud</span> of the slutty swimsuit ${he}'s wearing, but ${he} constantly has to adjust ${his} string bikini bottom in a vain effort to cover ${his} penis.`);
+			} else { // nice
+				switch (slave.clothes) {
+					case "an apron":
+						if (slave.fetish === "submissive") {
+							if (slave.fetishKnown === 0) {
+								r.push(`${He} pretends to be embarrassed by wearing nothing but an apron, but seems to get off on how it invites other to take control and use ${him}. <span class="lightcoral">${He}'s a natural submissive.</span>`);
+								slave.fetishKnown = 1;
+							} else {
+								r.push(`${He} pretends to be embarrassed by wearing nothing but an apron but <span class="hotpink">secretly gets off</span> on how it invites men to bend ${him} over and put ${him} in ${his} place.`);
+								slave.devotion += 1;
+							}
+						} else if (slave.fetish === "humiliation") {
+							if (slave.fetishKnown === 0) {
+								r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but seems to get off on it. <span class="lightcoral">${He}'s into humiliation.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetishStrength > 60) {
+								r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but <span class="hotpink">openly gets off on it.</span>`);
+								slave.devotion += 2;
+							} else {
+								r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but <span class="hotpink">secretly gets off on it.</span>`);
+								slave.devotion += 1;
+							}
+						} else if (slave.fetish === "pregnancy" && (slave.bellyPreg >= 1500 || slave.bellyImplant >= 1500)) {
+							if (slave.fetishKnown === 0) {
+								r.push(`${He} pretends to be embarrassed over only having an apron to cover ${his} gravid swell but seems to get off on it. <span class="lightcoral">${He}'s a pregnancy fetishist.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetishStrength > 60) {
+								r.push(`${He} <span class="hotpink">openly gets off</span> from how motherly ${he} looks wearing nothing but an apron over ${his}`);
+								if (slave.bellyPreg > 100) {
+									r.push(`increasingly`);
+								}
+								r.push(`gravid frame.`);
+								slave.devotion += 2;
+							} else {
+								r.push(`${He} <span class="hotpink">secretly gets off</span> from how motherly ${he} feels wearing nothing but an apron over ${his}`);
+								if (slave.bellyPreg > 100) {
+									r.push(`increasingly`);
+								}
+								r.push(`gravid frame.`);
+								slave.devotion += 1;
+							}
+						} else if (slave.devotion <= 20) {
+							r.push(`${He} is <span class="mediumorchid">inappropriately proud</span> of the nice apron ${he}'s wearing, <span class="mediumaquamarine">building ${his} confidence.</span>`);
+							slave.devotion -= 5;
+							slave.trust += 3;
+						} else {
+							r.push(`${He} is <span class="hotpink">proud</span> and <span class="mediumaquamarine">confident</span> of the nice apron ${he}'s wearing.`);
 							slave.devotion += 1;
-							break;
-						default:
+							slave.trust += 1;
+						}
+						break;
+					default:
+						if (slave.devotion <= 20) {
+							if (App.Data.clothes.get(slave.clothes).exposure === 0) {
+								r.push(`${He} is <span class="mediumorchid">inappropriately proud</span> of the modest clothes ${he}'s wearing; their decency <span class="mediumaquamarine">rapidly building ${his} confidence.</span>`);
+								slave.trust += 7;
+							} else if (App.Data.clothes.get(slave.clothes).exposure === 1) {
+								r.push(`${He} is <span class="mediumorchid">inappropriately proud</span> of the nice clothes ${he}'s wearing; their relative decency <span class="mediumaquamarine">building ${his} confidence.</span>`);
+								slave.trust += 5;
+							} else if (App.Data.clothes.get(slave.clothes).exposure <= 3) {
+								r.push(`${He} is <span class="mediumorchid">inappropriately proud</span> of the nice clothes ${he}'s wearing, <span class="mediumaquamarine">building ${his} confidence.</span>`);
+								slave.trust += 3;
+							}
+							slave.devotion -= 5;
+						} else if (slave.fetish === "boobs" && slave.clothes === "a monokini") {
+							if (slave.fetishKnown === 0) {
+								r.push(`${He} pretends to be embarrassed by how ${his} monokini draws attention to ${his} breasts but <span class="hotpink">seems to get off on it.</span>`);
+								slave.devotion += 1;
+							} else if (slave.fetishStrength > 60) {
+								r.push(`${He} pretends to be embarrassed by ${his} clearly exposed breasts but <span class="hotpink">openly gets off on it.</span>`);
+								slave.devotion += 2;
+							} else {
+								r.push(`${He} pretends to be embarrassed by ${his} clearly exposed breasts but <span class="hotpink">secretly gets off on it.</span>`);
+								slave.devotion += 1;
+							}
+						} else if (slave.fetish === "humiliation" && getExposure(slave) === 3) {
+							if (slave.fetishKnown === 0) {
+								r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but seems to get off on it. <span class="lightcoral">${He}'s into humiliation.</span>`);
+								slave.fetishKnown = 1;
+							} else if (slave.fetishStrength > 60) {
+								r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but <span class="hotpink">openly gets off on it.</span>`);
+								slave.devotion += 2;
+							} else {
+								r.push(`${He} pretends to be embarrassed by ${his} extremely revealing clothing but <span class="hotpink">secretly gets off on it.</span>`);
+								slave.devotion += 1;
+							}
+						} else if (slave.dick > 0) {
+							/* males have trouble with outfit block */ /* return to with crotch description overhaul */
+							switch (slave.clothes) {
+								case "attractive lingerie":
+								case "attractive lingerie for a pregnant woman":
+									r.push(`${He} is <span class="hotpink">proud</span> of the pretty lingerie ${he}'s wearing, but ${he} constantly has to adjust ${his} g-string to cover ${his} penis.`);
+									slave.devotion += 1;
+									break;
+								case "a string bikini":
+									r.push(`${He} is <span class="hotpink">proud</span> of the slutty swimsuit ${he}'s wearing, but ${he} constantly has to adjust ${his} string bikini bottom in a vain effort to cover ${his} penis.`);
+									slave.devotion += 1;
+									break;
+								default:
+									r.push(`${He} is <span class="hotpink">proud</span> and <span class="mediumaquamarine">confident</span> of the nice clothes ${he}'s wearing.`);
+									slave.devotion += 1;
+									slave.trust += 1;
+							}
+						} else {
 							r.push(`${He} is <span class="hotpink">proud</span> and <span class="mediumaquamarine">confident</span> of the nice clothes ${he}'s wearing.`);
 							slave.devotion += 1;
 							slave.trust += 1;
-					}
-				} else {
-					r.push(`${He} is <span class="hotpink">proud</span> and <span class="mediumaquamarine">confident</span> of the nice clothes ${he}'s wearing.`);
-					slave.devotion += 1;
-					slave.trust += 1;
-				}
-		}
-
-		// humiliating clothing effects
-		if (slave.fetishKnown === 0 || slave.fetish === "none") {
-			if (App.Data.clothes.get(slave.clothes).exposure === 3) {
-				if (fetishChangeChance(slave) > jsRandom(0, 100)) {
-					r.push(`Surprisingly, ${he} takes to ${his} extremely revealing clothing, and gets an obvious thrill from it. <span class="lightcoral">${He}'s become a humiliation fetishist!</span>`);
-					slave.fetish = "humiliation";
-					slave.fetishKnown = 1;
-					slave.fetishStrength = 10;
+						}
 				}
 			}
 		}
@@ -427,7 +465,7 @@ App.SlaveAssignment.clothes = (function() {
 			if (slave.collar === "heavy gold" || slave.collar === "ancient Egyptian") {
 				r.push(`${He} bears the burden of ${his} heavy gold collar with <span class="mediumaquamarine">confidence.</span>`);
 				slave.trust += 1;
-			} else if (slave.collar === "bowtie" || slave.collar === "neck tie" ) {
+			} else if (slave.collar === "bowtie" || slave.collar === "neck tie") {
 				r.push(`The ${slave.collar} and shirt collar ${he} wears fill ${him} with <span class="mediumaquamarine">confidence,</span> since although they conceal a more traditional slave collar that can be used to restrain ${him}, they don't look like it.`);
 				slave.trust += 1;
 			} else if (["nice retirement counter", "pretty jewelry", "satin choker", "silk ribbon", "stylish leather"].includes(slave.collar)) {
diff --git a/src/gui/options/options.js b/src/gui/options/options.js
index a6ffd81760751d90cabb3ebeff05929bc7c4e08f..74cbea915f9176f506b76654c5beca92560d623e 100644
--- a/src/gui/options/options.js
+++ b/src/gui/options/options.js
@@ -1,465 +1,1061 @@
-App.UI.OptionsGroup = (function() {
-	class Row {
-		/**
-		 * @param {HTMLDivElement} container
-		 */
-		render(container) {} // jshint ignore:line
-	}
+App.UI.optionsPassage = function() {
+	const el = new DocumentFragment();
+	V.passageSwitchHandler = App.EventHandlers.optionsChanged;
+	el.append(intro());
+
+	// Results
+	const results = document.createElement("div");
+	results.id = "results";
+	el.append(results);
+
+	App.UI.tabBar.handlePreSelectedTab(V.tabChoice.Options);
 
+	// TODO: move me
 	/**
-	 * @typedef value
-	 * @property {*} value
-	 * @property {string} [name]
-	 * @property {string} mode
-	 * @property {number} [compareValue]
-	 * @property {string} [descAppend] can be SC markup
-	 * @property {boolean} [on]
-	 * @property {boolean} [off]
-	 * @property {boolean} [neutral]
-	 * @property {Function} [callback]
+	 *
+	 * @param {string} id
+	 * @param {Node} element
+	 * @returns {HTMLSpanElement}
 	 */
+	function makeSpanIded(id, element) {
+		const span = document.createElement("span");
+		span.id = id;
+		span.append(element);
+		return span;
+	}
 
-	class Option extends Row {
-		/**
-		 * @param {string} description can be SC markup
-		 * @param {string} property
-		 * @param {object} [object=V]
-		 */
-		constructor(description, property, object = V) {
-			super();
-			this.description = description;
-			this.property = property;
-			this.object = object;
-			/**
-			 * @type {Array<value>}
-			 */
-			this.valuePairs = [];
-		}
+	const tabCaptions = {
+		"display": 'Display',
+		"contentFlavor": 'Content & flavour',
+		"mods": 'Mods',
+		"debugCheating": 'Debug & cheating',
+		"experimental": 'Experimental'
+	};
 
-		/**
-		 * @param {*} name
-		 * @param {*} [value=name]
-		 * @param {Function} [callback]
-		 * @returns {Option}
-		 */
-		addValue(name, value = name, callback = undefined) {
-			this.valuePairs.push({
-				name: name, value: value, mode: "=", callback: callback
-			});
-			return this;
-		}
+	const tabBar = App.UI.DOM.appendNewElement("div", el, '', "tab-bar");
+	tabBar.append(
+		App.UI.tabBar.tabButton('display', tabCaptions.display),
+		App.UI.tabBar.tabButton('content-flavor', tabCaptions.contentFlavor),
+		App.UI.tabBar.tabButton('mods', tabCaptions.mods),
+		App.UI.tabBar.tabButton('debug-cheating', tabCaptions.debugCheating),
+		App.UI.tabBar.tabButton('experimental', tabCaptions.experimental),
+	);
 
-		/**
-		 * @param {Array<*|Array>} values
-		 * @returns {Option}
-		 */
-		addValueList(values) {
-			for (const value of values) {
-				if (Array.isArray(value)) {
-					this.addValue(value[0], value[1]);
-				} else {
-					this.addValue(value);
-				}
-			}
-			return this;
-		}
+	el.append(App.UI.tabBar.makeTab('display', makeSpanIded("content-display", display())));
+	el.append(App.UI.tabBar.makeTab('content-flavor', makeSpanIded("content-content-flavor", contentFlavor())));
+	el.append(App.UI.tabBar.makeTab('mods', makeSpanIded("content-mods", mods())));
+	el.append(App.UI.tabBar.makeTab('debug-cheating', makeSpanIded("content-debug-cheating", debugCheating())));
+	el.append(App.UI.tabBar.makeTab('experimental', makeSpanIded("content-experimental", experimental())));
 
-		/**
-		 * @param {Map} values
-		 * @returns {Option}
-		 */
-		addValueMap(values) {
-			for (const [key, value] of values) {
-				this.addValue(key, value);
-			}
-			return this;
-		}
+	return el;
 
-		/**
-		 * @param {*} value
-		 * @param {number} compareValue
-		 * @param {string} mode on of: "<", "<=", ">", ">="
-		 * @param {string} [name=value]
-		 */
-		addRange(value, compareValue, mode, name = value) {
-			this.valuePairs.push({
-				name: name, value: value, mode: mode, compareValue: compareValue
-			});
-			return this;
-		}
+	function intro() {
+		let links;
+		let options;
+		let r;
+		const el = new DocumentFragment();
 
-		/**
-		 * @param {Object} [params]
-		 * @param {string} [params.unit]
-		 * @param {boolean} [params.large=false]
-		 * @returns {Option}
-		 */
-		showTextBox({unit, large = false} = {}) {
-			this.textbox = {unit: unit, large: large};
-			return this;
-		}
+		options = new App.UI.OptionsGroup();
+		options.addOption("End of week autosaving is currently", "autosave")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+		el.append(options.render());
 
-		/**
-		 * @param {string} comment can be SC markup
-		 * @returns {Option}
-		 */
-		addComment(comment) {
-			this.comment = comment;
-			return this;
-		}
+		App.UI.DOM.appendNewElement("div", el, `This save was created using FC version ${V.ver} build ${V.releaseID}. You are currently playing version: ${App.Version.base}, mod version: ${App.Version.pmod}, build: ${App.Version.release}${App.Version.commitHash ? `, commit: ${App.Version.commitHash}` : ``}`);
 
-		/**
-		 * Adds a button that executes the callback when clicked AND reloads the passage
-		 *
-		 * @param {string} name
-		 * @param {Function} callback
-		 * @param {string} passage
-		 */
-		customButton(name, callback, passage) {
-			this.valuePairs.push({
-				name: name, value: passage, callback: callback, mode: "custom"
-			});
-			return this;
-		}
+		links = [];
+		links.push(App.UI.DOM.passageLink("Apply Backwards Compatibility Update", "Backwards Compatibility"));
 
-		/**
-		 * @param {Node} node
-		 * @returns {Option}
-		 */
-		addCustomDOM(node) {
-			this.valuePairs.push({
-				value: node, mode: "DOM"
-			});
-			return this;
-		}
+		links.push(
+			App.UI.DOM.link(
+				`Reset extended family mode controllers`,
+				() => {
+					resetFamilyCounters();
+					const span = document.createElement("span");
+					span.classList.add("note");
+					App.UI.DOM.appendNewElement("span", span, "Done: ", "lightgreen");
+					span.append("all family relations flushed and rebuilt.");
+					jQuery("#results").empty().append(span);
+				},
+				[],
+				"",
+				"Clears and rebuilds .sister and .daughter tracking."
+			)
+		);
 
-		/* modify last added option */
 
-		/**
-		 * Added to the description if last added value is selected.
-		 * example use: addValue(...).customDescription(...).addValue(...).customDescription(...)
-		 * @param {string} description can be SC markup
-		 */
-		customDescription(description) {
-			this.valuePairs.last().descAppend = description;
-			return this;
+		if (isNaN(V.rep)) {
+			links.push(
+				App.UI.DOM.link(
+					`Reset Reputation (${V.rep})`,
+					() => {
+						V.rep = 0;
+						jQuery("#results").empty().append(`Reputation reset to ${V.rep}`);
+					},
+					[],
+					"Options"
+				)
+			);
 		}
 
-		/**
-		 * @param {Function} callback gets executed on every button click. Selected value is given as argument.
-		 */
-		addCallback(callback) {
-			this.valuePairs.last().callback = callback;
-			return this;
+		if (isNaN(V.rep)) {
+			links.push(
+				App.UI.DOM.link(
+					`Reset Money (${V.cash})`,
+					() => {
+						V.cash = 500;
+						jQuery("#results").empty().append(`Cash reset to ${V.cash}`);
+					},
+					[],
+					"Options"
+				)
+			);
 		}
 
-		/**
-		 * @param {Function} callback gets executed on every button click. Selected value is given as argument.
-		 */
-		addCallbackToEach(callback) {
-			this.valuePairs.forEach(pair => pair.callback = callback);
-			return this;
+		if (V.releaseID === 1057) {
+			links.push(
+				App.UI.DOM.link(
+					`Free male anatomy removal due to accidentally flawed updater`,
+					() => {
+						V.PC.dick = 0;
+						V.PC.balls = 0;
+						V.PC.prostate = 0;
+						V.PC.scrotum = 0;
+						V.PC.ballsImplant = 0;
+						jQuery("#results").empty().append(`Cash reset to ${V.cash}`);
+					},
+					[],
+					"Options",
+					"Use this if your female PC picked up a few extra parts during the conversion process.",
+				)
+			);
 		}
 
-		/**
-		 * Mark option as on to style differently.
-		 * @returns {Option}
-		 */
-		on() {
-			this.valuePairs.last().on = true;
-			return this;
-		}
+		App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links));
 
-		/**
-		 * Mark option as off to style differently.
-		 * @returns {Option}
-		 */
-		off() {
-			this.valuePairs.last().off = true;
-			return this;
+		if ((V.releaseID >= 1000) || V.ver.startsWith("0.9") || V.ver.startsWith("0.8") || V.ver.startsWith("0.7") || V.ver.startsWith("0.6")) {
+			App.UI.DOM.appendNewElement("h3", el, `NEW GAME PLUS`);
+			r = [];
+			r.push(`You can begin a new game with up to five (or more) of your current slaves, although starting resources other than these slaves will be reduced. New Game Plus`);
+			r.push(App.UI.DOM.makeElement("span", "MAY", "yellow"));
+			r.push(`work across versions. To attempt to migrate a save across versions:`);
+			App.Events.addNode(el, r, "div", "note");
+
+			const ngpInstructions = document.createElement("ol");
+			App.UI.DOM.appendNewElement("li", ngpInstructions, "Save on this screen", "note");
+			App.UI.DOM.appendNewElement("li", ngpInstructions, "Re-open the .html in a new tab then load the above save.", "note");
+			App.UI.DOM.appendNewElement(
+				"li",
+				ngpInstructions,
+				App.UI.DOM.link(
+					"Activate New Game Plus.",
+					() => {
+						V.ui = "start";
+					},
+					[],
+					"New Game Plus"
+				),
+				"note"
+			);
+			el.append(ngpInstructions);
+		} else {
+			App.UI.DOM.appendNewElement("div", el, `New Game Plus is not available because this game was not started with a compatible version.`, "note");
 		}
+		return el;
+	}
 
-		/**
-		 * Mark option as neutral to style differently.
-		 * @returns {Option}
-		 */
-		neutral() {
-			this.valuePairs.last().neutral = true;
-			return this;
+	function display() {
+		const el = new DocumentFragment();
+		let options;
+		let r;
+
+		App.UI.DOM.appendNewElement("h2", el, "Reports");
+
+		options = new App.UI.OptionsGroup();
+
+		options.addOption("End week report descriptive details are", "showEWD")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("End week report performance details are", "showEWM")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Master Suite report details such as slave changes are", "verboseDescriptions")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("End week societal effects from slaves are", "compressSocialEffects", V.UI)
+			.addValue("Expanded", 0).on().addValue("Compacted", 1).off();
+
+		options.addOption("Accordion on week end defaults to", "useAccordion")
+			.addValue("Open", 0).on().addValue("Collapsed", 1).off();
+
+		options.addOption("Economic Tabs on weekly reports are", "useTabs")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Economic detail sheets for facilities are", "showEconomicDetails")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Economic report neighbor details such as trade impacts on culture are", "showNeighborDetails")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Numeric formatting is currently", "formatNumbers")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("This will comma-format numbers in some areas.");
+
+		el.append(options.render());
+
+		App.UI.DOM.appendNewElement("h2", el, "General");
+
+		options = new App.UI.OptionsGroup();
+
+		options.addOption("Main menu leadership controls displayed", "positionMainLinks")
+			.addValueList([["Above", 1], ["Above and below", 0], ["Below", -1]]);
+
+		options.addOption("New Model UI", "newModelUI")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Penthouse Facility Display", "verticalizeArcologyLinks")
+			.addValueList([["Triple column", 3], ["Double Column", 2], ["Single Column", 1], ["Collapsed", 0]]);
+
+		options.addOption("Main menu arcology description", "seeArcology")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Main menu desk description", "seeDesk")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Main menu newsfeed", "seeFCNN")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Tips from the Encyclopedia are", "showTipsFromEncy")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Help tooltips are", "tooltipsEnabled")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment(`This is mostly for new players. <span class='exampleTooltip noteworthy'>Colored text</span> can have tooltips.`);
+
+		options.addOption("Main menu slave tabs are", "useSlaveSummaryTabs")
+			.addValue("Enabled", 1).on().addValue("CardStyle", 2).on().addValue("Disabled", 0).off();
+
+		options.addOption("The slave Quick list in-page scroll-to is", "useSlaveListInPageJSNavigation")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Condense special slaves into their own tab", "useSlaveSummaryOverviewTab")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Interactions with your fucktoys are", "fucktoyInteractionsPosition")
+			.addValueList([["next to them", 1], ["at page bottom", 0]]);
+
+		options.addOption("Hide tabs in Slave Interact", "slaveInteractLongForm")
+			.addValue("Enabled", true).on().addValue("Disabled", false).off();
+
+		options.addOption("Line separations are", "lineSeparations")
+			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
+
+		el.append(options.render());
+
+		r = [];
+		r.push(`UI theme selector. Allows to select a single CSS file to be loaded.`);
+		r.push(App.UI.DOM.makeElement("span", `The file has to be located in the same directory as the HTML file otherwise it will simply not load at all.`, "red"));
+		r.push(App.UI.Theme.selector());
+		App.Events.addParagraph(el, r);
+
+		App.UI.DOM.appendNewElement("h2", el, "Sidebar");
+
+		options = new App.UI.OptionsGroup();
+
+		options.addOption("Cash is", "Cash", V.sideBarOptions)
+			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
+
+		options.addOption("Upkeep is", "Upkeep", V.sideBarOptions)
+			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
+
+		options.addOption("Sex slave count is", "SexSlaveCount", V.sideBarOptions)
+			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
+
+		options.addOption("Room population is", "roomPop", V.sideBarOptions)
+			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
+
+		options.addOption("GSP is", "GSP", V.sideBarOptions)
+			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
+
+		options.addOption("Rep is", "Rep", V.sideBarOptions)
+			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
+
+		options.addOption("Confirmation before ending a week is", "confirmWeekEnd", V.sideBarOptions)
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("Enabling this will open a dialog box to confirm you meant to end a week.");
+
+		if (V.secExpEnabled > 0) {
+			options.addOption("Authority is", "Authority", V.sideBarOptions)
+				.addValue("Shown", 1).on().addValue("Hidden", 0).off();
+
+			options.addOption("Security is", "Security", V.sideBarOptions)
+				.addValue("Shown", 1).on().addValue("Hidden", 0).off();
+
+			options.addOption("Crime is", "Crime", V.sideBarOptions)
+				.addValue("Shown", 1).on().addValue("Hidden", 0).off();
 		}
 
-		/**
-		 * Puts the options in side a pulldown if there are at least 6.
-		 * Not counting text boxes or comments.
-		 * @returns {Option}
-		 */
-		pulldown() {
-			this.enablePulldown = true;
-			return this;
+		el.append(options.render());
+
+
+		App.UI.DOM.appendNewElement("h2", el, "Images");
+		el.append(App.UI.artOptions());
+
+		return el;
+	}
+
+	function contentFlavor() {
+		const el = new DocumentFragment();
+		let r;
+		let options;
+
+		App.UI.DOM.appendNewElement("h2", el, "Content");
+
+		r = [];
+		r.push("More granular control of what appears is in");
+		r.push(App.UI.DOM.passageLink("Description Options", "Description Options"));
+		App.Events.addNode(el, r, "div", "note");
+
+		options = new App.UI.OptionsGroup();
+
+		options.addOption("The difficulty setting is currently set to", "baseDifficulty")
+			.addValueList([["Very easy", 1], ["Easy", 2], ["Default", 3], ["Hard", 4], ["Very hard", 5]]);
+
+		options.addOption("Slaves falling ill is currently", "seeIllness")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("Will not affect existing ill slaves already in-game.");
+
+		options.addOption("Extreme content like amputation is currently", "seeExtreme")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("Will not affect extreme surgeries already applied in-game.");
+
+		options.addOption("Bestiality related content is currently", "seeBestiality")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Watersports related content is currently", "seePee")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Incest content is currently", "seeIncest")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Pregnancy related content is currently", "seePreg")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("Will not affect existing pregnancies already in-game.");
+
+		options.addOption("Child gender to be generated based off dick content settings", "seeDicksAffectsPregnancy")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment(`${(V.seeDicksAffectsPregnancy === 1) ? `Currently ${V.seeDicks}% of children will be born male. ` : ``}Will not affect existing pregnancies already in-game.`);
+
+		if (V.seeDicksAffectsPregnancy === 0) {
+			options.addOption("XX slaves only father daughters", "adamPrinciple")
+				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+				.addComment("Will not affect existing pregnancies already in-game.");
 		}
 
-		/**
-		 * @param {HTMLDivElement} container
-		 */
-		render(container) {
-			/* left side */
-			const desc = document.createElement("div");
-			desc.className = "description";
-			$(desc).wiki(this.description);
-			container.append(desc);
-
-			/* right side */
-			const currentValue = this.object[this.property];
-			let anySelected = false;
-
-			const buttonGroup = document.createElement("div");
-			buttonGroup.classList.add("button-group");
-			if (!this.enablePulldown || this.valuePairs.length < 6) {
-				for (const value of this.valuePairs) {
-					if (value.mode === "DOM") {
-						/* insert DOM and go to next element */
-						buttonGroup.append(value.value);
-						continue;
-					}
-					const button = document.createElement("button");
-					button.append(value.name);
-					if (value.on) {
-						button.classList.add("on");
-					} else if (value.off) {
-						button.classList.add("off");
-					} else if (value.neutral) {
-						button.classList.add("neutral");
-					}
-					if (value.mode === "custom") {
-						button.onclick = () => {
-							value.callback();
-							if (value.value) {
-								Engine.play(value.value);
-							} else {
-								App.UI.reload();
-							}
-						};
-					} else {
-						if (value.mode === "=" && currentValue === value.value) {
-							button.classList.add("selected", "disabled");
-							anySelected = true;
-							if (value.descAppend !== undefined) {
-								desc.append(" ");
-								$(desc).wiki(value.descAppend);
-							}
-						} else if (!anySelected && inRange(value.mode, value.compareValue, currentValue)) {
-							button.classList.add("selected");
-							// disable the button if clicking it won't change the variable value
-							if (currentValue === value.value) {
-								button.classList.add("disabled");
-							}
-							anySelected = true;
-							if (value.descAppend !== undefined) {
-								desc.append(" ");
-								$(desc).wiki(value.descAppend);
-							}
-						}
-						button.onclick = () => {
-							this.object[this.property] = value.value;
-							if (value.callback) {
-								value.callback();
-							}
-							App.UI.reload();
-						};
-					}
-					buttonGroup.append(button);
-				}
-			} else {
-				let matchFound = false;
-				let select = document.createElement("select");
-
-				for (const value of this.valuePairs) {
-					let el = document.createElement("option");
-					el.textContent = value.name;
-					el.value = value.value;
-					if (this.object[this.property] === value.value) {
-						el.selected = true;
-						matchFound = true;
-					}
-					select.appendChild(el);
-				}
-				if (!matchFound) {
-					select.selectedIndex = -1;
-				}
-				select.onchange = () => {
-					const O = select.options[select.selectedIndex];
-					if (isNaN(Number(O.value))) {
-						this.object[this.property] = O.value;
-					} else {
-						this.object[this.property] = Number(O.value);
-					}
-					const originalObj = this.valuePairs.find(obj => obj.name === O.textContent);
-					if (originalObj && typeof originalObj.callback === "function") {
-						originalObj.callback();
-					}
-					App.UI.reload();
-				};
-				buttonGroup.append(select);
+		options.addOption("Extreme pregnancy content like broodmothers is currently", "seeHyperPreg")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("Will not affect existing hyperpregnancies already in-game.");
+
+		options.addOption("Pregnancy complications due to multiples and body size are currently", "dangerousPregnancy")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption(`Precocious puberty (pregnancy younger than ${V.fertilityAge})`, "precociousPuberty")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("Will not affect existing precocious puberty cases already in-game.");
+
+		options.addOption("Slaves with fat lips or heavy oral piercings may lisp", "disableLisping")
+			.addValue("Yes", 0).on().addValue("No", 1).off();
+
+		options.addOption("Disables the long term damage mechanic. //Temp option//", "disableLongDamage")
+			.addValue("Enabled", 0).on().addValue("Disabled", 1).off();
+
+		options.addOption("Experimental male pronouns are currently", "diversePronouns")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("Apply Backwards Compatibility after changing to update slave's pronouns. Not all scenes support male pronouns and this is not yet incorporated into the lore or mechanics.");
+
+		options.addOption("Male slave names are currently", "allowMaleSlaveNames")
+			.addValue("Enabled", true).on().addValue("Disabled", false).off()
+			.addComment("This only affects slave generation and not your ability to name your slaves.");
+
+		options.addOption("Missing slave names are currently", "showMissingSlaves")
+			.addValue("Enabled", true).on().addValue("Disabled", false).off();
+
+		el.append(options.render());
+
+		App.UI.DOM.appendNewElement("h2", el, `Intersecting mechanics`);
+
+		options = new App.UI.OptionsGroup();
+
+		options.addOption("Slave assets affected by weight is", "weightAffectsAssets")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("Diet will still affect asset size.");
+
+		options.addOption("Curative side effects are", "curativeSideEffects")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("If enabled, curatives have a chance to give slaves harmful side effects.");
+
+		el.append(options.render());
+
+		App.UI.DOM.appendNewElement("h2", el, `Flavour`);
+
+		options = new App.UI.OptionsGroup();
+
+		options.addOption("Slave reactions to facility assignments are", "showAssignToScenes")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Post sex clean up", "postSexCleanUp")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Appraisal miniscenes on slave sale are", "showAppraisal")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Assignment performance vignettes on the end week report are", "showVignettes")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Slaves can have alternate titles", "newDescriptions")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Family titles for relatives", "allowFamilyTitles")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Limit family growth", "limitFamilies")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("Restricts acquisition of additional relatives, by means other than birth, for slaves with families.");
+
+		options.addOption("Distant relatives such as aunts, nieces and cousins are", "showDistantRelatives")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		el.append(options.render());
+		return el;
+	}
+
+	function mods() {
+		const el = new DocumentFragment();
+		let options;
+
+		options = new App.UI.OptionsGroup();
+
+		options.addOption("The Special Force Mod is currently", "Toggle", V.SF)
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.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().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>");
+
+		el.append(options.render());
+
+		if (V.secExpEnabled > 0) {
+			if (Object.values(V.SecExp).length === 0) {
+				App.SecExp.generalBC();
+				Engine.play("Options");
 			}
+			App.UI.DOM.appendNewElement("h2", el, `Security Expansion mod options`);
+			if (V.terrain === "oceanic") {
+				App.UI.DOM.appendNewElement("div", el, `Oceanic arcologies are not by default subject to external attacks. You can however allow them to happen anyway. If you choose to do so please keep in mind that descriptions and mechanics are not intended for naval combat but land combat.`);
+			}
+			options = new App.UI.OptionsGroup();
 
-			if (this.textbox) {
-				const isNumber = typeof currentValue === "number";
-				const textbox = App.UI.DOM.makeTextBox(currentValue, input => {
-					this.object[this.property] = input;
-					App.UI.reload();
-				}, isNumber);
-				if (isNumber) {
-					textbox.classList.add("number");
-				}
-				if (this.textbox.large) {
-					textbox.classList.add("full-width");
-				}
-				buttonGroup.append(textbox);
-				if (this.textbox.unit) {
-					buttonGroup.append(" ", this.textbox.unit);
-				}
+			if (V.SecExp.settings.battle.enabled > 0 || V.SecExp.settings.rebellion.enabled > 0) {
+				options.addOption("Detailed battle statistics are", "showStats", V.SecExp.settings)
+					.addValue("Shown", 1).on().addValue("Hidden", 0).off()
+					.addComment("Visibility of detailed statistics and battle turns.");
+
+				options.addOption("Difficulty is", "difficulty", V.SecExp.settings)
+					.addValueList([["Extremely hard", 2], ["Very hard", 1.5], ["Hard", 1.25], ["Normal", 1], ["Easy", 0.75], ["Very easy", 0.5]]);
+
+				options.addOption("Unit descriptions are", "unitDescriptions", V.SecExp.settings)
+					.addValue("Abbreviated", 1).addValue("Summarized", 0);
 			}
 
-			if (this.comment) {
-				const comment = document.createElement("span");
-				comment.classList.add("comment");
-				$(comment).wiki(this.comment);
-				buttonGroup.append(comment);
+			options.addOption("Battles are", "enabled", V.SecExp.settings.battle)
+				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+			options.addOption("Rebellions are", "enabled", V.SecExp.settings.rebellion)
+				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+			if (V.SecExp.settings.battle.enabled > 0) {
+				options.addOption("Battle frequency", "frequency", V.SecExp.settings.battle)
+					.addValueList([["Extremely high", 2], ["Very high", 1.5], ["High", 1.25], ["Normal", 1], ["Low", 0.75], ["Very low", 0.5]]);
 			}
-			container.append(buttonGroup);
-
-			function inRange(mode, compareValue, value) {
-				if (mode === "<") {
-					return value < compareValue;
-				} else if (mode === "<=") {
-					return value <= compareValue;
-				} else if (mode === ">") {
-					return value > compareValue;
-				} else if (mode === ">=") {
-					return value >= compareValue;
-				}
-				return false;
+
+			if (V.SecExp.settings.rebellion.enabled > 0) {
+				options.addOption("Rebellion buildup", "speed", V.SecExp.settings.rebellion)
+					.addValueList([["Extremely fast", 2], ["Very fast", 1.5], ["Fast", 1.25], ["Normal", 1], ["Slow", 0.75], ["Very slow", 0.5]]);
 			}
-		}
-	}
 
-	class Comment extends Row {
-		/**
-		 * @param {string} comment can be SC markup
-		 */
-		constructor(comment) {
-			super();
-			this.comment = comment;
-			this.long = false;
-		}
 
-		/**
-		 * @param {HTMLDivElement} container
-		 */
-		render(container) {
-			/* left */
-			container.append(document.createElement("div"));
-
-			/* right */
-			const comment = document.createElement("div");
-			comment.classList.add("comment");
-			$(comment).wiki(this.comment);
-			container.append(comment);
-		}
-	}
+			if (V.SecExp.settings.battle.enabled > 0) {
+				options.addOption("Commanders gain a prestige rank every 10 victories", "allowSlavePrestige", V.SecExp.settings.battle)
+					.addValue("Yes", 1).on().addValue("No", 0).off();
+			}
 
-	class CustomRow extends Row {
-		/**
-		 * @param {HTMLElement|string} element
-		 */
-		constructor(element) {
-			super();
-			this.element = element;
+			if (V.SecExp.settings.battle.enabled > 0) {
+				options.addOption("Force battles", "force", V.SecExp.settings.battle)
+					.addValue("Yes", 1).on().addValue("No", 0).off();
+			}
+			if (V.SecExp.settings.rebellion.enabled > 0) {
+				options.addOption("Force rebellions", "force", V.SecExp.settings.rebellion)
+					.addValue("Yes", 1).on().addValue("No", 0).off()
+					.addComment("Rebellions take precedence over Battles.");
+			}
+
+			if (V.SecExp.settings.battle.enabled > 0) {
+				options.addOption("Late game major battles are", "enabled", V.SecExp.settings.battle.major)
+					.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+			}
+
+			if (V.SecExp.settings.battle.enabled > 0 && V.SecExp.settings.battle.major.enabled > 0) {
+				options.addOption("Multiplier is", "mult", V.SecExp.settings.battle.major)
+					.addValueList([["Extremely high", 2], ["Very high", 1.5], ["High", 1.25], ["Normal", 1], ["Low", 0.75], ["Very low", 0.5]]);
+
+				options.addOption("This week a major battle is", "force", V.SecExp.settings.battle.major)
+					.addValue("Guaranteed", 1).on().addValue("Not guaranteed", 0).off();
+			}
+
+			if (V.SecExp.settings.battle.enabled > 0 && V.SecExp.settings.battle.major.enabled > 0) {
+				options.addOption("Gameover on battle loss", "gameOver", V.SecExp.settings.battle.major)
+					.addValue("Yes", 1).on().addValue("No", 0).off();
+			}
+
+			if (V.SecExp.settings.rebellion.enabled > 0) {
+				options.addOption("Gameover on rebellion loss", "gameOver", V.SecExp.settings.rebellion)
+					.addValue("Yes", 1).on().addValue("No", 0).off();
+			}
+
+			el.append(options.render());
+
+			const subHeading = document.createElement("div");
+			subHeading.classList.add("subHeading");
+
+			if (V.debugMode || V.cheatMode || V.cheatModeM) { // TODO make me a fucking function
+				App.UI.DOM.appendNewElement("div", subHeading, "Debug/cheat", "bold");
+				let td;
+				let links;
+				const table = document.createElement("table");
+				table.classList.add("invisible");
+				el.append(table);
+
+				let tr = document.createElement("tr");
+				tr.style.textAlign = "center";
+
+				td = createTd();
+				links = [];
+				links.push(
+					App.UI.DOM.link(
+						"Set loyalty high",
+						() => {
+							changeLoyalty("high");
+						},
+						[],
+						"Options"
+					)
+				);
+				links.push(
+					App.UI.DOM.link(
+						"Set loyalty average",
+						() => {
+							changeLoyalty("average");
+						},
+						[],
+						"Options"
+					)
+				);
+				links.push(
+					App.UI.DOM.link(
+						"Set loyalty low",
+						() => {
+							changeLoyalty("low");
+						},
+						[],
+						"Options"
+					)
+				);
+				links.push(
+					App.UI.DOM.link(
+						"Randomize loyalty",
+						() => {
+							changeLoyalty("random");
+						},
+						[],
+						"Options"
+					)
+				);
+
+				td.append(App.UI.DOM.generateLinksStrip(links));
+				tr.append(td);
+				table.append(tr);
+
+				tr = document.createElement("tr");
+				tr.style.textAlign = "center";
+				td = createTd();
+				links = [];
+				links.push(App.UI.DOM.link(
+					"Give Authority",
+					() => {
+						V.SecExp.core.authority = Math.clamp(V.SecExp.core.authority + 1000, 0, 20000);
+					},
+					[],
+					"Options"
+				));
+				links.push(App.UI.DOM.link(
+					"Remove Authority",
+					() => {
+						V.SecExp.core.authority = Math.clamp(V.SecExp.core.authority - 1000, 0, 20000);
+					},
+					[],
+					"Options"
+				));
+				td.append(App.UI.DOM.generateLinksStrip(links));
+				tr.append(td);
+				table.append(tr);
+
+
+				tr = document.createElement("tr");
+				td = document.createElement("td");
+				td.style.textAlign = "right";
+				links = [];
+				links.push(App.UI.DOM.link(
+					"Raise security",
+					() => {
+						V.SecExp.core.security = Math.clamp(V.SecExp.core.security + 5, 0, 100);
+					},
+					[],
+					"Options"
+				));
+				links.push(App.UI.DOM.link(
+					"Lower security",
+					() => {
+						V.SecExp.core.security = Math.clamp(V.SecExp.core.security - 5, 0, 100);
+					},
+					[],
+					"Options"
+				));
+				tr.append(App.UI.DOM.generateLinksStrip(links));
+				tr.append(td);
+
+				td = document.createElement("td");
+				td.style.textAlign = "left";
+				links = [];
+				links.push(App.UI.DOM.link(
+					"Raise crime",
+					() => {
+						V.SecExp.core.crimeLow = Math.clamp(V.SecExp.core.crimeLow + 5, 0, 100);
+					},
+					[],
+					"Options"
+				));
+				links.push(App.UI.DOM.link(
+					"Lower crime",
+					() => {
+						V.SecExp.core.crimeLow = Math.clamp(V.SecExp.core.crimeLow - 5, 0, 100);
+					},
+					[],
+					"Options"
+				));
+				tr.append(App.UI.DOM.generateLinksStrip(links));
+				tr.append(td);
+				table.append(tr);
+
+				tr = document.createElement("tr");
+				td = document.createElement("td");
+				td.style.textAlign = "right";
+				links = [];
+				links.push(App.UI.DOM.link(
+					"Give militia manpower",
+					() => {
+						V.SecExp.units.militia.free += 30;
+					},
+					[],
+					"Options"
+				));
+				links.push(App.UI.DOM.link(
+					"Remove militia manpower",
+					() => {
+						V.SecExp.units.militia.free = Math.max(V.SecExp.units.militia.free - 30, 0);
+					},
+					[],
+					"Options"
+				));
+				tr.append(App.UI.DOM.generateLinksStrip(links));
+				tr.append(td);
+
+				td = document.createElement("td");
+				td.style.textAlign = "left";
+				links = [];
+				links.push(App.UI.DOM.link(
+					"Give mercs manpower",
+					() => {
+						V.SecExp.units.mercs.free += 30;
+					},
+					[],
+					"Options"
+				));
+				links.push(App.UI.DOM.link(
+					"Remove mercs manpower",
+					() => {
+						V.SecExp.units.mercs.free = Math.max(V.SecExp.units.mercs.free - 30, 0);
+					},
+					[],
+					"Options"
+				));
+				tr.append(App.UI.DOM.generateLinksStrip(links));
+				tr.append(td);
+				table.append(tr);
+				subHeading.append(table);
+				el.append(subHeading);
+			}	/* closes cheatmode check */
+		} /* closes SecExp check*/
+		return el;
+
+		function createTd() {
+			const td = document.createElement("td");
+			td.style.columnSpan = "2";
+			return td;
 		}
 
 		/**
-		 * @param {HTMLDivElement} container
+		 *
+		 * @param {"high"|"average"|"low"|"random"} level
 		 */
-		render(container) {
-			/** @type {HTMLDivElement} */
-			const div = App.UI.DOM.makeElement("div", this.element, "custom-row");
-			container.append(div);
+		function changeLoyalty(level) {
+			const numberMap = new Map([
+				["high", [80, 100]],
+				["average", [40, 60]],
+				["low", [20]],
+				["random", [100]],
+			]);
+
+			for (const squad of App.SecExp.unit.humanSquads()) {
+				squad.loyalty = numberGenerator();
+			}
+
+			function numberGenerator() {
+				const range = numberMap.get(level);
+				if (range[1]) {
+					return random(range[0], range[1]);
+				} else {
+					return random(range[0]);
+				}
+			}
 		}
 	}
 
-	return class {
-		constructor() {
-			/**
-			 * @type {Array<Row>}
-			 */
-			this.rows = [];
-			this.doubleColumn = false;
+	function debugCheating() {
+		const el = new DocumentFragment();
+		let options;
+		let option;
+		let links;
+		let r;
+		const popCap = menialPopCap();
+
+		App.UI.DOM.appendNewElement("h2", el, `Debug`);
+
+		options = new App.UI.OptionsGroup();
+
+		options.addOption("DebugMode is", "debugMode")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("This will add a Display Variables and Bug Report passage to the sidebar.");
+
+		if (V.debugMode > 0) {
+			options.addOption("The custom function part of debug mode is", "debugModeCustomFunction")
+				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
 		}
 
-		/**
-		 * @returns {App.UI.OptionsGroup}
-		 */
-		enableDoubleColumn() {
-			this.doubleColumn = true;
-			return this;
+		option = options.addOption("Genetics array")
+			.customButton("Run test", () => { }, "test genetics");
+		if (V.cheatMode === 1) {
+			option.customButton("Edit Genetics", () => { }, "Edit Genetics");
+		} else {
+			option.addComment("Enable cheat mode to edit genetics.");
 		}
 
-		/**
-		 * @template {Row} T
-		 * @param {T} row
-		 * @returns {T}
-		 * @private
-		 */
-		_addRow(row) {
-			this.rows.push(row);
-			return row;
+		options.addOption("Rules Assistant").customButton("Reset Rules", () => { initRules(); }, "Rules Assistant");
+
+		options.addOption("Passage Profiler is", "profiler")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("Outputs performance data at the bottom of every passage.");
+
+		el.append(options.render());
+
+		App.UI.DOM.appendNewElement("h2", el, `Cheating`);
+
+		options = new App.UI.OptionsGroup();
+
+		options.addOption("CheatMode is", "cheatMode")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("This will allow manual selection of events and unlock some options that would usually be restricted by progress.");
+
+		if (V.cheatMode === 0) {
+			el.append(options.render());
+		} else {
+			options.addOption("Sidebar Cheats are currently", "cheatModeM")
+				.addValue("Shown", 1).on().addValue("Hidden", 0).off();
+
+			options.addOption("Slave aging", "seeAge")
+				.addValue("Enabled", 1).on().addValue("Celebrate birthdays, but don't age.", 2).neutral().addValue("Disabled", 0).off();
+
+			el.append(options.render());
+
+			links = [];
+
+			links.push(
+				App.UI.DOM.link(
+					`Add ${commaNum(100000)} money`,
+					() => {
+						V.cheater = 1;
+						cashX(100000, "cheating");
+					},
+					[],
+					"Options"
+				)
+			);
+
+			links.push(
+				App.UI.DOM.link(
+					`Add ${commaNum(10000)} rep`,
+					() => {
+						V.cheater = 1;
+						repX(10000, "cheating");
+					},
+					[],
+					"Options"
+				)
+			);
+
+			r = [];
+			r.push(App.UI.DOM.generateLinksStrip(links));
+			r.push(App.UI.DOM.makeElement("span", "Cheating will be flagged in your save", "note"));
+			App.Events.addNode(el, r, "div", "scLink2");
+
+
+			SectorCounts();
+
+			links = [];
+			links.push(
+				App.UI.DOM.link(
+					"Raise prosperity cap",
+					() => {
+						V.AProsperityCapModified += 10;
+					},
+					[],
+					"Options"
+				)
+			);
+
+			links.push(
+				App.UI.DOM.link(
+					"Lower prosperity cap",
+					() => {
+						V.AProsperityCapModified -= 10;
+					},
+					[],
+					"Options"
+				)
+			);
+			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links), "scLink2");
+
+
+			links = [];
+			links.push(
+				App.UI.DOM.link(
+					"Raise prosperity",
+					() => {
+						V.arcologies[0].prosperity = Math.clamp(V.arcologies[0].prosperity + 10, 0, V.AProsperityCap);
+					},
+					[],
+					"Options"
+				)
+			);
+
+			links.push(
+				App.UI.DOM.link(
+					"Lower prosperity",
+					() => {
+						V.arcologies[0].prosperity = Math.clamp(V.arcologies[0].prosperity - 10, 0, V.AProsperityCap);
+					},
+					[],
+					"Options"
+				)
+			);
+			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links), "scLink2");
+
+			links = [];
+			links.push(
+				App.UI.DOM.link(
+					"Give menial slaves",
+					() => {
+						V.menials = Math.clamp(V.menials + 30, 0, popCap.value);
+					},
+					[],
+					"Options"
+				)
+			);
+
+			links.push(
+				App.UI.DOM.link(
+					"Remove menial slaves",
+					() => {
+						V.menials = Math.clamp(V.menials - 30, 0, popCap.value);
+					},
+					[],
+					"Options"
+				)
+			);
+			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links), "scLink2");
+
+			links = [];
+
+			// Will no longer work as intended due to population changes
+			links.push(
+				App.UI.DOM.link(
+					"Add citizens",
+					() => {
+						V.lowerClass = Math.max(V.lowerClass + 200, 0);
+					},
+					[],
+					"Options"
+				)
+			);
+
+			// also no longer properly functional
+			links.push(
+				App.UI.DOM.link(
+					"Remove citizens",
+					() => {
+						V.lowerClass = Math.max(V.lowerClass - 200, 0);
+					},
+					[],
+					"Options"
+				)
+			);
+			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links), "scLink2");
+
+			links = [];
+			// Will work to a limited degree, minimums and maximums for slaves are set through population
+			links.push(
+				App.UI.DOM.link(
+					"Add slaves",
+					() => {
+						V.NPCSlaves = Math.max(V.NPCSlaves + 200, 0);
+					},
+					[],
+					"Options"
+				)
+			);
+
+			// Will work to a limited degree
+			links.push(
+				App.UI.DOM.link(
+					"Remove slaves",
+					() => {
+						V.NPCSlaves = Math.max(V.NPCSlaves - 200, 0);
+					},
+					[],
+					"Options"
+				)
+			);
+			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links), "scLink2");
 		}
+		return (el);
+	}
 
-		/**
-		 * @param {string} name
-		 * @param {string} property
-		 * @param {object} [object=V]
-		 * @returns {Option}
-		 */
-		addOption(name, property, object = V) {
-			const option = new Option(name, property, object);
-			return this._addRow(option);
+	function experimental() {
+		const el = new DocumentFragment();
+		let options;
+		let r;
+
+		r = [];
+		r.push(`Experimental means just that: experimental. Options below are likely to be in an`);
+		r.push(App.UI.DOM.makeElement("span", `even more incomplete or broken state than usual.`, "yellow"));
+		r.push(App.UI.DOM.makeElement("span", `THEY MAY NOT WORK AT ALL.`, "red"));
+		r.push(`Make sure you back up your save before enabling any of these, and if you are that interested, consider helping to improve them.`);
+		App.Events.addNode(el, r, "div", "bold");
+
+		options = new App.UI.OptionsGroup();
+
+		if (V.seePreg !== 0) {
+			options.addOption("Nursery is", "nursery", V.experimental)
+				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+				.addComment("This will enable the experimental nursery, which allows players to interact with growing slave children. An alternative to the incubator.");
 		}
 
-		/**
-		 * @param {string} comment may contain SC markup
-		 * @returns {Comment}
-		 */
-		addComment(comment) {
-			const c = new Comment(comment);
-			return this._addRow(c);
+		options.addOption("Food is", "food", V.experimental)
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+			.addComment("This will enable the experimental food supply and demand system, as well as a new farmyard building and assignments.");
+
+		if (V.seeExtreme === 1 && V.seeBestiality === 1) {
+			options.addOption("Animal Ovaries are", "animalOvaries", V.experimental)
+				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+				.addComment("This will allow slaves to be impregnated by animals.");
 		}
 
-		/**
-		 * Adds a custom element taking up both rows
-		 *
-		 * @param {HTMLElement|string} element
-		 * @returns {CustomRow}
-		 */
-		addCustom(element) {
-			return this._addRow(new CustomRow(element));
+		if (V.seeExtreme === 1) {
+			options.addOption("Dinner party", "dinnerParty", V.experimental)
+				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
+				.addComment("This will enable a controversial but very broken event. Warning: Snuff, cannibalism.");
 		}
 
-		/**
-		 * @returns {HTMLDivElement}
-		 */
-		render() {
-			const container = document.createElement("div");
-			container.className = "options-group";
-			if (this.doubleColumn) {
-				container.classList.add("double");
-			}
+		options.addOption("New event", "tempEventToggle")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
 
-			for (/** @type {Row} */ const row of this.rows) {
-				row.render(container, this.doubleColumn);
-			}
+		el.append(options.render());
+		return el;
+	}
+};
 
-			return container;
+App.UI.artOptions = function() {
+	const el = new DocumentFragment();
+	let options = new App.UI.OptionsGroup();
+
+	if (V.seeImages > 0) {
+		App.Events.drawEventArt(el, BaseSlave());
+	}
+
+	options.addOption("Images are", "seeImages")
+		.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+	if (V.seeImages > 0) {
+		options.addOption("Image style is", "imageChoice")
+			.addValueList([["Revamped embedded vector art", 3], ["Non-embedded vector art", 2], ["NoX/Deepmurk's vector art", 1], ["Shokushu's rendered imagepack", 0]]);
+
+		if (V.imageChoice === 1) {
+			options.addComment('<span class="warning">Git compiled only, no exceptions.</span>');
+
+			options.addOption("Face artwork is", "seeFaces")
+				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+			options.addOption("Highlights on shiny clothing are", "seeVectorArtHighlights")
+				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+			options.addOption("Height scaling", "seeHeight")
+				.addValue("All images", 2).on().addValue("Small images", 1).neutral().addValue("Disabled", 0).off();
+
+			options.addOption("Clothing erection bulges are", "showClothingErection")
+				.addValue("Enabled", true).on().addValue("Disabled", false).off();
+		} else if (V.imageChoice === 0) {
+			options.addComment(`You need """to"""
+				<a href="https://mega.nz/#!upoAlBaZ!EbZ5wCixxZxBhMN_ireJTXt0SIPOywO2JW9XzTIPhe0">download the image pack</a>
+				"""and""" put the 'renders' folder into the resources/ folder where this html file is.`
+			);
+
+			options.addOption("Slave summary fetish images are", "seeMainFetishes")
+				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+		} else if (V.imageChoice === 3) {
+			options.addComment('<span class="warning">Git compiled only, no exceptions.</span>');
+
+			options.addOption("Clothing erection bulges are", "showClothingErection")
+				.addValue("Enabled", true).on().addValue("Disabled", false).off();
 		}
-	};
-})();
+
+		options.addOption("PA avatar art is", "seeAvatar")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Slave images in lists are", "seeSummaryImages")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+
+		options.addOption("Slave images in the weekly report are", "seeReportImages")
+			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
+	}
+	el.append(options.render());
+	return el;
+};
diff --git a/src/gui/options/optionsGroup.js b/src/gui/options/optionsGroup.js
new file mode 100644
index 0000000000000000000000000000000000000000..a6ffd81760751d90cabb3ebeff05929bc7c4e08f
--- /dev/null
+++ b/src/gui/options/optionsGroup.js
@@ -0,0 +1,465 @@
+App.UI.OptionsGroup = (function() {
+	class Row {
+		/**
+		 * @param {HTMLDivElement} container
+		 */
+		render(container) {} // jshint ignore:line
+	}
+
+	/**
+	 * @typedef value
+	 * @property {*} value
+	 * @property {string} [name]
+	 * @property {string} mode
+	 * @property {number} [compareValue]
+	 * @property {string} [descAppend] can be SC markup
+	 * @property {boolean} [on]
+	 * @property {boolean} [off]
+	 * @property {boolean} [neutral]
+	 * @property {Function} [callback]
+	 */
+
+	class Option extends Row {
+		/**
+		 * @param {string} description can be SC markup
+		 * @param {string} property
+		 * @param {object} [object=V]
+		 */
+		constructor(description, property, object = V) {
+			super();
+			this.description = description;
+			this.property = property;
+			this.object = object;
+			/**
+			 * @type {Array<value>}
+			 */
+			this.valuePairs = [];
+		}
+
+		/**
+		 * @param {*} name
+		 * @param {*} [value=name]
+		 * @param {Function} [callback]
+		 * @returns {Option}
+		 */
+		addValue(name, value = name, callback = undefined) {
+			this.valuePairs.push({
+				name: name, value: value, mode: "=", callback: callback
+			});
+			return this;
+		}
+
+		/**
+		 * @param {Array<*|Array>} values
+		 * @returns {Option}
+		 */
+		addValueList(values) {
+			for (const value of values) {
+				if (Array.isArray(value)) {
+					this.addValue(value[0], value[1]);
+				} else {
+					this.addValue(value);
+				}
+			}
+			return this;
+		}
+
+		/**
+		 * @param {Map} values
+		 * @returns {Option}
+		 */
+		addValueMap(values) {
+			for (const [key, value] of values) {
+				this.addValue(key, value);
+			}
+			return this;
+		}
+
+		/**
+		 * @param {*} value
+		 * @param {number} compareValue
+		 * @param {string} mode on of: "<", "<=", ">", ">="
+		 * @param {string} [name=value]
+		 */
+		addRange(value, compareValue, mode, name = value) {
+			this.valuePairs.push({
+				name: name, value: value, mode: mode, compareValue: compareValue
+			});
+			return this;
+		}
+
+		/**
+		 * @param {Object} [params]
+		 * @param {string} [params.unit]
+		 * @param {boolean} [params.large=false]
+		 * @returns {Option}
+		 */
+		showTextBox({unit, large = false} = {}) {
+			this.textbox = {unit: unit, large: large};
+			return this;
+		}
+
+		/**
+		 * @param {string} comment can be SC markup
+		 * @returns {Option}
+		 */
+		addComment(comment) {
+			this.comment = comment;
+			return this;
+		}
+
+		/**
+		 * Adds a button that executes the callback when clicked AND reloads the passage
+		 *
+		 * @param {string} name
+		 * @param {Function} callback
+		 * @param {string} passage
+		 */
+		customButton(name, callback, passage) {
+			this.valuePairs.push({
+				name: name, value: passage, callback: callback, mode: "custom"
+			});
+			return this;
+		}
+
+		/**
+		 * @param {Node} node
+		 * @returns {Option}
+		 */
+		addCustomDOM(node) {
+			this.valuePairs.push({
+				value: node, mode: "DOM"
+			});
+			return this;
+		}
+
+		/* modify last added option */
+
+		/**
+		 * Added to the description if last added value is selected.
+		 * example use: addValue(...).customDescription(...).addValue(...).customDescription(...)
+		 * @param {string} description can be SC markup
+		 */
+		customDescription(description) {
+			this.valuePairs.last().descAppend = description;
+			return this;
+		}
+
+		/**
+		 * @param {Function} callback gets executed on every button click. Selected value is given as argument.
+		 */
+		addCallback(callback) {
+			this.valuePairs.last().callback = callback;
+			return this;
+		}
+
+		/**
+		 * @param {Function} callback gets executed on every button click. Selected value is given as argument.
+		 */
+		addCallbackToEach(callback) {
+			this.valuePairs.forEach(pair => pair.callback = callback);
+			return this;
+		}
+
+		/**
+		 * Mark option as on to style differently.
+		 * @returns {Option}
+		 */
+		on() {
+			this.valuePairs.last().on = true;
+			return this;
+		}
+
+		/**
+		 * Mark option as off to style differently.
+		 * @returns {Option}
+		 */
+		off() {
+			this.valuePairs.last().off = true;
+			return this;
+		}
+
+		/**
+		 * Mark option as neutral to style differently.
+		 * @returns {Option}
+		 */
+		neutral() {
+			this.valuePairs.last().neutral = true;
+			return this;
+		}
+
+		/**
+		 * Puts the options in side a pulldown if there are at least 6.
+		 * Not counting text boxes or comments.
+		 * @returns {Option}
+		 */
+		pulldown() {
+			this.enablePulldown = true;
+			return this;
+		}
+
+		/**
+		 * @param {HTMLDivElement} container
+		 */
+		render(container) {
+			/* left side */
+			const desc = document.createElement("div");
+			desc.className = "description";
+			$(desc).wiki(this.description);
+			container.append(desc);
+
+			/* right side */
+			const currentValue = this.object[this.property];
+			let anySelected = false;
+
+			const buttonGroup = document.createElement("div");
+			buttonGroup.classList.add("button-group");
+			if (!this.enablePulldown || this.valuePairs.length < 6) {
+				for (const value of this.valuePairs) {
+					if (value.mode === "DOM") {
+						/* insert DOM and go to next element */
+						buttonGroup.append(value.value);
+						continue;
+					}
+					const button = document.createElement("button");
+					button.append(value.name);
+					if (value.on) {
+						button.classList.add("on");
+					} else if (value.off) {
+						button.classList.add("off");
+					} else if (value.neutral) {
+						button.classList.add("neutral");
+					}
+					if (value.mode === "custom") {
+						button.onclick = () => {
+							value.callback();
+							if (value.value) {
+								Engine.play(value.value);
+							} else {
+								App.UI.reload();
+							}
+						};
+					} else {
+						if (value.mode === "=" && currentValue === value.value) {
+							button.classList.add("selected", "disabled");
+							anySelected = true;
+							if (value.descAppend !== undefined) {
+								desc.append(" ");
+								$(desc).wiki(value.descAppend);
+							}
+						} else if (!anySelected && inRange(value.mode, value.compareValue, currentValue)) {
+							button.classList.add("selected");
+							// disable the button if clicking it won't change the variable value
+							if (currentValue === value.value) {
+								button.classList.add("disabled");
+							}
+							anySelected = true;
+							if (value.descAppend !== undefined) {
+								desc.append(" ");
+								$(desc).wiki(value.descAppend);
+							}
+						}
+						button.onclick = () => {
+							this.object[this.property] = value.value;
+							if (value.callback) {
+								value.callback();
+							}
+							App.UI.reload();
+						};
+					}
+					buttonGroup.append(button);
+				}
+			} else {
+				let matchFound = false;
+				let select = document.createElement("select");
+
+				for (const value of this.valuePairs) {
+					let el = document.createElement("option");
+					el.textContent = value.name;
+					el.value = value.value;
+					if (this.object[this.property] === value.value) {
+						el.selected = true;
+						matchFound = true;
+					}
+					select.appendChild(el);
+				}
+				if (!matchFound) {
+					select.selectedIndex = -1;
+				}
+				select.onchange = () => {
+					const O = select.options[select.selectedIndex];
+					if (isNaN(Number(O.value))) {
+						this.object[this.property] = O.value;
+					} else {
+						this.object[this.property] = Number(O.value);
+					}
+					const originalObj = this.valuePairs.find(obj => obj.name === O.textContent);
+					if (originalObj && typeof originalObj.callback === "function") {
+						originalObj.callback();
+					}
+					App.UI.reload();
+				};
+				buttonGroup.append(select);
+			}
+
+			if (this.textbox) {
+				const isNumber = typeof currentValue === "number";
+				const textbox = App.UI.DOM.makeTextBox(currentValue, input => {
+					this.object[this.property] = input;
+					App.UI.reload();
+				}, isNumber);
+				if (isNumber) {
+					textbox.classList.add("number");
+				}
+				if (this.textbox.large) {
+					textbox.classList.add("full-width");
+				}
+				buttonGroup.append(textbox);
+				if (this.textbox.unit) {
+					buttonGroup.append(" ", this.textbox.unit);
+				}
+			}
+
+			if (this.comment) {
+				const comment = document.createElement("span");
+				comment.classList.add("comment");
+				$(comment).wiki(this.comment);
+				buttonGroup.append(comment);
+			}
+			container.append(buttonGroup);
+
+			function inRange(mode, compareValue, value) {
+				if (mode === "<") {
+					return value < compareValue;
+				} else if (mode === "<=") {
+					return value <= compareValue;
+				} else if (mode === ">") {
+					return value > compareValue;
+				} else if (mode === ">=") {
+					return value >= compareValue;
+				}
+				return false;
+			}
+		}
+	}
+
+	class Comment extends Row {
+		/**
+		 * @param {string} comment can be SC markup
+		 */
+		constructor(comment) {
+			super();
+			this.comment = comment;
+			this.long = false;
+		}
+
+		/**
+		 * @param {HTMLDivElement} container
+		 */
+		render(container) {
+			/* left */
+			container.append(document.createElement("div"));
+
+			/* right */
+			const comment = document.createElement("div");
+			comment.classList.add("comment");
+			$(comment).wiki(this.comment);
+			container.append(comment);
+		}
+	}
+
+	class CustomRow extends Row {
+		/**
+		 * @param {HTMLElement|string} element
+		 */
+		constructor(element) {
+			super();
+			this.element = element;
+		}
+
+		/**
+		 * @param {HTMLDivElement} container
+		 */
+		render(container) {
+			/** @type {HTMLDivElement} */
+			const div = App.UI.DOM.makeElement("div", this.element, "custom-row");
+			container.append(div);
+		}
+	}
+
+	return class {
+		constructor() {
+			/**
+			 * @type {Array<Row>}
+			 */
+			this.rows = [];
+			this.doubleColumn = false;
+		}
+
+		/**
+		 * @returns {App.UI.OptionsGroup}
+		 */
+		enableDoubleColumn() {
+			this.doubleColumn = true;
+			return this;
+		}
+
+		/**
+		 * @template {Row} T
+		 * @param {T} row
+		 * @returns {T}
+		 * @private
+		 */
+		_addRow(row) {
+			this.rows.push(row);
+			return row;
+		}
+
+		/**
+		 * @param {string} name
+		 * @param {string} property
+		 * @param {object} [object=V]
+		 * @returns {Option}
+		 */
+		addOption(name, property, object = V) {
+			const option = new Option(name, property, object);
+			return this._addRow(option);
+		}
+
+		/**
+		 * @param {string} comment may contain SC markup
+		 * @returns {Comment}
+		 */
+		addComment(comment) {
+			const c = new Comment(comment);
+			return this._addRow(c);
+		}
+
+		/**
+		 * Adds a custom element taking up both rows
+		 *
+		 * @param {HTMLElement|string} element
+		 * @returns {CustomRow}
+		 */
+		addCustom(element) {
+			return this._addRow(new CustomRow(element));
+		}
+
+		/**
+		 * @returns {HTMLDivElement}
+		 */
+		render() {
+			const container = document.createElement("div");
+			container.className = "options-group";
+			if (this.doubleColumn) {
+				container.classList.add("double");
+			}
+
+			for (/** @type {Row} */ const row of this.rows) {
+				row.render(container, this.doubleColumn);
+			}
+
+			return container;
+		}
+	};
+})();
diff --git a/src/gui/options/optionsPassage.js b/src/gui/options/optionsPassage.js
deleted file mode 100644
index 74cbea915f9176f506b76654c5beca92560d623e..0000000000000000000000000000000000000000
--- a/src/gui/options/optionsPassage.js
+++ /dev/null
@@ -1,1061 +0,0 @@
-App.UI.optionsPassage = function() {
-	const el = new DocumentFragment();
-	V.passageSwitchHandler = App.EventHandlers.optionsChanged;
-	el.append(intro());
-
-	// Results
-	const results = document.createElement("div");
-	results.id = "results";
-	el.append(results);
-
-	App.UI.tabBar.handlePreSelectedTab(V.tabChoice.Options);
-
-	// TODO: move me
-	/**
-	 *
-	 * @param {string} id
-	 * @param {Node} element
-	 * @returns {HTMLSpanElement}
-	 */
-	function makeSpanIded(id, element) {
-		const span = document.createElement("span");
-		span.id = id;
-		span.append(element);
-		return span;
-	}
-
-	const tabCaptions = {
-		"display": 'Display',
-		"contentFlavor": 'Content & flavour',
-		"mods": 'Mods',
-		"debugCheating": 'Debug & cheating',
-		"experimental": 'Experimental'
-	};
-
-	const tabBar = App.UI.DOM.appendNewElement("div", el, '', "tab-bar");
-	tabBar.append(
-		App.UI.tabBar.tabButton('display', tabCaptions.display),
-		App.UI.tabBar.tabButton('content-flavor', tabCaptions.contentFlavor),
-		App.UI.tabBar.tabButton('mods', tabCaptions.mods),
-		App.UI.tabBar.tabButton('debug-cheating', tabCaptions.debugCheating),
-		App.UI.tabBar.tabButton('experimental', tabCaptions.experimental),
-	);
-
-	el.append(App.UI.tabBar.makeTab('display', makeSpanIded("content-display", display())));
-	el.append(App.UI.tabBar.makeTab('content-flavor', makeSpanIded("content-content-flavor", contentFlavor())));
-	el.append(App.UI.tabBar.makeTab('mods', makeSpanIded("content-mods", mods())));
-	el.append(App.UI.tabBar.makeTab('debug-cheating', makeSpanIded("content-debug-cheating", debugCheating())));
-	el.append(App.UI.tabBar.makeTab('experimental', makeSpanIded("content-experimental", experimental())));
-
-	return el;
-
-	function intro() {
-		let links;
-		let options;
-		let r;
-		const el = new DocumentFragment();
-
-		options = new App.UI.OptionsGroup();
-		options.addOption("End of week autosaving is currently", "autosave")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-		el.append(options.render());
-
-		App.UI.DOM.appendNewElement("div", el, `This save was created using FC version ${V.ver} build ${V.releaseID}. You are currently playing version: ${App.Version.base}, mod version: ${App.Version.pmod}, build: ${App.Version.release}${App.Version.commitHash ? `, commit: ${App.Version.commitHash}` : ``}`);
-
-		links = [];
-		links.push(App.UI.DOM.passageLink("Apply Backwards Compatibility Update", "Backwards Compatibility"));
-
-		links.push(
-			App.UI.DOM.link(
-				`Reset extended family mode controllers`,
-				() => {
-					resetFamilyCounters();
-					const span = document.createElement("span");
-					span.classList.add("note");
-					App.UI.DOM.appendNewElement("span", span, "Done: ", "lightgreen");
-					span.append("all family relations flushed and rebuilt.");
-					jQuery("#results").empty().append(span);
-				},
-				[],
-				"",
-				"Clears and rebuilds .sister and .daughter tracking."
-			)
-		);
-
-
-		if (isNaN(V.rep)) {
-			links.push(
-				App.UI.DOM.link(
-					`Reset Reputation (${V.rep})`,
-					() => {
-						V.rep = 0;
-						jQuery("#results").empty().append(`Reputation reset to ${V.rep}`);
-					},
-					[],
-					"Options"
-				)
-			);
-		}
-
-		if (isNaN(V.rep)) {
-			links.push(
-				App.UI.DOM.link(
-					`Reset Money (${V.cash})`,
-					() => {
-						V.cash = 500;
-						jQuery("#results").empty().append(`Cash reset to ${V.cash}`);
-					},
-					[],
-					"Options"
-				)
-			);
-		}
-
-		if (V.releaseID === 1057) {
-			links.push(
-				App.UI.DOM.link(
-					`Free male anatomy removal due to accidentally flawed updater`,
-					() => {
-						V.PC.dick = 0;
-						V.PC.balls = 0;
-						V.PC.prostate = 0;
-						V.PC.scrotum = 0;
-						V.PC.ballsImplant = 0;
-						jQuery("#results").empty().append(`Cash reset to ${V.cash}`);
-					},
-					[],
-					"Options",
-					"Use this if your female PC picked up a few extra parts during the conversion process.",
-				)
-			);
-		}
-
-		App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links));
-
-		if ((V.releaseID >= 1000) || V.ver.startsWith("0.9") || V.ver.startsWith("0.8") || V.ver.startsWith("0.7") || V.ver.startsWith("0.6")) {
-			App.UI.DOM.appendNewElement("h3", el, `NEW GAME PLUS`);
-			r = [];
-			r.push(`You can begin a new game with up to five (or more) of your current slaves, although starting resources other than these slaves will be reduced. New Game Plus`);
-			r.push(App.UI.DOM.makeElement("span", "MAY", "yellow"));
-			r.push(`work across versions. To attempt to migrate a save across versions:`);
-			App.Events.addNode(el, r, "div", "note");
-
-			const ngpInstructions = document.createElement("ol");
-			App.UI.DOM.appendNewElement("li", ngpInstructions, "Save on this screen", "note");
-			App.UI.DOM.appendNewElement("li", ngpInstructions, "Re-open the .html in a new tab then load the above save.", "note");
-			App.UI.DOM.appendNewElement(
-				"li",
-				ngpInstructions,
-				App.UI.DOM.link(
-					"Activate New Game Plus.",
-					() => {
-						V.ui = "start";
-					},
-					[],
-					"New Game Plus"
-				),
-				"note"
-			);
-			el.append(ngpInstructions);
-		} else {
-			App.UI.DOM.appendNewElement("div", el, `New Game Plus is not available because this game was not started with a compatible version.`, "note");
-		}
-		return el;
-	}
-
-	function display() {
-		const el = new DocumentFragment();
-		let options;
-		let r;
-
-		App.UI.DOM.appendNewElement("h2", el, "Reports");
-
-		options = new App.UI.OptionsGroup();
-
-		options.addOption("End week report descriptive details are", "showEWD")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("End week report performance details are", "showEWM")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Master Suite report details such as slave changes are", "verboseDescriptions")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("End week societal effects from slaves are", "compressSocialEffects", V.UI)
-			.addValue("Expanded", 0).on().addValue("Compacted", 1).off();
-
-		options.addOption("Accordion on week end defaults to", "useAccordion")
-			.addValue("Open", 0).on().addValue("Collapsed", 1).off();
-
-		options.addOption("Economic Tabs on weekly reports are", "useTabs")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Economic detail sheets for facilities are", "showEconomicDetails")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Economic report neighbor details such as trade impacts on culture are", "showNeighborDetails")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Numeric formatting is currently", "formatNumbers")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("This will comma-format numbers in some areas.");
-
-		el.append(options.render());
-
-		App.UI.DOM.appendNewElement("h2", el, "General");
-
-		options = new App.UI.OptionsGroup();
-
-		options.addOption("Main menu leadership controls displayed", "positionMainLinks")
-			.addValueList([["Above", 1], ["Above and below", 0], ["Below", -1]]);
-
-		options.addOption("New Model UI", "newModelUI")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Penthouse Facility Display", "verticalizeArcologyLinks")
-			.addValueList([["Triple column", 3], ["Double Column", 2], ["Single Column", 1], ["Collapsed", 0]]);
-
-		options.addOption("Main menu arcology description", "seeArcology")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Main menu desk description", "seeDesk")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Main menu newsfeed", "seeFCNN")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Tips from the Encyclopedia are", "showTipsFromEncy")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Help tooltips are", "tooltipsEnabled")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment(`This is mostly for new players. <span class='exampleTooltip noteworthy'>Colored text</span> can have tooltips.`);
-
-		options.addOption("Main menu slave tabs are", "useSlaveSummaryTabs")
-			.addValue("Enabled", 1).on().addValue("CardStyle", 2).on().addValue("Disabled", 0).off();
-
-		options.addOption("The slave Quick list in-page scroll-to is", "useSlaveListInPageJSNavigation")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Condense special slaves into their own tab", "useSlaveSummaryOverviewTab")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Interactions with your fucktoys are", "fucktoyInteractionsPosition")
-			.addValueList([["next to them", 1], ["at page bottom", 0]]);
-
-		options.addOption("Hide tabs in Slave Interact", "slaveInteractLongForm")
-			.addValue("Enabled", true).on().addValue("Disabled", false).off();
-
-		options.addOption("Line separations are", "lineSeparations")
-			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-
-		el.append(options.render());
-
-		r = [];
-		r.push(`UI theme selector. Allows to select a single CSS file to be loaded.`);
-		r.push(App.UI.DOM.makeElement("span", `The file has to be located in the same directory as the HTML file otherwise it will simply not load at all.`, "red"));
-		r.push(App.UI.Theme.selector());
-		App.Events.addParagraph(el, r);
-
-		App.UI.DOM.appendNewElement("h2", el, "Sidebar");
-
-		options = new App.UI.OptionsGroup();
-
-		options.addOption("Cash is", "Cash", V.sideBarOptions)
-			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-
-		options.addOption("Upkeep is", "Upkeep", V.sideBarOptions)
-			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-
-		options.addOption("Sex slave count is", "SexSlaveCount", V.sideBarOptions)
-			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-
-		options.addOption("Room population is", "roomPop", V.sideBarOptions)
-			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-
-		options.addOption("GSP is", "GSP", V.sideBarOptions)
-			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-
-		options.addOption("Rep is", "Rep", V.sideBarOptions)
-			.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-
-		options.addOption("Confirmation before ending a week is", "confirmWeekEnd", V.sideBarOptions)
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("Enabling this will open a dialog box to confirm you meant to end a week.");
-
-		if (V.secExpEnabled > 0) {
-			options.addOption("Authority is", "Authority", V.sideBarOptions)
-				.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-
-			options.addOption("Security is", "Security", V.sideBarOptions)
-				.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-
-			options.addOption("Crime is", "Crime", V.sideBarOptions)
-				.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-		}
-
-		el.append(options.render());
-
-
-		App.UI.DOM.appendNewElement("h2", el, "Images");
-		el.append(App.UI.artOptions());
-
-		return el;
-	}
-
-	function contentFlavor() {
-		const el = new DocumentFragment();
-		let r;
-		let options;
-
-		App.UI.DOM.appendNewElement("h2", el, "Content");
-
-		r = [];
-		r.push("More granular control of what appears is in");
-		r.push(App.UI.DOM.passageLink("Description Options", "Description Options"));
-		App.Events.addNode(el, r, "div", "note");
-
-		options = new App.UI.OptionsGroup();
-
-		options.addOption("The difficulty setting is currently set to", "baseDifficulty")
-			.addValueList([["Very easy", 1], ["Easy", 2], ["Default", 3], ["Hard", 4], ["Very hard", 5]]);
-
-		options.addOption("Slaves falling ill is currently", "seeIllness")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("Will not affect existing ill slaves already in-game.");
-
-		options.addOption("Extreme content like amputation is currently", "seeExtreme")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("Will not affect extreme surgeries already applied in-game.");
-
-		options.addOption("Bestiality related content is currently", "seeBestiality")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Watersports related content is currently", "seePee")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Incest content is currently", "seeIncest")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Pregnancy related content is currently", "seePreg")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("Will not affect existing pregnancies already in-game.");
-
-		options.addOption("Child gender to be generated based off dick content settings", "seeDicksAffectsPregnancy")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment(`${(V.seeDicksAffectsPregnancy === 1) ? `Currently ${V.seeDicks}% of children will be born male. ` : ``}Will not affect existing pregnancies already in-game.`);
-
-		if (V.seeDicksAffectsPregnancy === 0) {
-			options.addOption("XX slaves only father daughters", "adamPrinciple")
-				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-				.addComment("Will not affect existing pregnancies already in-game.");
-		}
-
-		options.addOption("Extreme pregnancy content like broodmothers is currently", "seeHyperPreg")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("Will not affect existing hyperpregnancies already in-game.");
-
-		options.addOption("Pregnancy complications due to multiples and body size are currently", "dangerousPregnancy")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption(`Precocious puberty (pregnancy younger than ${V.fertilityAge})`, "precociousPuberty")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("Will not affect existing precocious puberty cases already in-game.");
-
-		options.addOption("Slaves with fat lips or heavy oral piercings may lisp", "disableLisping")
-			.addValue("Yes", 0).on().addValue("No", 1).off();
-
-		options.addOption("Disables the long term damage mechanic. //Temp option//", "disableLongDamage")
-			.addValue("Enabled", 0).on().addValue("Disabled", 1).off();
-
-		options.addOption("Experimental male pronouns are currently", "diversePronouns")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("Apply Backwards Compatibility after changing to update slave's pronouns. Not all scenes support male pronouns and this is not yet incorporated into the lore or mechanics.");
-
-		options.addOption("Male slave names are currently", "allowMaleSlaveNames")
-			.addValue("Enabled", true).on().addValue("Disabled", false).off()
-			.addComment("This only affects slave generation and not your ability to name your slaves.");
-
-		options.addOption("Missing slave names are currently", "showMissingSlaves")
-			.addValue("Enabled", true).on().addValue("Disabled", false).off();
-
-		el.append(options.render());
-
-		App.UI.DOM.appendNewElement("h2", el, `Intersecting mechanics`);
-
-		options = new App.UI.OptionsGroup();
-
-		options.addOption("Slave assets affected by weight is", "weightAffectsAssets")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("Diet will still affect asset size.");
-
-		options.addOption("Curative side effects are", "curativeSideEffects")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("If enabled, curatives have a chance to give slaves harmful side effects.");
-
-		el.append(options.render());
-
-		App.UI.DOM.appendNewElement("h2", el, `Flavour`);
-
-		options = new App.UI.OptionsGroup();
-
-		options.addOption("Slave reactions to facility assignments are", "showAssignToScenes")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Post sex clean up", "postSexCleanUp")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Appraisal miniscenes on slave sale are", "showAppraisal")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Assignment performance vignettes on the end week report are", "showVignettes")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Slaves can have alternate titles", "newDescriptions")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Family titles for relatives", "allowFamilyTitles")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Limit family growth", "limitFamilies")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("Restricts acquisition of additional relatives, by means other than birth, for slaves with families.");
-
-		options.addOption("Distant relatives such as aunts, nieces and cousins are", "showDistantRelatives")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		el.append(options.render());
-		return el;
-	}
-
-	function mods() {
-		const el = new DocumentFragment();
-		let options;
-
-		options = new App.UI.OptionsGroup();
-
-		options.addOption("The Special Force Mod is currently", "Toggle", V.SF)
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.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().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>");
-
-		el.append(options.render());
-
-		if (V.secExpEnabled > 0) {
-			if (Object.values(V.SecExp).length === 0) {
-				App.SecExp.generalBC();
-				Engine.play("Options");
-			}
-			App.UI.DOM.appendNewElement("h2", el, `Security Expansion mod options`);
-			if (V.terrain === "oceanic") {
-				App.UI.DOM.appendNewElement("div", el, `Oceanic arcologies are not by default subject to external attacks. You can however allow them to happen anyway. If you choose to do so please keep in mind that descriptions and mechanics are not intended for naval combat but land combat.`);
-			}
-			options = new App.UI.OptionsGroup();
-
-			if (V.SecExp.settings.battle.enabled > 0 || V.SecExp.settings.rebellion.enabled > 0) {
-				options.addOption("Detailed battle statistics are", "showStats", V.SecExp.settings)
-					.addValue("Shown", 1).on().addValue("Hidden", 0).off()
-					.addComment("Visibility of detailed statistics and battle turns.");
-
-				options.addOption("Difficulty is", "difficulty", V.SecExp.settings)
-					.addValueList([["Extremely hard", 2], ["Very hard", 1.5], ["Hard", 1.25], ["Normal", 1], ["Easy", 0.75], ["Very easy", 0.5]]);
-
-				options.addOption("Unit descriptions are", "unitDescriptions", V.SecExp.settings)
-					.addValue("Abbreviated", 1).addValue("Summarized", 0);
-			}
-
-			options.addOption("Battles are", "enabled", V.SecExp.settings.battle)
-				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-			options.addOption("Rebellions are", "enabled", V.SecExp.settings.rebellion)
-				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-			if (V.SecExp.settings.battle.enabled > 0) {
-				options.addOption("Battle frequency", "frequency", V.SecExp.settings.battle)
-					.addValueList([["Extremely high", 2], ["Very high", 1.5], ["High", 1.25], ["Normal", 1], ["Low", 0.75], ["Very low", 0.5]]);
-			}
-
-			if (V.SecExp.settings.rebellion.enabled > 0) {
-				options.addOption("Rebellion buildup", "speed", V.SecExp.settings.rebellion)
-					.addValueList([["Extremely fast", 2], ["Very fast", 1.5], ["Fast", 1.25], ["Normal", 1], ["Slow", 0.75], ["Very slow", 0.5]]);
-			}
-
-
-			if (V.SecExp.settings.battle.enabled > 0) {
-				options.addOption("Commanders gain a prestige rank every 10 victories", "allowSlavePrestige", V.SecExp.settings.battle)
-					.addValue("Yes", 1).on().addValue("No", 0).off();
-			}
-
-			if (V.SecExp.settings.battle.enabled > 0) {
-				options.addOption("Force battles", "force", V.SecExp.settings.battle)
-					.addValue("Yes", 1).on().addValue("No", 0).off();
-			}
-			if (V.SecExp.settings.rebellion.enabled > 0) {
-				options.addOption("Force rebellions", "force", V.SecExp.settings.rebellion)
-					.addValue("Yes", 1).on().addValue("No", 0).off()
-					.addComment("Rebellions take precedence over Battles.");
-			}
-
-			if (V.SecExp.settings.battle.enabled > 0) {
-				options.addOption("Late game major battles are", "enabled", V.SecExp.settings.battle.major)
-					.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-			}
-
-			if (V.SecExp.settings.battle.enabled > 0 && V.SecExp.settings.battle.major.enabled > 0) {
-				options.addOption("Multiplier is", "mult", V.SecExp.settings.battle.major)
-					.addValueList([["Extremely high", 2], ["Very high", 1.5], ["High", 1.25], ["Normal", 1], ["Low", 0.75], ["Very low", 0.5]]);
-
-				options.addOption("This week a major battle is", "force", V.SecExp.settings.battle.major)
-					.addValue("Guaranteed", 1).on().addValue("Not guaranteed", 0).off();
-			}
-
-			if (V.SecExp.settings.battle.enabled > 0 && V.SecExp.settings.battle.major.enabled > 0) {
-				options.addOption("Gameover on battle loss", "gameOver", V.SecExp.settings.battle.major)
-					.addValue("Yes", 1).on().addValue("No", 0).off();
-			}
-
-			if (V.SecExp.settings.rebellion.enabled > 0) {
-				options.addOption("Gameover on rebellion loss", "gameOver", V.SecExp.settings.rebellion)
-					.addValue("Yes", 1).on().addValue("No", 0).off();
-			}
-
-			el.append(options.render());
-
-			const subHeading = document.createElement("div");
-			subHeading.classList.add("subHeading");
-
-			if (V.debugMode || V.cheatMode || V.cheatModeM) { // TODO make me a fucking function
-				App.UI.DOM.appendNewElement("div", subHeading, "Debug/cheat", "bold");
-				let td;
-				let links;
-				const table = document.createElement("table");
-				table.classList.add("invisible");
-				el.append(table);
-
-				let tr = document.createElement("tr");
-				tr.style.textAlign = "center";
-
-				td = createTd();
-				links = [];
-				links.push(
-					App.UI.DOM.link(
-						"Set loyalty high",
-						() => {
-							changeLoyalty("high");
-						},
-						[],
-						"Options"
-					)
-				);
-				links.push(
-					App.UI.DOM.link(
-						"Set loyalty average",
-						() => {
-							changeLoyalty("average");
-						},
-						[],
-						"Options"
-					)
-				);
-				links.push(
-					App.UI.DOM.link(
-						"Set loyalty low",
-						() => {
-							changeLoyalty("low");
-						},
-						[],
-						"Options"
-					)
-				);
-				links.push(
-					App.UI.DOM.link(
-						"Randomize loyalty",
-						() => {
-							changeLoyalty("random");
-						},
-						[],
-						"Options"
-					)
-				);
-
-				td.append(App.UI.DOM.generateLinksStrip(links));
-				tr.append(td);
-				table.append(tr);
-
-				tr = document.createElement("tr");
-				tr.style.textAlign = "center";
-				td = createTd();
-				links = [];
-				links.push(App.UI.DOM.link(
-					"Give Authority",
-					() => {
-						V.SecExp.core.authority = Math.clamp(V.SecExp.core.authority + 1000, 0, 20000);
-					},
-					[],
-					"Options"
-				));
-				links.push(App.UI.DOM.link(
-					"Remove Authority",
-					() => {
-						V.SecExp.core.authority = Math.clamp(V.SecExp.core.authority - 1000, 0, 20000);
-					},
-					[],
-					"Options"
-				));
-				td.append(App.UI.DOM.generateLinksStrip(links));
-				tr.append(td);
-				table.append(tr);
-
-
-				tr = document.createElement("tr");
-				td = document.createElement("td");
-				td.style.textAlign = "right";
-				links = [];
-				links.push(App.UI.DOM.link(
-					"Raise security",
-					() => {
-						V.SecExp.core.security = Math.clamp(V.SecExp.core.security + 5, 0, 100);
-					},
-					[],
-					"Options"
-				));
-				links.push(App.UI.DOM.link(
-					"Lower security",
-					() => {
-						V.SecExp.core.security = Math.clamp(V.SecExp.core.security - 5, 0, 100);
-					},
-					[],
-					"Options"
-				));
-				tr.append(App.UI.DOM.generateLinksStrip(links));
-				tr.append(td);
-
-				td = document.createElement("td");
-				td.style.textAlign = "left";
-				links = [];
-				links.push(App.UI.DOM.link(
-					"Raise crime",
-					() => {
-						V.SecExp.core.crimeLow = Math.clamp(V.SecExp.core.crimeLow + 5, 0, 100);
-					},
-					[],
-					"Options"
-				));
-				links.push(App.UI.DOM.link(
-					"Lower crime",
-					() => {
-						V.SecExp.core.crimeLow = Math.clamp(V.SecExp.core.crimeLow - 5, 0, 100);
-					},
-					[],
-					"Options"
-				));
-				tr.append(App.UI.DOM.generateLinksStrip(links));
-				tr.append(td);
-				table.append(tr);
-
-				tr = document.createElement("tr");
-				td = document.createElement("td");
-				td.style.textAlign = "right";
-				links = [];
-				links.push(App.UI.DOM.link(
-					"Give militia manpower",
-					() => {
-						V.SecExp.units.militia.free += 30;
-					},
-					[],
-					"Options"
-				));
-				links.push(App.UI.DOM.link(
-					"Remove militia manpower",
-					() => {
-						V.SecExp.units.militia.free = Math.max(V.SecExp.units.militia.free - 30, 0);
-					},
-					[],
-					"Options"
-				));
-				tr.append(App.UI.DOM.generateLinksStrip(links));
-				tr.append(td);
-
-				td = document.createElement("td");
-				td.style.textAlign = "left";
-				links = [];
-				links.push(App.UI.DOM.link(
-					"Give mercs manpower",
-					() => {
-						V.SecExp.units.mercs.free += 30;
-					},
-					[],
-					"Options"
-				));
-				links.push(App.UI.DOM.link(
-					"Remove mercs manpower",
-					() => {
-						V.SecExp.units.mercs.free = Math.max(V.SecExp.units.mercs.free - 30, 0);
-					},
-					[],
-					"Options"
-				));
-				tr.append(App.UI.DOM.generateLinksStrip(links));
-				tr.append(td);
-				table.append(tr);
-				subHeading.append(table);
-				el.append(subHeading);
-			}	/* closes cheatmode check */
-		} /* closes SecExp check*/
-		return el;
-
-		function createTd() {
-			const td = document.createElement("td");
-			td.style.columnSpan = "2";
-			return td;
-		}
-
-		/**
-		 *
-		 * @param {"high"|"average"|"low"|"random"} level
-		 */
-		function changeLoyalty(level) {
-			const numberMap = new Map([
-				["high", [80, 100]],
-				["average", [40, 60]],
-				["low", [20]],
-				["random", [100]],
-			]);
-
-			for (const squad of App.SecExp.unit.humanSquads()) {
-				squad.loyalty = numberGenerator();
-			}
-
-			function numberGenerator() {
-				const range = numberMap.get(level);
-				if (range[1]) {
-					return random(range[0], range[1]);
-				} else {
-					return random(range[0]);
-				}
-			}
-		}
-	}
-
-	function debugCheating() {
-		const el = new DocumentFragment();
-		let options;
-		let option;
-		let links;
-		let r;
-		const popCap = menialPopCap();
-
-		App.UI.DOM.appendNewElement("h2", el, `Debug`);
-
-		options = new App.UI.OptionsGroup();
-
-		options.addOption("DebugMode is", "debugMode")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("This will add a Display Variables and Bug Report passage to the sidebar.");
-
-		if (V.debugMode > 0) {
-			options.addOption("The custom function part of debug mode is", "debugModeCustomFunction")
-				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-		}
-
-		option = options.addOption("Genetics array")
-			.customButton("Run test", () => { }, "test genetics");
-		if (V.cheatMode === 1) {
-			option.customButton("Edit Genetics", () => { }, "Edit Genetics");
-		} else {
-			option.addComment("Enable cheat mode to edit genetics.");
-		}
-
-		options.addOption("Rules Assistant").customButton("Reset Rules", () => { initRules(); }, "Rules Assistant");
-
-		options.addOption("Passage Profiler is", "profiler")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("Outputs performance data at the bottom of every passage.");
-
-		el.append(options.render());
-
-		App.UI.DOM.appendNewElement("h2", el, `Cheating`);
-
-		options = new App.UI.OptionsGroup();
-
-		options.addOption("CheatMode is", "cheatMode")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("This will allow manual selection of events and unlock some options that would usually be restricted by progress.");
-
-		if (V.cheatMode === 0) {
-			el.append(options.render());
-		} else {
-			options.addOption("Sidebar Cheats are currently", "cheatModeM")
-				.addValue("Shown", 1).on().addValue("Hidden", 0).off();
-
-			options.addOption("Slave aging", "seeAge")
-				.addValue("Enabled", 1).on().addValue("Celebrate birthdays, but don't age.", 2).neutral().addValue("Disabled", 0).off();
-
-			el.append(options.render());
-
-			links = [];
-
-			links.push(
-				App.UI.DOM.link(
-					`Add ${commaNum(100000)} money`,
-					() => {
-						V.cheater = 1;
-						cashX(100000, "cheating");
-					},
-					[],
-					"Options"
-				)
-			);
-
-			links.push(
-				App.UI.DOM.link(
-					`Add ${commaNum(10000)} rep`,
-					() => {
-						V.cheater = 1;
-						repX(10000, "cheating");
-					},
-					[],
-					"Options"
-				)
-			);
-
-			r = [];
-			r.push(App.UI.DOM.generateLinksStrip(links));
-			r.push(App.UI.DOM.makeElement("span", "Cheating will be flagged in your save", "note"));
-			App.Events.addNode(el, r, "div", "scLink2");
-
-
-			SectorCounts();
-
-			links = [];
-			links.push(
-				App.UI.DOM.link(
-					"Raise prosperity cap",
-					() => {
-						V.AProsperityCapModified += 10;
-					},
-					[],
-					"Options"
-				)
-			);
-
-			links.push(
-				App.UI.DOM.link(
-					"Lower prosperity cap",
-					() => {
-						V.AProsperityCapModified -= 10;
-					},
-					[],
-					"Options"
-				)
-			);
-			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links), "scLink2");
-
-
-			links = [];
-			links.push(
-				App.UI.DOM.link(
-					"Raise prosperity",
-					() => {
-						V.arcologies[0].prosperity = Math.clamp(V.arcologies[0].prosperity + 10, 0, V.AProsperityCap);
-					},
-					[],
-					"Options"
-				)
-			);
-
-			links.push(
-				App.UI.DOM.link(
-					"Lower prosperity",
-					() => {
-						V.arcologies[0].prosperity = Math.clamp(V.arcologies[0].prosperity - 10, 0, V.AProsperityCap);
-					},
-					[],
-					"Options"
-				)
-			);
-			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links), "scLink2");
-
-			links = [];
-			links.push(
-				App.UI.DOM.link(
-					"Give menial slaves",
-					() => {
-						V.menials = Math.clamp(V.menials + 30, 0, popCap.value);
-					},
-					[],
-					"Options"
-				)
-			);
-
-			links.push(
-				App.UI.DOM.link(
-					"Remove menial slaves",
-					() => {
-						V.menials = Math.clamp(V.menials - 30, 0, popCap.value);
-					},
-					[],
-					"Options"
-				)
-			);
-			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links), "scLink2");
-
-			links = [];
-
-			// Will no longer work as intended due to population changes
-			links.push(
-				App.UI.DOM.link(
-					"Add citizens",
-					() => {
-						V.lowerClass = Math.max(V.lowerClass + 200, 0);
-					},
-					[],
-					"Options"
-				)
-			);
-
-			// also no longer properly functional
-			links.push(
-				App.UI.DOM.link(
-					"Remove citizens",
-					() => {
-						V.lowerClass = Math.max(V.lowerClass - 200, 0);
-					},
-					[],
-					"Options"
-				)
-			);
-			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links), "scLink2");
-
-			links = [];
-			// Will work to a limited degree, minimums and maximums for slaves are set through population
-			links.push(
-				App.UI.DOM.link(
-					"Add slaves",
-					() => {
-						V.NPCSlaves = Math.max(V.NPCSlaves + 200, 0);
-					},
-					[],
-					"Options"
-				)
-			);
-
-			// Will work to a limited degree
-			links.push(
-				App.UI.DOM.link(
-					"Remove slaves",
-					() => {
-						V.NPCSlaves = Math.max(V.NPCSlaves - 200, 0);
-					},
-					[],
-					"Options"
-				)
-			);
-			App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(links), "scLink2");
-		}
-		return (el);
-	}
-
-	function experimental() {
-		const el = new DocumentFragment();
-		let options;
-		let r;
-
-		r = [];
-		r.push(`Experimental means just that: experimental. Options below are likely to be in an`);
-		r.push(App.UI.DOM.makeElement("span", `even more incomplete or broken state than usual.`, "yellow"));
-		r.push(App.UI.DOM.makeElement("span", `THEY MAY NOT WORK AT ALL.`, "red"));
-		r.push(`Make sure you back up your save before enabling any of these, and if you are that interested, consider helping to improve them.`);
-		App.Events.addNode(el, r, "div", "bold");
-
-		options = new App.UI.OptionsGroup();
-
-		if (V.seePreg !== 0) {
-			options.addOption("Nursery is", "nursery", V.experimental)
-				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-				.addComment("This will enable the experimental nursery, which allows players to interact with growing slave children. An alternative to the incubator.");
-		}
-
-		options.addOption("Food is", "food", V.experimental)
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-			.addComment("This will enable the experimental food supply and demand system, as well as a new farmyard building and assignments.");
-
-		if (V.seeExtreme === 1 && V.seeBestiality === 1) {
-			options.addOption("Animal Ovaries are", "animalOvaries", V.experimental)
-				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-				.addComment("This will allow slaves to be impregnated by animals.");
-		}
-
-		if (V.seeExtreme === 1) {
-			options.addOption("Dinner party", "dinnerParty", V.experimental)
-				.addValue("Enabled", 1).on().addValue("Disabled", 0).off()
-				.addComment("This will enable a controversial but very broken event. Warning: Snuff, cannibalism.");
-		}
-
-		options.addOption("New event", "tempEventToggle")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		el.append(options.render());
-		return el;
-	}
-};
-
-App.UI.artOptions = function() {
-	const el = new DocumentFragment();
-	let options = new App.UI.OptionsGroup();
-
-	if (V.seeImages > 0) {
-		App.Events.drawEventArt(el, BaseSlave());
-	}
-
-	options.addOption("Images are", "seeImages")
-		.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-	if (V.seeImages > 0) {
-		options.addOption("Image style is", "imageChoice")
-			.addValueList([["Revamped embedded vector art", 3], ["Non-embedded vector art", 2], ["NoX/Deepmurk's vector art", 1], ["Shokushu's rendered imagepack", 0]]);
-
-		if (V.imageChoice === 1) {
-			options.addComment('<span class="warning">Git compiled only, no exceptions.</span>');
-
-			options.addOption("Face artwork is", "seeFaces")
-				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-			options.addOption("Highlights on shiny clothing are", "seeVectorArtHighlights")
-				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-			options.addOption("Height scaling", "seeHeight")
-				.addValue("All images", 2).on().addValue("Small images", 1).neutral().addValue("Disabled", 0).off();
-
-			options.addOption("Clothing erection bulges are", "showClothingErection")
-				.addValue("Enabled", true).on().addValue("Disabled", false).off();
-		} else if (V.imageChoice === 0) {
-			options.addComment(`You need """to"""
-				<a href="https://mega.nz/#!upoAlBaZ!EbZ5wCixxZxBhMN_ireJTXt0SIPOywO2JW9XzTIPhe0">download the image pack</a>
-				"""and""" put the 'renders' folder into the resources/ folder where this html file is.`
-			);
-
-			options.addOption("Slave summary fetish images are", "seeMainFetishes")
-				.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-		} else if (V.imageChoice === 3) {
-			options.addComment('<span class="warning">Git compiled only, no exceptions.</span>');
-
-			options.addOption("Clothing erection bulges are", "showClothingErection")
-				.addValue("Enabled", true).on().addValue("Disabled", false).off();
-		}
-
-		options.addOption("PA avatar art is", "seeAvatar")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Slave images in lists are", "seeSummaryImages")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-
-		options.addOption("Slave images in the weekly report are", "seeReportImages")
-			.addValue("Enabled", 1).on().addValue("Disabled", 0).off();
-	}
-	el.append(options.render());
-	return el;
-};
diff --git a/src/interaction/siWardrobe.js b/src/interaction/siWardrobe.js
index 167dbaa3b3eaaa7957b0a73107b87fb0b3bc4177..6cccc2fa78b5132a69ca736edbc739b0c3682d55 100644
--- a/src/interaction/siWardrobe.js
+++ b/src/interaction/siWardrobe.js
@@ -4,40 +4,133 @@ App.UI.SlaveInteract.wardrobe = function(slave) {
 		him,
 		his,
 	} = getPronouns(slave);
-	const frag = new DocumentFragment();
-	frag.append(clothes());
-	if (slave.fuckdoll === 0) {
-		frag.append(collar());
-		frag.append(mask());
-		frag.append(mouth());
-		frag.append(armAccessory());
-		frag.append(shoes());
-		frag.append(legAccessory());
-		frag.append(bellyAccessory());
-		frag.append(buttplug());
-		frag.append(buttplugAttachment());
-		frag.append(vaginalAccessory());
-		frag.append(vaginalAttachment());
-		frag.append(dickAccessory());
-		frag.append(chastity());
+	let filters = {};
+	const el = document.createElement("span");
+	el.id = "content";
+	el.append(contents())
+	return el;
+
+
+	function contents() {
+		const frag = new DocumentFragment();
+		if (slave.fuckdoll === 0) {
+			frag.append(filtersDOM());
+			frag.append(clothes());
+			frag.append(mask());
+			frag.append(mouth());
+			frag.append(armAccessory());
+			frag.append(shoes());
+			frag.append(legAccessory());
+			frag.append(bellyAccessory());
+			frag.append(buttplug());
+			frag.append(buttplugAttachment());
+			frag.append(vaginalAccessory());
+			frag.append(vaginalAttachment());
+			frag.append(dickAccessory());
+			frag.append(chastity());
+		} else {
+			frag.append(clothes());
+		}
+
+		App.UI.DOM.appendNewElement("h3", frag, `Shopping`);
+		frag.append(shopping());
+	
+		return frag;
 	}
 
-	App.UI.DOM.appendNewElement("h3", frag, `Shopping`);
-	frag.append(shopping());
+	function filtersDOM() {
+		const el = document.createElement("p");
+		el.append("Filters: ");
+
+		const niceFilters = new Map([
+			[false, "Nice"],
+			[true, "Harsh"],
+		]);
+		let linkArray = [];
+		for (const [bool, string] of niceFilters) {
+			if (filters.harsh === bool) {
+				linkArray.push(
+					App.UI.DOM.disabledLink(
+						string,
+						["Currently selected"]
+					)
+				);
+			} else {
+				linkArray.push(
+					App.UI.DOM.link(
+						string,
+						() => {
+							filters.harsh = bool;
+							refresh();
+						}
+					)
+				);
+			}
+		}
+		App.UI.DOM.appendNewElement("span", el, App.UI.DOM.generateLinksStrip(linkArray));
+
+		el.append(" / ");
+		const exposureFilters = new Map([
+			[0, "Modest"],
+			[1, "Normal"],
+			[2, "Slutty"],
+			[3, "Humiliating"],
+			[4, "Practically nude"],
+		]);
+		linkArray = [];
+		for (const [num, string] of exposureFilters) {
+			if (filters.exposure === num) {
+				linkArray.push(
+					App.UI.DOM.disabledLink(
+						string,
+						["Currently selected"]
+					)
+				);
+			} else {
+				linkArray.push(
+					App.UI.DOM.link(
+						string,
+						() => {
+							filters.exposure = num;
+							refresh();
+						}
+					)
+				);
+			}
+		}
+		App.UI.DOM.appendNewElement("span", el, App.UI.DOM.generateLinksStrip(linkArray));
+		el.append(" / ");
 
-	return frag;
+		App.UI.DOM.appendNewElement("span", el, App.UI.DOM.link(
+			"Reset Filters",
+			() => {
+				filters = {};
+				refresh();
+			}
+		)); // clear filters
+		App.UI.DOM.appendNewElement("hr", el);
+		return el;
+	}
 
 	function clothes() {
 		const el = document.createElement('div');
 		let links;
 		if (slave.fuckdoll === 0) {
+			// First Row
 			let label = document.createElement('div');
 			label.append(`Clothes: `);
 
-			let choice = App.UI.DOM.disabledLink(`${slave.clothes}`, [clothTooltip(`${slave.clothes}`)]);
+			let choice = App.UI.DOM.disabledLink(`${slave.clothes} `, [clothTooltip(`${slave.clothes}`)]);
 			choice.style.fontWeight = "bold";
 			label.appendChild(choice);
 
+			if (slave.fuckdoll !== 0 || slave.clothes === "restrictive latex" || slave.clothes === "a latex catsuit" || slave.clothes === "a cybersuit" || slave.clothes === "a comfortable bodysuit") {
+				if (V.seeImages === 1 && V.imageChoice === 1) {
+					// Color options
+					label.appendChild(colorOptions("clothingBaseColor"));
+				}
+			}
+
 			// Choose her own
 			if (slave.clothes !== `choosing her own clothes`) {
 				let choiceOptionsArray = [];
@@ -45,105 +138,89 @@ App.UI.SlaveInteract.wardrobe = function(slave) {
 				label.appendChild(generateRows(choiceOptionsArray, "clothes", false));
 			}
 			el.appendChild(label);
+			links = App.UI.DOM.appendNewElement("div", el, clothingSelection());
+			links.id = "clothing-selection";
+		}
+
+		const label = document.createElement('div');
+		label.append(`Collar: `);
+		let choice = App.UI.DOM.disabledLink(`${slave.collar}`, [clothTooltip(`${slave.collar}`)]);
+		choice.style.fontWeight = "bold";
+		label.appendChild(choice);
+		// Choose her own
+		if (slave.collar !== `none`) {
+			let choiceOptionsArray = [];
+			choiceOptionsArray.push({text: ` None`, updateSlave: {collar: `none`}});
+			label.appendChild(generateRows(choiceOptionsArray, "collar", false));
+		}
+		el.appendChild(label);
 
+		links = App.UI.DOM.appendNewElement("div", el, collar());
+		links.id = "collar-selection";
 
-			let niceOptionsArray = [];
-			let harshOptionsArray = [];
+		return el;
+
+		function clothingSelection() {
+			const el = new DocumentFragment();
+			let array = [];
 
 			for (const [key, object] of App.Data.clothes) {
 				if (key === "choosing her own clothes") {
 					continue;
 				}
+				if (filters.hasOwnProperty("exposure") && filters.exposure !== object.exposure) {
+					continue;
+				}
+				if (filters.hasOwnProperty("harsh") && ((filters.harsh === false && object.harsh) || (filters.harsh === true && !object.harsh))) {
+					continue;
+				}
 				const reshapedItem = {
 					text: object.name,
 					updateSlave: {clothes: key, choosesOwnClothes: 0},
 					FS: object.fs,
 					exposure: object.exposure,
 				};
-				if (object.harsh) {
-					harshOptionsArray.push(reshapedItem);
-				} else {
-					niceOptionsArray.push(reshapedItem);
-				}
+				array.push(reshapedItem);
 			}
 
 			// Sort
-			niceOptionsArray = niceOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1);
-			harshOptionsArray = harshOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1);
-
-			// Nice options
-			links = App.UI.DOM.appendNewElement("div", el, "Nice: ", "choices");
-			links.appendChild(generateRows(niceOptionsArray, "clothes", true));
-
-			// Harsh options
-			links = App.UI.DOM.appendNewElement("div", el, "Harsh: ", "choices");
-			links.appendChild(generateRows(harshOptionsArray, "clothes", true));
-		}
-		if (slave.fuckdoll !== 0 || slave.clothes === "restrictive latex" || slave.clothes === "a latex catsuit" || slave.clothes === "a cybersuit" || slave.clothes === "a comfortable bodysuit") {
-			if (V.seeImages === 1 && V.imageChoice === 1) {
-				// Color options
-				links = App.UI.DOM.appendNewElement("div", el, "Color: ", "choices");
-				links.appendChild(colorOptions("clothingBaseColor"));
+			array = array.sort((a, b) => (a.text > b.text) ? 1 : -1);
+			if (array.length > 0) {
+				App.UI.DOM.appendNewElement("div", el, generateRows(array, "clothes", true), "choices");
+			} else {
+				App.UI.DOM.appendNewElement("div", el, "No available clothing meets your criteria", ["note", "choices"]);
 			}
+			return el;
 		}
 
-		return el;
-	}
-
-	function collar() {
-		const el = document.createElement('div');
-
-		const label = document.createElement('div');
-		label.append(`Collar: `);
-
-		let choice = App.UI.DOM.disabledLink(`${slave.collar}`, [clothTooltip(`${slave.collar}`)]);
-		choice.style.fontWeight = "bold";
-		label.appendChild(choice);
-
-		// Choose her own
-		if (slave.collar !== `none`) {
-			let choiceOptionsArray = [];
-			choiceOptionsArray.push({text: ` None`, updateSlave: {collar: `none`}});
-			label.appendChild(generateRows(choiceOptionsArray, "collar", false));
-		}
-
-		el.appendChild(label);
+		function collar() {
+			const el = new DocumentFragment();
+			let array = [];
 
-		let niceOptionsArray = [];
-		let harshOptionsArray = [];
+			for (const [key, object] of App.Data.slaveWear.collars) {
+				if (key === "choosing her own clothes") {
+					continue;
+				}
+				if (filters.hasOwnProperty("harsh") && ((filters.harsh === false && object.harsh) || (filters.harsh === true && !object.harsh))) {
+					continue;
+				}
+				const reshapedItem = {
+					text: object.name,
+					updateSlave: {collar: key},
+					FS: object.fs,
+				};
+				array.push(reshapedItem);
+			}
 
-		for (const [key, object] of App.Data.slaveWear.collars) {
-			const reshapedItem = {
-				text: object.name,
-				updateSlave: {collar: key},
-				FS: object.fs,
-			};
-			if (object.harsh) {
-				harshOptionsArray.push(reshapedItem);
+			// Sort
+			array = array.sort((a, b) => (a.text > b.text) ? 1 : -1);
+			if (array.length > 0) {
+				App.UI.DOM.appendNewElement("div", el, generateRows(array, "collar", true), "choices");
 			} else {
-				niceOptionsArray.push(reshapedItem);
+				App.UI.DOM.appendNewElement("div", el, "No available collar meets your criteria", ["note", "choices"]);
 			}
+			return el;
 		}
-
-		// Sort
-		niceOptionsArray = niceOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1);
-		harshOptionsArray = harshOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1);
-
-		// Nice options
-		let links = document.createElement('div');
-		links.className = "choices";
-		links.append(`Nice: `);
-		links.appendChild(generateRows(niceOptionsArray, "collar", true));
-		el.appendChild(links);
-
-		// Harsh options
-		links = document.createElement('div');
-		links.className = "choices";
-		links.append(`Harsh: `);
-		links.appendChild(generateRows(harshOptionsArray, "collar", true));
-		el.appendChild(links);
-
-		return el;
 	}
 
 	function mask() {
@@ -478,7 +555,7 @@ App.UI.SlaveInteract.wardrobe = function(slave) {
 
 		let optionsArray = [];
 
-		for (const [key, object] of App.Data.slaveWear.buttplugAttachment) {
+		for (const [key, object] of App.Data.slaveWear.buttplugAttachments) {
 			if (key === "none") {
 				// skip none in set, we set the link elsewhere.
 				continue;
@@ -754,8 +831,7 @@ App.UI.SlaveInteract.wardrobe = function(slave) {
 	}
 
 	function refresh() {
-		App.Art.refreshSlaveArt(slave, 3, "art-frame");
-		jQuery("#content-appearance").empty().append(App.UI.SlaveInteract.wardrobe(slave));
+		jQuery("#content").empty().append(contents());
 	}
 
 	/**
@@ -768,33 +844,38 @@ App.UI.SlaveInteract.wardrobe = function(slave) {
 	 */
 	function clothTooltip(cloth) {
 		let Cloth = capFirstChar(cloth);
+		let desc;
 
 		switch (cloth) {
 			/* nice clothes without specific effects(besides FS or being slutty/humiliating/modest) are handled at the end */
 			case "choosing her own clothes":
 			case "choosing his own clothes":
-				return Cloth + ", increases or greatly reduces devotion based on whether the slave is obedient(devotion at accepting or higher).";
+				desc = "Increases or greatly reduces devotion based on whether the slave is obedient(devotion at accepting or higher).";
+				break;
 			case "no clothing":
-				return Cloth + " increases devotion for resistant humiliations fetishists and nymphos.";
+				desc = "Increases devotion for resistant humiliations fetishists and nymphos.";
+				break;
 			case "a penitent nuns habit":
-				return Cloth + " increases devotion and fear but damages health, may cause masochism.";
+				desc = "Increases devotion and fear but damages health, may cause masochism.";
+				break;
 			case "restrictive latex":
-				return Cloth + ", it's modest and humiliating, increases fear and devotion for resistant slaves and just devotion for obedient, non-terrified submissives.";
+				desc = "Increases fear and devotion for resistant slaves and just devotion for obedient, non-terrified submissives.";
+				break;
 			case "shibari ropes":
-				return Cloth + ", it's humiliating, increases fear and devotion for resistant slaves and just devotion for obedient, non-terrified submissives.";
+				desc = "Increases fear and devotion for resistant slaves and just devotion for obedient, non-terrified submissives.";
+				break;
 			case "uncomfortable straps":
-				return Cloth + ", it's humiliating, increase devotion and fear for slaves who are disobedient and not terrified. Masochists who are at least ambivalent gain devotion, may also cause masochism.";
+				desc = "Increases devotion and fear for slaves who are disobedient and not terrified. Masochists who are at least ambivalent gain devotion, may also cause masochism.";
+				break;
 			case "chains":
-				return Cloth + " increase devotion and fear for slaves who are disobedient and not terrified. Masochists who are at least ambivalent gain devotion, may also cause masochism.";
-
+				desc = "Increases devotion and fear for slaves who are disobedient and not terrified. Masochists who are at least ambivalent gain devotion, may also cause masochism.";
+				break;
 			case "an apron":
-				return Cloth + ", nice clothing that increases just devotion for submissives, humiliation fetishists and visibly pregnant pregnancy fetishists regardless of devotion level.";
+				desc = "Increases just devotion for submissives, humiliation fetishists and visibly pregnant pregnancy fetishists regardless of devotion level.";
+				break;
 			case "a monokini":
-				return Cloth + ", nice clothing that boob fetishists enjoy.";
-
-			case "none":
-				return "No effect one way or another.";
-
+				desc = "Boob fetishists enjoy.";
+				break;
 			case "heavy gold":
 			case "ancient Egyptian":
 			case "bowtie":
@@ -804,151 +885,180 @@ App.UI.SlaveInteract.wardrobe = function(slave) {
 			case "satin choker":
 			case "silk ribbon":
 			case "stylish leather":
-				return Cloth + " on obedient slaves reduces fear, on non-obedient ones reduces fear a lot and devotion somewhat.";
+				desc = "On obedient slaves reduces fear, on non-obedient ones reduces fear a lot and devotion somewhat.";
+				break;
 			case "preg biometrics":
-				return Cloth + " increases devotion for those who have pregnancy fetish while fertile or a humiliation fetish. For others obedient ones gain devotion, ambivalent ones gain fear and devotion and resistant ones lose devotion and gain fear.";
+				desc = "Increases devotion for those who have pregnancy fetish while fertile or a humiliation fetish. For others obedient ones gain devotion, ambivalent ones gain fear and devotion and resistant ones lose devotion and gain fear.";
+				break;
 			case "bell collar":
-				return Cloth + " on non-obedient slaves reduces fear a lot and devotion somewhat.";
+				desc = "On non-obedient slaves reduces fear a lot and devotion somewhat.";
+				break;
 			case "leather with cowbell":
-				return Cloth + " on obedient slaves with boob fetish increases devotion, on disobedient slaves reduces fear a lot and devotion somewhat.";
-
+				desc = "On obedient slaves with boob fetish increases devotion, on disobedient slaves reduces fear a lot and devotion somewhat.";
+				break;
 			case "tight steel":
 			case "uncomfortable leather":
 			case "neck corset":
 			case "cruel retirement counter":
-				return Cloth + " increases fear for non-obedient slaves.";
+				desc = "Increases fear for non-obedient slaves.";
+				break;
 			case "shock punishment":
-				return Cloth + " for non-obedient slaves increases fear a great deal and reduces devotion, for resistant non-odd slaves it affects both much more a single time and gives the odd flaw.";
-
+				desc = "For non-obedient slaves increases fear a great deal and reduces devotion, for resistant non-odd slaves it affects both much more a single time and gives the odd flaw.";
+				break;
 			case "cat ears":
-				return Cloth + " increase fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one.";
+				desc = "Increases fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one.";
+				break;
 			case "porcelain mask":
-				return Cloth + " obscures the face, increases fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one.";
-
+				desc = "Obscures the face, increases fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one.";
+				break;
 			case "ball gag":
 			case "bit gag":
 			case "ring gag":
-				return Cloth + " increases fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one.";
+				desc = "Increases fear and devotion for disobedient slaves, submissives and nymphos also enjoy wearing one.";
+				break;
 			case "dildo gag":
 			case "massive dildo gag":
-				return Cloth + " increases oral skill up to a point and causes fear for disobedient slaves.";
-
+				desc = "Increases oral skill up to a point and causes fear for disobedient slaves.";
+				break;
 			case "hand gloves":
 			case "elbow gloves":
-				return Cloth + " have no effect one way or another.";
-
+				desc = "Have no effect one way or another.";
+				break;
 			case "flats":
-				return Cloth + " have no effect one way or another.";
+				desc = "Have no effect one way or another.";
+				break;
 			case "heels":
 			case "boots":
 			case "platform heels":
-				return Cloth + " increase height, resistant slaves with natural legs resent wearing them.";
+				desc = "Increases height, resistant slaves with natural legs resent wearing them.";
+				break;
 			case "pumps":
 			case "platform shoes":
-				return Cloth + " increase height.";
+				desc = "Increases height.";
+				break;
 			case "extreme heels":
 			case "extreme platform heels":
-				return Cloth + " increase height, slaves with natural legs who are resistant resent and fear wearing them while non-resistant ones become more fearful(unless masochistic) and obedient.";
-
+				desc = "Increases height, slaves with natural legs who are resistant resent and fear wearing them while non-resistant ones become more fearful(unless masochistic) and obedient.";
+				break;
 			case "short stockings":
-				return Cloth + " have no effect one way or another.";
 			case "long stockings":
-				return Cloth + " have no effect one way or another.";
-
+				desc = "Have no effect one way or another.";
+				break;
 			case "a tight corset":
-				return Cloth + " slowly narrows the waist into wispy one.";
+				desc = "Slowly narrows the waist into wispy one.";
+				break;
 			case "an extreme corset":
-				return Cloth + " 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";
+				desc = "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";
+				break;
 			case "a supportive band":
-				return Cloth + " reduces chance of miscarriage.";
+				desc = "Reduces chance of miscarriage.";
+				break;
 			case "a small empathy belly":
 			case "a medium empathy belly":
 			case "a large empathy belly":
 			case "a huge empathy belly":
-				return Cloth + " strengthens or removes(a weak) pregnancy fetish and affects devotion in various ways depending on devotion, fertility and having a pregnancy fetish or breeder flaw.";
-
+				desc = "Strengthens or removes(a weak) pregnancy fetish and affects devotion in various ways depending on devotion, fertility and having a pregnancy fetish or breeder flaw.";
+				break;
 			case "bullet vibrator":
-				return Cloth + " increases devotion but weakens fetish and libido.";
+				desc = "Increases devotion but weakens fetish and libido.";
+				break;
 			case "smart bullet vibrator":
-				return Cloth + " increases devotion and affects a specific fetish, attraction or sex drive.";
+				desc = "Increases devotion and affects a specific fetish, attraction or sex drive.";
+				break;
 			case "dildo":
-				return Cloth + " stretches vagina from virgin to tight, might remove hatred of penetration.";
+				desc = "Stretches vagina from virgin to tight, might remove hatred of penetration.";
+				break;
 			case "long dildo":
-				return Cloth + " stretches vagina from virgin to tight, might remove hatred of penetration. Makes size queens happy while others less trusting.";
+				desc = "Stretches vagina from virgin to tight, might remove hatred of penetration. Makes size queens happy while others less trusting.";
+				break;
 			case "large dildo":
 			case "long, large dildo":
-				return Cloth + " stretches vagina into a loose one, on a tight vagina increases obedience and fear.";
+				desc = "Stretches vagina into a loose one, on a tight vagina increases obedience and fear.";
+				break;
 			case "huge dildo":
 			case "long, huge dildo":
-				return Cloth + " stretches vagina into a cavernous one, on smaller vaginas size queens get much more devoted, masochists and submissives much more devoted and fearful and anyone else becomes much less devoted and trusting. Might cause miscarriage.";
-
+				desc = "Stretches vagina into a cavernous one, on smaller vaginas size queens get much more devoted, masochists and submissives much more devoted and fearful and anyone else becomes much less devoted and trusting. Might cause miscarriage.";
+				break;
 			case "vibrator":
-				return Cloth + " ";
 			case "smart vibrator":
-				return Cloth + " ";
-
+				desc = "";
+				break;
 			case "plug":
-				return Cloth + " stretches butthole from virgin to tight, might remove hatred of anal.";
+				desc = "Stretches butthole from virgin to tight, might remove hatred of anal.";
+				break;
 			case "long plug":
-				return Cloth + " stretches vagina from virgin to tight, might remove hatred of penetration. Makes size queens happy.";
+				desc = "Stretches vagina from virgin to tight, might remove hatred of penetration. Makes size queens happy.";
+				break;
 			case "large plug":
 			case "long, large plug":
-				return Cloth + " stretches vagina into a loose one, on a tight vagina increases obedience and fear.";
+				desc = "Stretches vagina into a loose one, on a tight vagina increases obedience and fear.";
+				break;
 			case "huge plug":
 			case "long, huge plug":
-				return Cloth + " stretches vagina into a cavernous one, on smaller vaginas size queens get much more devoted, masochists and submissives much more devoted and fearful and anyone else becomes much less devoted and trusting. Might cause miscarriage.";
-
+				desc = "Stretches vagina into a cavernous one, on smaller vaginas size queens get much more devoted, masochists and submissives much more devoted and fearful and anyone else becomes much less devoted and trusting. Might cause miscarriage.";
+				break;
 			case "tail":
 			case "fox tail":
 			case "cat tail":
 			case "cow tail":
-				return Cloth + " makes it more scary to wear a plug but might give humiliation fetish,";
-
-
+				desc = "Makes it more scary to wear a plug but might give humiliation fetish,";
+				break;
 			case "anal chastity":
-				return Cloth + " prevents losing anal virginity.";
+				desc = "Prevents losing anal virginity.";
+				break;
 			case "chastity belt":
-				return Cloth + " prevents losing virginity, has various effects, obedient virgins, buttsluts and ones with relatively high sex drive are most affected.";
-			case "":
+				desc = "Prevents losing virginity, has various effects, obedient virgins, buttsluts and ones with relatively high sex drive are most affected.";
+				break;
 			case "combined chastity belt":
-				return Cloth + " prevents losing virginities, has various effects, obedient virgins, buttsluts and ones with relatively high sex drive are most affected.";
+				desc = "Prevents losing virginities, has various effects, obedient virgins, buttsluts and ones with relatively high sex drive are most affected.";
+				break;
 			case "chastity cage":
-				return Cloth + " prevents using penis, has various effects, devotion, trust and sex drive of unresistant slaves with healthy sex drive all suffer from wearing one unless they're a masochist, nympho, neglectful, buttslut, sterile or lack balls.";
+				desc = "Prevents using penis, has various effects, devotion, trust and sex drive of unresistant slaves with healthy sex drive all suffer from wearing one unless they're a masochist, nympho, neglectful, buttslut, sterile or lack balls.";
+				break;
 			case "combined chastity cage":
-				return Cloth + " protects both penis and anus from sex, has various effects, devotion and trust and sex drive of unresistant slaves with healthy sex drive all suffer from wearing one unless they're a masochist, nympho, neglectful, buttslut, sterile or lack balls.";
+				desc = "Protects both penis and anus from sex, has various effects, devotion and trust and sex drive of unresistant slaves with healthy sex drive all suffer from wearing one unless they're a masochist, nympho, neglectful, buttslut, sterile or lack balls.";
+				break;
 			case "genital chastity":
-				return Cloth + " protects both penis and vagina from sex, has various effects.";
+				desc = "Protects both penis and vagina from sex, has various effects.";
+				break;
 			case "full chastity":
-				return Cloth + " protects penis, vagina and anus, has various effects.";
+				desc = "Protects penis, vagina and anus, has various effects.";
+				break;
 			case "choosing her own chastity":
 			case "choosing his own chastity":
 			case "choose own chastity":
-				return Cloth + " ";
 			case "revoke choosing own chastity":
-				return Cloth + " ";
-
-			default: {
-				/* assuming nice clothes, could actually add some sort of check to make sure. */
-				/* which clothes have these is decided in miscData.js */
-				let clothTooltip = Cloth + "";
-				switch (App.Data.clothes.get(slave.clothes).exposure) {
+				desc = "";
+				break;
+		}
+		if (cloth === "none") {
+			return "No effect one way or another.";
+		} else {
+			const clothingData = App.Data.clothes.get(cloth);
+			if (clothingData) {
+				switch (clothingData.exposure) {
+					case 4:
+						Cloth += ", might as well be naked";
+						break;
 					case 3:
-						clothTooltip += ", it's humiliating";
+						Cloth += ", it's humiliating";
 						break;
 					case 2:
-						clothTooltip += ", it's slutty";
+						Cloth += ", it's slutty";
+						break;
+					case 1:
+						Cloth += ", it's normal";
 						break;
 					case 0:
-						clothTooltip += ", it's modest";
+						Cloth += ", it's modest";
 						break;
+					default:
+						if (!clothingData.harsh) {
+							Cloth += ", it's only nice (meaning non-obedients lose devotion and fear while obedients gain devotion and trust)";
+						}
 				}
-
-				if (clothTooltip === Cloth + "") {
-					clothTooltip += ", it's only nice(meaning non-obedients lose devotion and fear while obedients gain devotion and trust).";
-				}
-				clothTooltip += ".";
-				return clothTooltip;
 			}
+			return Cloth + ". " + (desc || "");
 		}
 	}
 	/** @typedef RowItem
diff --git a/src/js/eventSelectionJS.js b/src/js/eventSelectionJS.js
index f499e6bbae627abe658d7a6cf3658ea320beaf01..9576db5afa979e6973855d79ede9d1739edce19d 100644
--- a/src/js/eventSelectionJS.js
+++ b/src/js/eventSelectionJS.js
@@ -618,7 +618,7 @@ globalThis.generateRandomEventPoolStandard = function(eventSlave) {
 					if (eventSlave.trust > 20) {
 						if (eventSlave.rules.speech !== "restrictive") {
 							if (eventSlave.choosesOwnClothes !== 1) {
-								if (App.Data.clothes.get(eventSlave.clothes).exposure === 0) {
+								if (getExposure(slave) === 0) {
 									V.RESSevent.push("modest clothes");
 								}
 							}
diff --git a/src/js/statsChecker/statsChecker.js b/src/js/statsChecker/statsChecker.js
index 4c94e5f40860ef9dda5431f208eab3e8fae95033..250bb2698a02ed44ccd00d7030af1c048018971a 100644
--- a/src/js/statsChecker/statsChecker.js
+++ b/src/js/statsChecker/statsChecker.js
@@ -472,7 +472,7 @@ globalThis.bimboScore = function(slave) {
 	if (slave.skin === "sun tanned" || slave.skin === "spray tanned") {
 		degree++;
 	}
-	if (App.Data.clothes.get(slave.clothes).exposure === 2) {
+	if (getExposure(slave) === 2) {
 		degree++;
 	}
 
diff --git a/src/js/utilsFC.js b/src/js/utilsFC.js
index ff6d0c4e524222a00017bf18f4d4e6397c2e8f64..14f26e503ccbfd87a4971cc1de810d4e86f5bb46 100644
--- a/src/js/utilsFC.js
+++ b/src/js/utilsFC.js
@@ -3085,3 +3085,12 @@ App.Utils.alphabetizeIterable = function(iterable) {
 	return clonedArray.sort(compare);
 };
 
+/**
+ * Returns how exposing a slave's outfit is, after taking into consideration a topless outfit is more revealing for beboobed slaves or female ones.
+ * @param {App.Entity.SlaveState} slave
+ * @returns {0|1|2|3|4}
+ */
+globalThis.getExposure = function(slave) {
+	const clothes = App.Data.clothes.get(slave.clothes);
+	return (clothes.topless && clothes.exposure < 3 && (slave.boobs > 299 || (slave.genes === 'XX' && slave.vagina >= 0))) ? 3 : clothes.exposure;
+};
diff --git a/src/npc/interaction/fAnimal.js b/src/npc/interaction/fAnimal.js
index 41330e9d0d2ce39b928b5282cb62224865960c51..fa7c48e7217dfc9321011bbbd3eff32cf6c47b2c 100644
--- a/src/npc/interaction/fAnimal.js
+++ b/src/npc/interaction/fAnimal.js
@@ -15,10 +15,6 @@ App.Interact.fAnimal = function(slave, type) {
 		ORAL: "oral",
 	};
 
-	const vaginal = Acts.VAGINAL;
-	const anal = Acts.ANAL;
-	const oral = Acts.ORAL;
-
 	const approvingFetishes = ["masochist", "humiliation", "perverted", "sinful"];	// not strictly fetishes, but approvingFetishesAndBehavioralQuirksAndSexualQuirks doesn't have the same ring to it
 
 	const animal = V.active[type];
@@ -30,49 +26,49 @@ App.Interact.fAnimal = function(slave, type) {
 	let hole;
 	let orifice;
 
-	const anAnimal = animal.articleAn ? `an ${animal.name}` : `a ${animal.name}`;
+	const anAnimal = `${animal.articleAn} ${animal.name}`;
 
 	if (slave.assignment === Job.FUCKTOY || slave.assignment === Job.MASTERSUITE) {
 		if (slave.toyHole === "pussy") {
-			act = vaginal;
+			act = Acts.VAGINAL;
 		} else if (slave.toyHole === "ass") {
-			act = anal;
+			act = Acts.ANAL;
 		} else if (slave.toyHole === "mouth") {
-			act = oral;
+			act = Acts.ORAL;
 		} else {
 			if (canDoVaginal(slave)) {
-				act = vaginal;
+				act = Acts.VAGINAL;
 			} else if (canDoAnal(slave)) {
-				act = anal;
+				act = Acts.ANAL;
 			} else {
-				act = oral;
+				act = Acts.ORAL;
 			}
 		}
 	} else if (canDoVaginal(slave)) {
-		act = vaginal;
+		act = Acts.VAGINAL;
 	} else if (canDoAnal(slave)) {
-		act = anal;
+		act = Acts.ANAL;
 	} else {
-		act = oral;
+		act = Acts.ORAL;
 	}
 
 	const slaveApproves = () =>
 		approvingFetishes.includes(slave.fetish) ||
 		approvingFetishes.includes(slave.sexualQuirk) ||
 		approvingFetishes.includes(slave.behavioralQuirk) ||
-		slave.fetish === "buttslut" && act === anal ||
-		slave.fetish === "cumslut" && act === oral ||
-		slave.sexualQuirk === "gagfuck queen" && act === oral;
+		slave.fetish === "buttslut" && act === Acts.ANAL ||
+		slave.fetish === "cumslut" && act === Acts.ORAL ||
+		slave.sexualQuirk === "gagfuck queen" && act === Acts.ORAL;
 
 	switch (act) {
-		case oral:
+		case Acts.ORAL:
 			orifice = () => either("mouth", "throat");
 			break;
-		case vaginal:
+		case Acts.VAGINAL:
 			orifice = () => either("pussy", "cunt");
 			hole = 0;
 			break;
-		case anal:
+		case Acts.ANAL:
 			orifice = () => either("asshole", "rectum");
 			hole = 1;
 			break;
@@ -80,17 +76,17 @@ App.Interact.fAnimal = function(slave, type) {
 			throw new Error(`Unexpected act type '${act}' in fAnimal()`);
 	}
 
-	if (slave.fetish === "cumslut" && act === oral) {
+	if (slave.fetish === "cumslut" && act === Acts.ORAL) {
 		fetishDesc = `getting to drink more cum`;
 	} else if (slave.fetish === "humiliation") {
 		fetishDesc = `committing such a humiliating act`;
-	} else if (slave.fetish === "buttslut" && act === anal) {
+	} else if (slave.fetish === "buttslut" && act === Acts.ANAL) {
 		fetishDesc = `getting to take a cock up ${his} ass`;
 	} else if (slave.fetish === "masochist") {
 		fetishDesc = `committing such a painful act`;
 	} else if (slave.sexualQuirk === "perverted") {
 		fetishDesc = `committing such a perverted act`;
-	} else if (slave.sexualQuirk === "gagfuck queen" && act === oral) {
+	} else if (slave.sexualQuirk === "gagfuck queen" && act === Acts.ORAL) {
 		fetishDesc = `getting to suck more dick`;
 	} else if (slave.behavioralQuirk === "sinful") {
 		fetishDesc = `committing such a sinful act`;
@@ -123,9 +119,9 @@ App.Interact.fAnimal = function(slave, type) {
 			r.push(`You order another slave to bring ${slave.slaveName} over. Once ${he} is situated, you`);
 		}
 
-		r.push(`tell ${him} you want to watch ${him} ${act === oral ?
+		r.push(`tell ${him} you want to watch ${him} ${act === Acts.ORAL ?
 			`suck off` :
-			act === vaginal ?
+			act === Acts.VAGINAL ?
 				`get fucked by` :
 				`get fucked in the ass by`} ${anAnimal}. `);
 
@@ -154,14 +150,14 @@ App.Interact.fAnimal = function(slave, type) {
 		function introDevoted() {
 			const mainSpan = document.createElement("span");
 
-			if (act === oral) {
+			if (act === Acts.ORAL) {
 				if (slaveApproves()) {
 					mainSpan.append(`${slave.slaveName}'s face visibly brightens at the prospect of ${fetishDesc}, even if it's an animal${slave.fetish === "cumslut" ? `'s cum` : ` that ${he} has to suck off`}. `);
 				} else {
 					mainSpan.append(`${slave.slaveName} visibly blanches at the thought of having to suck down an animal's cum, but ${he} is so devoted to you that ${he} reluctantly agrees. `);
 				}
 			} else {
-				if ((act === vaginal && slave.vagina > 0) || (act === anal && slave.anus > 0)) {
+				if ((act === Acts.VAGINAL && slave.vagina > 0) || (act === Acts.ANAL && slave.anus > 0)) {
 					if (slaveApproves()) {
 						mainSpan.append(`${slave.slaveName}'s face visibly brightens at the thought of ${fetishDesc}, even if the dick is an animal's. `);
 					} else {
@@ -182,14 +178,14 @@ App.Interact.fAnimal = function(slave, type) {
 		function introNondevoted() {
 			const mainSpan = document.createElement("span");
 
-			if (act === oral) {
+			if (act === Acts.ORAL) {
 				if (slaveApproves()) {
 					mainSpan.append(`${slave.slaveName} isn't too keen on the idea of sucking off an animal, but the idea of ${fetishDesc} is enough to get ${him} to comply. `);
 				} else {
 					mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of blowing an animal, but quickly regains ${his} composure. `);
 				}
 			} else {
-				if ((act === vaginal && slave.vagina > 0) || (act === anal && slave.anus > 0)) {
+				if ((act === Acts.VAGINAL && slave.vagina > 0) || (act === Acts.ANAL && slave.anus > 0)) {
 					if (slaveApproves()) {
 						mainSpan.append(`${slave.slaveName} doesn't seem terribly keen on the idea of fucking an animal, but the thought of ${fetishDesc} seems to be enough to win ${him} over. `);
 					} else {
@@ -197,9 +193,9 @@ App.Interact.fAnimal = function(slave, type) {
 					}
 				} else {
 					if (slaveApproves()) {
-						mainSpan.append(`${slave.slaveName} clearly has some reservations about having ${his} ${act === anal ? `anal ` : ``}virginity taken by ${anAnimal}, but the thought of ${fetishDesc} is enough to make agree to comply. `);
+						mainSpan.append(`${slave.slaveName} clearly has some reservations about having ${his} ${act === Acts.ANAL ? `anal ` : ``}virginity taken by ${anAnimal}, but the thought of ${fetishDesc} is enough to make agree to comply. `);
 					} else {
-						mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of having ${his} precious ${act === anal ? `rosebud` : `pearl`} taken by a beast, but quickly regains ${his} composure. `);
+						mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of having ${his} precious ${act === Acts.ANAL ? `rosebud` : `pearl`} taken by a beast, but quickly regains ${his} composure. `);
 					}
 				}
 			}
@@ -210,14 +206,14 @@ App.Interact.fAnimal = function(slave, type) {
 		function introNonresistant() {
 			const mainSpan = document.createElement("span");
 
-			if (act === oral) {
+			if (act === Acts.ORAL) {
 				if (slaveApproves()) {
 					mainSpan.append(`${slave.slaveName} looks disgusted at the thought of sucking off an animal at first, but the thought of the ${fetishDesc} that comes with it seems to spark a small flame of lust in ${him}. `);
 				} else {
 					mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of blowing an animal${canWalk(slave) ? `, and only the threat of worse punishment keeps ${him} from running away as fast as ${he} can` : ``}. `);
 				}
 			} else {
-				if ((act === vaginal && slave.vagina > 0) || (act === anal && slave.anus > 0)) {
+				if ((act === Acts.VAGINAL && slave.vagina > 0) || (act === Acts.ANAL && slave.anus > 0)) {
 					if (slaveApproves()) {
 						mainSpan.append(`${slave.slaveName} looks disgusted at the thought of fucking an animal at first, but the thought of the ${fetishDesc} that comes with it seems to spark a small flame of lust in ${him}. `);
 					} else {
@@ -225,9 +221,9 @@ App.Interact.fAnimal = function(slave, type) {
 					}
 				} else {
 					if (slaveApproves()) {
-						mainSpan.append(`${slave.slaveName} clearly has some reservations about having ${his} ${act === anal ? `anal ` : ``}virginity taken by ${anAnimal}, but the thought of ${fetishDesc} is enough to make agree to comply. `);
+						mainSpan.append(`${slave.slaveName} clearly has some reservations about having ${his} ${act === Acts.ANAL ? `anal ` : ``}virginity taken by ${anAnimal}, but the thought of ${fetishDesc} is enough to make agree to comply. `);
 					} else {
-						mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of having ${his} precious ${act === anal ? `rosebud` : `pearl`} taken by a beast${canWalk(slave) ? `, and only the threat of worse punishment keeps ${him} from running away as fast as ${he} can` : ``}. `);
+						mainSpan.append(`${slave.slaveName} tries in vain to conceal ${his} horror at the thought of having ${his} precious ${act === Acts.ANAL ? `rosebud` : `pearl`} taken by a beast${canWalk(slave) ? `, and only the threat of worse punishment keeps ${him} from running away as fast as ${he} can` : ``}. `);
 					}
 				}
 			}
@@ -266,7 +262,7 @@ App.Interact.fAnimal = function(slave, type) {
 				mainSpan = document.createElement("span"),
 				r = [];
 
-			if (act === oral) {
+			if (act === Acts.ORAL) {
 				r.push(`You have ${him} kneel on the floor before calling in the ${animal.name}. The beast slowly saunters up to the slave where ${he} waits, showing little concern when the slave reaches out and begins masturbating it to begin the process of getting the animal hard. Once the ${animal.name} is hard enough, ${slave.slaveName} takes its cock and begins to give it a few tentative licks before finally putting it in ${his} mouth. `);
 			} else {
 				r.push(`You have ${him} ${slave.clothes !== "no clothing" ? `take off ${his} clothes and ` : ``}get on the floor, ass in the air, before calling in the ${animal.name}. The beast slowly saunters up to the slave, where it takes only a few short moments for its animal brain to realize that what it is standing behind is a warm hole that needs to be filled with seed. `);
@@ -286,12 +282,12 @@ App.Interact.fAnimal = function(slave, type) {
 					throw new Error(`Unexpected animal type '${animal}' in consummationDevoted()`);
 			}
 
-			if (act !== oral) {
+			if (act !== Acts.ORAL) {
 				mainSpan.append(virginityCheck(act));
 			}
 
 			function consummationDevotedCanine(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`The slave seems to quickly get over the fact that the dick currently in ${his} mouth belongs to a canine as ${his} more carnal desires kick in. `);
 					} else {
@@ -304,12 +300,12 @@ App.Interact.fAnimal = function(slave, type) {
 						r.push(`The canine takes a few curious sniffs, then lines up its large cock with ${slave.slaveName}'s ${orifice()}. `);
 					}
 
-					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === vaginal ? `wet ` : ``}${orifice()} and begin to hammer away in the way that only canines can. `);
+					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === Acts.VAGINAL ? `wet ` : ``}${orifice()} and begin to hammer away in the way that only canines can. `);
 				}
 			}
 
 			function consummationDevotedHooved(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`The slave seems to quickly get over the fact that dick currently in ${his} mouth is not a human one as ${his} more carnal desires kick in. `);
 					} else {
@@ -321,7 +317,7 @@ App.Interact.fAnimal = function(slave, type) {
 			}
 
 			function consummationDevotedFeline(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`The slave seems to quickly get over the fact that dick currently in ${his} mouth belongs to ${anAnimal} as ${his} more carnal desires kick in. `);
 					} else {
@@ -342,7 +338,7 @@ App.Interact.fAnimal = function(slave, type) {
 				mainSpan = document.createElement("span"),
 				r = [];
 
-			if (act === oral) {
+			if (act === Acts.ORAL) {
 				r.push(`You tell ${him} to kneel on the floor before calling in the ${animal.name}. The beast slowly saunters up to the slave where ${he} waits, showing little concern when the slave hesitantly reaches out and begins masturbating it to begin the process of getting the animal hard. Once the ${animal.name} is hard enough, ${slave.slaveName} takes its cock, and, after taking a moment to steel ${his} resolve, begins to give it a few reluctant licks before putting it in ${his} mouth. `);
 			} else {
 				r.push(`You tell ${him} to ${slave.clothes !== "no clothing" ? `take off ${his} clothes and ` : ``}get on the floor, ass in the air, before calling in the ${animal.name}. The beast slowly saunters up to the slave, where it takes only a few seconds for its animal brain to realize that what it is standing behind is a warm hole that needs to be filled with seed. `);
@@ -362,12 +358,12 @@ App.Interact.fAnimal = function(slave, type) {
 					throw new Error(`Unexpected animal type '${animal}' in consummationDevoted()`);
 			}
 
-			if (act !== oral) {
+			if (act !== Acts.ORAL) {
 				mainSpan.append(virginityCheck(act));
 			}
 
 			function consummationNondevotedCanine(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`Though the slave still seems to have some reservations about sucking off an animal, ${he} seems to forget that the cock in ${his} mouth belongs to ${anAnimal} soon enough, once ${his} carnal desires kick in. `);
 					} else {
@@ -380,12 +376,12 @@ App.Interact.fAnimal = function(slave, type) {
 						r.push(`The canine takes a few curious sniffs, then lines up its large cock with ${slave.slaveName}'s ${orifice()}. `);
 					}
 
-					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === vaginal ? `wet ` : ``}${orifice()} and begin to hammer away in the way that only canines can. `);
+					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === Acts.VAGINAL ? `wet ` : ``}${orifice()} and begin to hammer away in the way that only canines can. `);
 				}
 			}
 
 			function consummationNondevotedHooved(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`Though the slave still seems to have some reservations about sucking off ${anAnimal}, ${he} seems to forget that the cock in ${his} mouth isn't human soon enough, once ${his} carnal desires kick in. `);
 					} else {
@@ -397,7 +393,7 @@ App.Interact.fAnimal = function(slave, type) {
 			}
 
 			function consummationNondevotedFeline(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`Though the slave still seems to have some reservations about sucking off an animal, ${he} seems to forget that the cock in ${his} mouth belongs to a feline soon enough, once ${his} carnal desires kick in. `);
 					} else {
@@ -418,7 +414,7 @@ App.Interact.fAnimal = function(slave, type) {
 				mainSpan = document.createElement("span"),
 				r = [];
 
-			if (act === oral) {
+			if (act === Acts.ORAL) {
 				r.push(`You force ${him} to kneel on the floor before calling in the ${animal.name}. The beast slowly saunters up to the slave where ${he} waits, showing little concern when the slave reluctantly reaches out and begins masturbating it to begin the process of getting the animal hard. Once the ${animal.name} is hard enough, ${slave.slaveName} takes its cock and begins to give it a few tentative licks before finally putting it in ${his} mouth. `);
 			} else {
 				r.push(`You force ${him} to ${slave.clothes !== "no clothing" ? `take off ${his} clothes and ` : ``}get on the floor, ass in the air, before calling in the ${animal.name}. The beast slowly saunters up to the slave, where it takes only a few short moments for its animal brain to realize that what it is standing behind is a warm hole that needs to be filled with seed. `);
@@ -438,12 +434,12 @@ App.Interact.fAnimal = function(slave, type) {
 					throw new Error(`Unexpected animal type '${animal}' in consummationNonresistant()`);
 			}
 
-			if (act !== oral) {
+			if (act !== Acts.ORAL) {
 				mainSpan.append(virginityCheck(act));
 			}
 
 			function consummationNonresistantCanine(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`Though the slave still seems to have some reservations about sucking off an animal, ${he} seems to forget that the cock in ${his} mouth belongs to ${anAnimal} soon enough, once ${his} carnal desires kick in. `);
 					} else {
@@ -456,12 +452,12 @@ App.Interact.fAnimal = function(slave, type) {
 						r.push(`The canine takes a few curious sniffs, then lines up its large cock with ${slave.slaveName}'s ${orifice()}. `);
 					}
 
-					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === vaginal ? `wet ` : ``}${orifice()} and begin to hammer away in the way that only canines can. `);
+					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === Acts.VAGINAL ? `wet ` : ``}${orifice()} and begin to hammer away in the way that only canines can. `);
 				}
 			}
 
 			function consummationNonresistantHooved(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`Though the slave still seems to have some reservations about sucking off ${anAnimal}, ${he} seems to forget that the cock in ${his} mouth isn't human soon enough, once ${his} carnal desires kick in. `);
 					} else {
@@ -473,7 +469,7 @@ App.Interact.fAnimal = function(slave, type) {
 			}
 
 			function consummationNonresistantFeline(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`Though the slave still seems to have some reservations about sucking off an animal, ${he} seems to forget that the cock in ${his} mouth belongs to a feline soon enough, once ${his} carnal desires kick in. `);
 					} else {
@@ -494,7 +490,7 @@ App.Interact.fAnimal = function(slave, type) {
 				mainSpan = document.createElement("span"),
 				r = [];
 
-			if (act === oral) {
+			if (act === Acts.ORAL) {
 				r.push(`You have to physically force ${him} to kneel on the floor before calling in the ${animal.name}. The beast slowly saunters up to the slave where ${he} is restrained, showing little concern when another slave reaches out and begins masturbating it to begin the process of getting the animal hard. Once the ${animal.name} is hard enough, the slave takes its cock and lines it up with ${slave.slaveName}'s mouth. The animal needs no prompting, and thrusts itself into ${his} ring-gagged mouth. `);
 			} else {
 				r.push(`You have to physically force ${him} to ${slave.clothes !== "no clothing" ? `take off ${his} clothes and ` : ``} get on the floor, ass in the air and restraints around ${his} wrists and ankles, before calling in the ${animal.name}. The beast slowly saunters up to the slave, where it takes only a few short moments for its animal brain to realize that what it is standing behind is a warm hole that needs to be filled with seed. `);
@@ -514,12 +510,12 @@ App.Interact.fAnimal = function(slave, type) {
 					throw new Error(`Unexpected animal type '${animal}' in consummationResistant()`);
 			}
 
-			if (act !== oral) {
+			if (act !== Acts.ORAL) {
 				mainSpan.append(virginityCheck(act));
 			}
 
 			function consummationResistantCanine(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`The slave glares daggers at you as ${he} takes the full length of the canine's cock in ${his} mouth, but ${slave.dick ?
 							canAchieveErection(slave) ?
@@ -539,12 +535,12 @@ App.Interact.fAnimal = function(slave, type) {
 						r.push(`The canine takes a few curious sniffs, then lines up its large cock with ${slave.slaveName}'s ${orifice()}. `);
 					}
 
-					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === vaginal ? `wet ` : ``}${orifice()} and begin to hammer away in the way that only canines can. `);
+					r.push(`It takes a few tries, but the ${animal.name} finally manages to sink its cock into ${his} ${slaveApproves() && act === Acts.VAGINAL ? `wet ` : ``}${orifice()} and begin to hammer away in the way that only canines can. `);
 				}
 			}
 
 			function consummationResistantHooved(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`The slave glares daggers at you as ${he} takes the full length of the ${animal.name}'s cock in ${his} mouth, but ${slave.dick ?
 							canAchieveErection(slave) ?
@@ -563,7 +559,7 @@ App.Interact.fAnimal = function(slave, type) {
 			}
 
 			function consummationResistantFeline(type) {
-				if (type === oral) {
+				if (type === Acts.ORAL) {
 					if (slaveApproves()) {
 						r.push(`The slave glares daggers at you as ${he} takes the full length of the feline's cock in ${his} mouth, but ${slave.dick ?
 							canAchieveErection(slave) ?
@@ -610,28 +606,28 @@ App.Interact.fAnimal = function(slave, type) {
 				throw new Error(`Unexpected animal type '${animal}' in completion()`);
 		}
 
-		if (act !== oral && canGetPregnant(slave) && canBreed(slave, animal)) {
+		if (act !== Acts.ORAL && canGetPregnant(slave) && canBreed(slave, animal)) {
 			knockMeUp(slave, 5, hole, -8);
 		}
 
 		function completionCanine() {
-			if (act === oral) {
+			if (act === Acts.ORAL) {
 				r.push(`The ${animal.species === "dog" ? `hound` : animal.name} wastes no time in beginning to hammer away at ${his} ${orifice()}, causing ${slave.slaveName} to moan uncontrollably as its thick, veiny member probes the depths of ${his} ${orifice()}. A few short minutes later, ${he} gives a loud groan ${slaveApproves() ? `and shakes in orgasm ` : ``}as the ${animal.name}'s knot begins to swell and its dick begins to erupt a thick stream of jizz down ${his} abused throat. Soon enough, the ${animal.name} finally finishes cumming and its knot is sufficiently small enough to slip out of ${slave.slaveName}'s mouth, causing ${him} to immediately begin coughing and retching uncontrollably. Having finished its business, the ${animal.name} runs off, presumably in search of food. `);
 			} else {
-				r.push(`The ${animal.species === "dog" ? `hound` : animal.name} wastes no time in beginning to hammer away at ${his} ${orifice()}, causing ${slave.slaveName} to moan uncontrollably as its thick, veiny member probes the depths of ${his} ${orifice()}. A few short minutes later, ${he} gives a loud groan ${slaveApproves() ? `and shakes in orgasm ` : ``}as the ${animal.name}'s knot begins to swell and its dick begins to erupt a thick stream of jizz into ${his} ${orifice()}. Soon enough, the ${animal.name} finally finishes cumming and its knot is sufficiently small enough to slip out of ${slave.slaveName}'s ${act === vaginal && slave.vagina < 3 || act === anal && slave.anus < 2 ?
+				r.push(`The ${animal.species === "dog" ? `hound` : animal.name} wastes no time in beginning to hammer away at ${his} ${orifice()}, causing ${slave.slaveName} to moan uncontrollably as its thick, veiny member probes the depths of ${his} ${orifice()}. A few short minutes later, ${he} gives a loud groan ${slaveApproves() ? `and shakes in orgasm ` : ``}as the ${animal.name}'s knot begins to swell and its dick begins to erupt a thick stream of jizz into ${his} ${orifice()}. Soon enough, the ${animal.name} finally finishes cumming and its knot is sufficiently small enough to slip out of ${slave.slaveName}'s ${act === Acts.VAGINAL && slave.vagina < 3 || act === Acts.ANAL && slave.anus < 2 ?
 					`now-gaping ${orifice()}` :
 					orifice()}, causing a thick stream of cum to slide out of it. Having finished its business, the ${animal.name} runs off, presumably in search of food. `);
 			}
 
 			switch (act) {
-				case oral:
+				case Acts.ORAL:
 					slave.counter.oral++;
 					break;
-				case vaginal:
+				case Acts.VAGINAL:
 					slave.counter.vaginal++;
 					slave.vagina = slave.vagina < 3 ? 3 : slave.vagina;
 					break;
-				case anal:
+				case Acts.ANAL:
 					slave.counter.anal++;
 					slave.anus = slave.anus < 2 ? 2 : slave.anus;
 					break;
@@ -641,21 +637,21 @@ App.Interact.fAnimal = function(slave, type) {
 		}
 
 		function completionHooved() {
-			if (act === oral) {
+			if (act === Acts.ORAL) {
 				r.push(`The ${animal.species === "horse" ? `stallion` : animal.name} begins to thrust faster and faster, causing ${him} to moan and groan past the huge ${animal.species} cock stretching ${his} poor throat to its limits. Before too long, the ${animal.name}'s movements begin to slow, and you can see its large testicles contract as its begins to erupt and pour its thick semen down ${his} throat and into ${his} stomach, filling it to the brim. After what seems like an impossibly long time, the ${animal.name}'s dick finally begins to soften and pull out, causing ${slave.slaveName} to begin coughing and retching uncontrollably. You have another slave lead the ${animal.name} away, with a fresh apple as a treat for its good performance. `);
 			} else {
-				r.push(`The ${animal.species === "horse" ? `stallion` : animal.name} begins to thrust faster and faster, causing ${him} to moan and groan as the huge ${animal.species} cock ${act === vaginal ? `batters ${his} cervix` : `fills ${him} completely`}. Before too long, the ${animal.name}'s movements begin to slow, and you can see its large testicles contract as its begins to erupt and fill ${his} ${orifice()} with its thick baby batter. After what seems like an impossibly long time, the ${animal.name}'s dick finally begins to soften and pull out, leaving ${slave.slaveName} panting and covered in sweat. You have another slave lead the ${animal.name} away, with a fresh apple as a treat for its good performance. `);
+				r.push(`The ${animal.species === "horse" ? `stallion` : animal.name} begins to thrust faster and faster, causing ${him} to moan and groan as the huge ${animal.species} cock ${act === Acts.VAGINAL ? `batters ${his} cervix` : `fills ${him} completely`}. Before too long, the ${animal.name}'s movements begin to slow, and you can see its large testicles contract as its begins to erupt and fill ${his} ${orifice()} with its thick baby batter. After what seems like an impossibly long time, the ${animal.name}'s dick finally begins to soften and pull out, leaving ${slave.slaveName} panting and covered in sweat. You have another slave lead the ${animal.name} away, with a fresh apple as a treat for its good performance. `);
 			}
 
 			switch (act) {
-				case oral:
+				case Acts.ORAL:
 					slave.counter.oral++;
 					break;
-				case vaginal:
+				case Acts.VAGINAL:
 					slave.counter.vaginal++;
 					slave.vagina = slave.vagina < 4 ? 4 : slave.vagina;
 					break;
-				case anal:
+				case Acts.ANAL:
 					slave.counter.anal++;
 					slave.anus = slave.anus < 3 ? 3 : slave.anus;
 					break;
@@ -665,7 +661,7 @@ App.Interact.fAnimal = function(slave, type) {
 		}
 
 		function completionFeline() {
-			if (act === oral) {
+			if (act === Acts.ORAL) {
 				r.push(`The ${animal.name} begins to move, thrusting faster and faster. The ${girl} underneath it can't stop a groan of pain from escaping ${his} lips as the ${animal.species}'s barbed dick rubs the inside of ${his} mouth and throat raw. After a few minutes of painful coupling, the ${animal.species}'s thrusts finally slow, then stop completely as its ${animal.species !== "cat" ? `large` : ``} cock erupts down ${slave.slaveName}'s throat. With a ${animal.species !== "cat" ? `deep bellow` : `loud meow`}, he finally dismounts, gives you a long look, then stalks off. `);
 			} else {
 				r.push(`The ${animal.name} begins to move, thrusting faster and faster. The ${girl} underneath it can't stop a groan of pain from escaping ${his} lips as the ${animal.species}'s barbed dick rubs the inside of ${his} ${orifice()} raw. After a few minutes of painful coupling, the ${animal.species}'s thrusts finally slow, then stop completely as its ${animal.species !== "cat" ? `large` : ``} cock erupts, filling ${slave.slaveName} with its sperm. With a ${animal.species !== "cat" ? `deep bellow` : `loud meow`}, he finally dismounts, gives you a long look, then stalks off. `);
@@ -674,14 +670,14 @@ App.Interact.fAnimal = function(slave, type) {
 			healthDamage(slave, 1);
 
 			switch (act) {
-				case oral:
+				case Acts.ORAL:
 					slave.counter.oral++;
 					return;
-				case vaginal:
+				case Acts.VAGINAL:
 					slave.counter.vaginal++;
 					slave.vagina = slave.vagina < 2 ? 2 : slave.vagina;
 					return;
-				case anal:
+				case Acts.ANAL:
 					slave.counter.anal++;
 					slave.anus = slave.anus < 1 ? 1 : slave.anus;
 					return;
@@ -704,21 +700,21 @@ App.Interact.fAnimal = function(slave, type) {
 
 		if (jsRandom(1, 100) > 100 + slave.devotion) {
 			switch (act) {
-				case oral:
+				case Acts.ORAL:
 					if (slave.energy < 95 && slave.sexualFlaw !== "hates oral") {
 						mainSpan.append(`Having ${anAnimal} fuck ${his} throat by force has given ${him} a hatred of oral sex. `);
 					}
 					slave.sexualFlaw = "hates oral";
 
 					break;
-				case vaginal:
+				case Acts.VAGINAL:
 					if (slave.energy < 95 && slave.sexualFlaw !== "hates penetration") {
 						mainSpan.append(`Having ${anAnimal} fuck ${him} by force has given ${him} a hatred of penetration. `);
 					}
 					slave.sexualFlaw = "hates penetration";
 
 					break;
-				case anal:
+				case Acts.ANAL:
 					if (slave.energy < 95 && slave.sexualFlaw !== "hates anal") {
 						mainSpan.append(`Having ${anAnimal} fuck ${his} asshole by force has given ${him} a hatred of anal penetration. `);
 					}
@@ -738,8 +734,8 @@ App.Interact.fAnimal = function(slave, type) {
 			mainSpan = document.createElement("span"),
 			r = [];
 
-		if (act !== oral) {
-			if (act === vaginal) {
+		if (act !== Acts.ORAL) {
+			if (act === Acts.VAGINAL) {
 				if (slave.vagina === 3) {
 					r.push(`${capFirstChar(animal.name)} cum drips out of ${his} fucked-out hole. `);
 				} else if (slave.vagina === 2) {
@@ -834,8 +830,8 @@ App.Interact.fAnimal = function(slave, type) {
 			virginityLossSpan = App.UI.DOM.makeElement("span", '', ["virginity", "loss"]);
 
 		switch (type) {
-			case vaginal:
-				if (act === vaginal && slave.vagina === 0) {
+			case Acts.VAGINAL:
+				if (act === Acts.VAGINAL && slave.vagina === 0) {
 					virginityLossSpan.append(`${his} virginity is taken from ${him}${slave.devotion < -20 ? ` by force` : ``}. `);
 
 					mainSpan.append(`The slave gives a loud ${slave.devotion > 20 ? `moan` : `groan`} as `, virginityLossSpan, ` `);
@@ -844,8 +840,8 @@ App.Interact.fAnimal = function(slave, type) {
 				}
 
 				return mainSpan;
-			case anal:
-				if (act === anal && slave.anus === 0) {
+			case Acts.ANAL:
+				if (act === Acts.ANAL && slave.anus === 0) {
 					mainSpan.append(`The slave gives a loud ${slave.devotion > 20 ? `moan` : `groan`} as ${his} anal virginity is taken from ${him}${slave.devotion < -20 ? ` by force` : ``}. `);
 
 					mainSpan.append(virginityEffects(type));
@@ -865,7 +861,7 @@ App.Interact.fAnimal = function(slave, type) {
 			healthSpan = App.UI.DOM.makeElement("span", '', ["health", "dec"]);
 
 		switch (type) {
-			case vaginal:
+			case Acts.VAGINAL:
 				if (slave.devotion >= -20) {
 					if (slaveApproves()) {
 						devotionSpan.classList.add("devotion", "inc");
@@ -928,7 +924,7 @@ App.Interact.fAnimal = function(slave, type) {
 				healthDamage(slave, 5);
 
 				return mainSpan;
-			case anal:
+			case Acts.ANAL:
 				if (slave.devotion >= -20) {
 					if (slaveApproves()) {
 						devotionSpan.classList.add("devotion", "inc");