diff --git a/src/pregmod/FCTV/FCTV.js b/src/pregmod/FCTV/FCTV.js
index d2a769c5a5f583c3e979357884998d87f91675fd..5fdf17baca015bacd3fd40686d847a85b54c46f2 100644
--- a/src/pregmod/FCTV/FCTV.js
+++ b/src/pregmod/FCTV/FCTV.js
@@ -23,14 +23,10 @@ globalThis.FCTV = (function() {
 	};
 
 	/** Produce an array of numbers representing all available channels in App.Data.FCTV.channels
-	 * @returns {Array}
+	 * @returns {number[]}
 	 */
 	function channels() {
-		const array = [];
-		for (const channel in App.Data.FCTV.channels) {
-			array.push(parseInt(channel, 10));
-		}
-		return array;
+		return Object.keys(App.Data.FCTV.channels).map(chStr => parseInt(chStr, 10));
 	}
 
 	function initChannels() {
@@ -161,7 +157,7 @@ globalThis.FctvDisplay = function({usedRemote = 0, seeAll = 0, selectedChannel =
 		return jQuery("#FctvWatch").empty().append(frag);
 
 		/** Creates a remote control for FCTV
-		 * @returns {node}
+		 * @returns {HTMLParagraphElement}
 		 */
 		function createRemote() {
 			const p = document.createElement("p");
@@ -175,7 +171,7 @@ globalThis.FctvDisplay = function({usedRemote = 0, seeAll = 0, selectedChannel =
 					if (selectedChannel !== i) { // Selected button
 						buttons.push(
 							App.UI.DOM.link(
-								i,
+								i.toFixed(0),
 								() => {
 									watch({usedRemote: 1, seeAll: seeAll, selectedChannel: i});
 								}
@@ -187,7 +183,7 @@ globalThis.FctvDisplay = function({usedRemote = 0, seeAll = 0, selectedChannel =
 						span.style.fontWeight = "bold";
 						span.append(
 							App.UI.DOM.link(
-								i,
+								i.toFixed(0),
 								() => {
 									watch({usedRemote: 1, seeAll: seeAll, selectedChannel: i});
 								},
@@ -200,7 +196,7 @@ globalThis.FctvDisplay = function({usedRemote = 0, seeAll = 0, selectedChannel =
 					}
 				} else { // Channel you cannot choose
 					buttons.push(
-						App.UI.DOM.disabledLink(i, [showChannel(i).text])
+						App.UI.DOM.disabledLink(i.toFixed(0), [showChannel(i).text])
 					);
 				}
 			}
@@ -302,7 +298,7 @@ globalThis.FctvDisplay = function({usedRemote = 0, seeAll = 0, selectedChannel =
 		/**
 		 * Text to frame if content won't work due to tags.
 		 * @param {string} text Reason this channel/episode can't be shown
-		 * @returns {node}
+		 * @returns {Node}
 		 */
 		function channelFailed(text) {
 			const frag = new DocumentFragment;
@@ -314,7 +310,7 @@ globalThis.FctvDisplay = function({usedRemote = 0, seeAll = 0, selectedChannel =
 
 		/**
 		 * Displays just the channel itself, including art
-		 * @returns {node}
+		 * @returns {Node}
 		 */
 		function displayShow() {
 			const frag = new DocumentFragment();
@@ -343,11 +339,12 @@ globalThis.FctvDisplay = function({usedRemote = 0, seeAll = 0, selectedChannel =
 			if (channel.intro) {
 				$(frag).append(channel.intro);
 			}
-			if (channel.episode[epToShow].text) {
-				if (typeof channel.episode[epToShow].text === 'function') {
-					$(frag).append(channel.episode[epToShow].text(slave));
+			const episodeText = channel.episode[epToShow].text;
+			if (episodeText) {
+				if (typeof episodeText === 'function') {
+					$(frag).append(episodeText(slave));
 				} else {
-					$(frag).append(channel.episode[epToShow].text);
+					$(frag).append(episodeText);
 				}
 			}
 			if (channel.outro) {
diff --git a/src/pregmod/FCTV/FCTVshows.js b/src/pregmod/FCTV/FCTVshows.js
index 32944cf7b54ebca94b96200d59300aa679bd6359..1922a44e77c1dad5cef7a4c87b8283973195dd38 100644
--- a/src/pregmod/FCTV/FCTVshows.js
+++ b/src/pregmod/FCTV/FCTVshows.js
@@ -1,8 +1,4 @@
-/**
- * @typedef {object<string, App.Entity.SlaveState>} FctvActor
- */
-
-/** @type {object.<string, FctvActor>} */
+/** @type {Object.<string, App.Entity.SlaveState>} */
 App.Data.FCTV.actors = {
 	get millie() {
 		const slave = BaseSlave();
@@ -109,7 +105,7 @@ App.Data.FCTV.actors = {
 	},
 	get premiumVirgin() {
 		let slave = GenerateNewSlave("XX", {
-			disableDisability: 1, slaveOneTimeMinAge: (V.fertilityAge + 2), slaveOneTimeMaxAge: 18, ageOverridesPedoMode: 1
+			disableDisability: 1, minAge: (V.fertilityAge + 2), maxAge: 18, ageOverridesPedoMode: 1
 		});
 		slave.devotion = jsRandom(60, 90);
 		slave.weight = jsRandom(-10, 10);
@@ -154,7 +150,7 @@ App.Data.FCTV.actors = {
 	},
 	get hyperPregnant() {
 		let slave = GenerateNewSlave("XX", {
-			disableDisability: 1, slaveOneTimeMinAge: (V.fertilityAge + 3), slaveOneTimeMaxAge: 20, ageOverridesPedoMode: 1
+			disableDisability: 1, minAge: (V.fertilityAge + 3), maxAge: 20, ageOverridesPedoMode: 1
 		});
 		slave.weight = jsRandom(10, 20);
 		slave.waist = jsRandom(-25, 25);
@@ -203,7 +199,7 @@ App.Data.FCTV.actors = {
 	},
 	get superfetation() { // superfetation
 		let slave = GenerateNewSlave("XX", {
-			disableDisability: 1, slaveOneTimeMinAge: (V.fertilityAge + 4), slaveOneTimeMaxAge: 24, ageOverridesPedoMode: 1
+			disableDisability: 1, minAge: (V.fertilityAge + 4), maxAge: 24, ageOverridesPedoMode: 1
 		});
 
 		slave.weight = jsRandom(20, 40);
@@ -246,7 +242,7 @@ App.Data.FCTV.actors = {
 	},
 	get MILF() { // MILF
 		let slave = GenerateNewSlave("XX", {
-			disableDisability: 1, slaveOneTimeMinAge: 36, slaveOneTimeMaxAge: 40, ageOverridesPedoMode: 1
+			disableDisability: 1, minAge: 36, maxAge: 40, ageOverridesPedoMode: 1
 		});
 		slave.weight = jsRandom(20, 90);
 		slave.waist = jsRandom(-45, 45);
@@ -284,7 +280,7 @@ App.Data.FCTV.actors = {
 		return slave;
 	},
 	get youngHottie() { // discount young hottie
-		let slave = GenerateNewSlave("XX", {disableDisability: 1, slaveOneTimeMaxAge: 25, ageOverridesPedoMode: 1});
+		let slave = GenerateNewSlave("XX", {disableDisability: 1, maxAge: 25, ageOverridesPedoMode: 1});
 
 		slave.face = jsRandom(70, 100);
 		slave.weight = jsRandom(-5, 10);
@@ -318,7 +314,7 @@ App.Data.FCTV.actors = {
 		return slave;
 	},
 	get hugeBalls() { // huge balls
-		let slave = GenerateNewSlave("XY", {disableDisability: 1, slaveOneTimeMaxAge: 25, ageOverridesPedoMode: 1});
+		let slave = GenerateNewSlave("XY", {disableDisability: 1, maxAge: 25, ageOverridesPedoMode: 1});
 
 		slave.anus = 2;
 		slave.balls = jsRandom(20, 35);
@@ -334,7 +330,7 @@ App.Data.FCTV.actors = {
 		return slave;
 	},
 	get mpreg() { // mpreg dickgirl
-		let slave = GenerateNewSlave("XY", {disableDisability: 1, slaveOneTimeMaxAge: 22, ageOverridesPedoMode: 1});
+		let slave = GenerateNewSlave("XY", {disableDisability: 1, maxAge: 22, ageOverridesPedoMode: 1});
 		slave.anus = 2;
 		slave.vagina = 1;
 		slave.ovaries = 0;
@@ -409,14 +405,14 @@ App.Data.FCTV.actors = {
 	},
 	get hostess() {
 		const gender = (V.seeDicks === 100) ? "XY" : "XX";
-		let races = 0;
+		let races = [];
 		if (V.arcologies[0].FSSupremacistLawME === 1) {
-			races = V.arcologies[0].FSSupremacistRace;
+			races = [V.arcologies[0].FSSupremacistRace];
 		} else if (V.arcologies[0].FSSubjugationistLawME === 1) {
 			races = setup.filterRacesLowercase.filter(race => race !== V.arcologies[0].FSSubjugationistRace);
 		}
 		const slave = GenerateNewSlave(gender, {
-			ageOverridesPedoMode: 1, oneTimeDisableDisability: 1, slaveOneTimeMinAge: 25, slaveOneTimeMaxAge: 35, fixedRace: races.jsRandom()
+			ageOverridesPedoMode: 1, disableDisability: 1, minAge: 25, maxAge: 35, race: races.random()
 		});
 		slave.devotion = 45;
 		slave.trust = 55;
@@ -438,14 +434,14 @@ App.Data.FCTV.actors = {
 	},
 	get scientist() {
 		const gender = (V.seeDicks === 0) ? "XY" : "XX";
-		let races = 0;
+		let races = [];
 		if (V.arcologies[0].FSSupremacistLawME === 1) {
-			races = V.arcologies[0].FSSupremacistRace;
+			races = [V.arcologies[0].FSSupremacistRace];
 		} else if (V.arcologies[0].FSSubjugationistLawME === 1) {
 			races = setup.filterRacesLowercase.filter(race => race !== V.arcologies[0].FSSubjugationistRace);
 		}
 		const slave = GenerateNewSlave(gender, {
-			ageOverridesPedoMode: 1, oneTimeDisableDisability: 1, slaveOneTimeMinAge: 25, slaveOneTimeMaxAge: 35, fixedRace: races.jsRandom()
+			ageOverridesPedoMode: 1, disableDisability: 1, minAge: 25, maxAge: 35, race: races.random()
 		});
 
 		slave.devotion = 0;
@@ -470,18 +466,18 @@ App.Data.FCTV.actors = {
 	},
 	get nun() {
 		const gender = (V.seeDicks === 100) ? "XY" : "XX";
-		let races = 0;
+		let races = [];
 		if (V.arcologies[0].FSSupremacistLawME === 1) {
-			races = V.arcologies[0].FSSupremacistRace;
+			races = [V.arcologies[0].FSSupremacistRace];
 		} else if (V.arcologies[0].FSSubjugationistLawME === 1) {
 			races = setup.filterRacesLowercase.filter(race => race !== V.arcologies[0].FSSubjugationistRace);
 		}
 		const slave = GenerateNewSlave(gender, {
-			ageOverridesPedoMode: 1, oneTimeDisableDisability: 1, slaveOneTimeMinAge: 25, slaveOneTimeMaxAge: 35, fixedRace: races.jsRandom()
+			ageOverridesPedoMode: 1, disableDisability: 1, minAge: 25, maxAge: 35, race: races.random()
 		});
 
 		slave.devotion = jsRandom(45, 60);
-		slave.trust = jsRandom(-10);
+		slave.trust = jsRandom(-10, 0);
 		slave.muscles = 30;
 		slave.hLength = 1;
 		slave.hStyle = "buzzcut";
@@ -517,17 +513,18 @@ App.Data.FCTV.actors = {
 /**
  * @typedef {object} FctvChannel
  * @property {FctvTags} [tags]
+ * @property {boolean} [disableSelection]
  * @property {boolean} loop After an initial viewing, should the episodes continue to play in order?
- * @property {string} intro
+ * @property {string} [intro]
  * @property {FctvEpisode[]} episode
- * @property {function(App.Entity.SlaveState, [number]):string} outro Takes slave and episode number
+ * @property {function(App.Entity.SlaveState, number):string | Node} [outro] Takes slave and episode number
  */
 
 /**
  * @typedef {object} FctvEpisode
  * @property {FctvTags} [tags]
  * @property {App.Entity.SlaveState[]} [slaves]
- * @property {string} text HTML embedded
+ * @property {(function(App.Entity.SlaveState):string) | string} text HTML embedded
  */
 
 /**
@@ -537,9 +534,10 @@ App.Data.FCTV.actors = {
  * @property {boolean} [loli]
  * @property {boolean} [extreme]
  * @property {boolean} [dicks]
+ * @property {boolean} [incest]
  */
 
-/** @type {object.<number, FctvChannel>} */
+/** @type {Object.<number, FctvChannel>} */
 App.Data.FCTV.channels = {
 	0: { // News
 		tags: {},
@@ -662,17 +660,17 @@ App.Data.FCTV.channels = {
 					r.push(`<p>The montage is overlaid with a narrator's voice: "12 of Canadia Arcology's most attractive women are all competing for the privilege of having the arcology owner's children. Clint Miles has desirable genes, and these ladies are determined to prove their worth as gestators. And here in Canadia, there are no restrictions on fertility drugs for the winner, so the competition this season is fierce! ${V.FCTV.channel.two} ladies have already been sent packing, who will be Canadia's... Next Top Breeder!?" The title finally pops up, redundantly labeling the show as 'Next Top Breeder: Canadia'.`);
 					if (MSL >= 1) {
 						r.push(`</p><p>You don't spend very much time actually watching the show; the randy opening, perverted competitions, and constant talk of creampies quickly has`);
-						if (MSL >= 1 && S.Concubine !== 0) {
+						if (MSL >= 1 && S.Concubine) {
 							r.push(`<span class="pink">${S.Concubine.slaveName}</span> eager for some attention from ${getPronouns(S.Concubine).possessive} own arcology owner. Of course, the same could be said for the other eager slaves living in your bedroom, and the situation quickly devolves into a lust-filled`);
 							if (MSL > 1) {
 								r.push(`orgy.`);
 							} else {
 								r.push(`threesome.`);
 							}
-						} else if (MSL === 0 && S.Concubine !== 0) {
+						} else if (MSL === 0 && S.Concubine) {
 							const {his2, him2, he2} = getPronouns(S.Concubine).appendSuffix(`2`);
 							r.push(`<span class="pink">${S.Concubine.slaveName}</span> eager for some attention from ${his2} own arcology owner. You've trained ${him2} well, and ${he2} knows exactly how to please you. You spend the rest of the evening doing something a lot more fun than watching reality TV.`);
-						} else if (MSL >= 1 && S.Concubine === 0) {
+						} else if (MSL >= 1 && !S.Concubine) {
 							r.push(`the pleasure slaves in your bed eager for some attention from their own arcology owner. You spend the rest of the evening doing something a lot more fun than watching reality TV.`);
 						}
 					}
@@ -1169,6 +1167,7 @@ App.Data.FCTV.channels = {
 		intro: `which is currently showing a preview of the how-to series "Extreme Gestation for Fun and Profit", hosted by Millie. It seems like the show's going to cover topics ranging from hyper-pregnancy to broodmother implants, and even hints and some sort of medical technique to allow anal pregnancy in males.`,
 		episode: [
 			{
+				text: null,
 				slaves: [
 					App.Data.FCTV.actors.millie
 				],
@@ -1501,8 +1500,8 @@ App.Data.FCTV.channels = {
 				},
 				get text() {
 					const r = [];
-					const {his} = S.Concubine ? getPronouns(S.Concubine) : {};
-					const {title: Master} = canTalk(S.Concubine) ? getEnunciation(S.Concubine) : {};
+					const {He = '', him = '', his = ''} = S.Concubine ? getPronouns(S.Concubine) : {};
+					const {title: Master = ''} = canTalk(S.Concubine) ? getEnunciation(S.Concubine) : {};
 
 					if (FCTV.channelCount(11, 1, 'gt')) {
 						r.push(`, once again,`);
@@ -1510,7 +1509,7 @@ App.Data.FCTV.channels = {
 					r.push(`which is currently showing an infomercial attempting to sell a product named "sag-B-gone" that claims to be able to prevent breasts from naturally sagging under their own weight.</p><p>`);
 					if (V.purchasedSagBGone === 1) {
 						r.push(`You've already made the mistake of ordering the sham of a product. While it gave you a great excuse to fondle breasts, it's not like you needed one in the first place.</p>`);
-						if (S.Concubine !== 0 && canTalk(S.Concubine)) {
+						if (S.Concubine && canTalk(S.Concubine)) {
 							r.push(`<p>`);
 							r.push(Spoken(S.Concubine, `"I told you it wouldn't work, ${Master}. Plus you know you can touch these anytime!"`));
 							r.push(`${S.Concubine.slaveName} shakes ${his} chest at you.</p>`);
@@ -1526,7 +1525,7 @@ App.Data.FCTV.channels = {
 							if (V.PC.dick !== 0) {
 								r.push(`At the very least it should make for some decent lubricant for a titfuck.`);
 							}
-							if (S.Concubine !== 0) {
+							if (S.Concubine) {
 								r.push(`</p><p>`);
 								if (S.Concubine.boobs > 2000 && S.Concubine.boobShape === "saggy") {
 									r.push(S.Concubine.slaveName);
@@ -2008,26 +2007,26 @@ App.Data.FCTV.channels = {
 						r.push(`appreciating the life growing within you and what future prospects may await it.</p>`);
 					} else if (V.PC.dick >= 1) {
 						r.push(`<p>Stunned and fully erect, you inexplicably feel the urge to creampie a pussy, so you`);
-						if (S.Concubine !== 0 && S.Concubine.vagina > 0 && canDoVaginal(S.Concubine)) {
+						if (S.Concubine && S.Concubine.vagina > 0 && canDoVaginal(S.Concubine)) {
 							const {him} = getPronouns(S.Concubine);
 							r.push(`grab ${S.Concubine.slaveName} and recreate the entire ending with ${him}.`);
 							S.Concubine.counter.vaginal++;
 							V.vaginalTotal++;
 							if (canImpreg(S.Concubine, V.PC)) {
-								r.push(knockMeUp(S.Concubine, 10, 0, -1, 1));
+								r.push(knockMeUp(S.Concubine, 10, 0, -1, true));
 							}
 						} else if (V.fuckSlaves > 0) {
 							r.push(`grab the nearest slave watching with you, who is overjoyed to recreate the entire ending with you.`);
 						} else {
-							r.push(`make your way to the slave dormitory and pick out the perfect ${slave}.`);
+							r.push(`make your way to the slave dormitory and pick out the perfect slave.`);
 						}
 						r.push(`You've never had a more hope-filled orgasm.</p>`);
 					} else if (V.PC.vagina >= 1) {
 						r.push(`<p>Stunned and soaking wet, you hurry to`);
-						if (S.Concubine !== 0 && canPenetrate(S.Concubine) && canImpreg(V.PC, S.Concubine) && (V.policies.sexualOpenness === 1 || S.Concubine.toyHole === "dick")) {
+						if (S.Concubine && canPenetrate(S.Concubine) && canImpreg(V.PC, S.Concubine) && (V.policies.sexualOpenness === 1 || S.Concubine.toyHole === "dick")) {
 							const {him} = getPronouns(S.Concubine);
 							r.push(`get ${S.Concubine.slaveName} nice and hard before recreating the entire ending with ${him}. You've never had a more hope-filled orgasm.`);
-							r.push(knockMeUp(V.PC, 10, 0, S.Concubine.ID, 1));
+							r.push(knockMeUp(V.PC, 10, 0, S.Concubine.ID, true));
 							S.Concubine.counter.penetrative++;
 							V.penetrativeTotal++;
 						} else if (V.policies.sexualOpenness === 1) {
@@ -2113,7 +2112,7 @@ App.Data.FCTV.channels = {
 			// All actors are at least 18
 			const r = [];
 			r.push(`<p>As you snuggle in for the night`);
-			if (S.Concubine !== 0) {
+			if (S.Concubine) {
 				r.push(`with your concubine, you`);
 			} else {
 				r.push(`you`);