From 68b3ac7cb94195738e240b427d4185914a15e2b7 Mon Sep 17 00:00:00 2001
From: Svornost <11434-svornost@users.noreply.gitgud.io>
Date: Wed, 9 Dec 2020 21:17:08 -0800
Subject: [PATCH] Rework gingering as a proxy wrapper for the slave object. 
 Remove all the gingering globals and stray functions.  Type fixes for
 markets.

---
 devTools/types/FC/human.d.ts             |   6 +
 devTools/types/FC/misc.d.ts              |   3 +-
 js/003-data/gameVariableData.js          |   8 --
 src/descriptions/familySummaries.js      |   2 +-
 src/endWeek/endWeek.js                   |   1 -
 src/endWeek/nextWeek/resetGlobals.js     |   3 -
 src/js/SlaveState.js                     |   4 +-
 src/js/assayJS.js                        |   8 +-
 src/js/health.js                         |  21 +++-
 src/js/slaveSummaryHelpers.js            |   4 +-
 src/markets/bulkSlave/bulkSlaveIntro.js  |  17 +--
 src/markets/marketUI.js                  |   8 +-
 src/npc/children/longChildDescription.js |  23 +---
 src/npc/descriptions/boobs/boobs.js      |   4 +-
 src/npc/descriptions/butt/anus.js        |   4 +-
 src/npc/descriptions/crotch/dick.js      |  12 +-
 src/npc/descriptions/crotch/vagina.js    |   9 +-
 src/npc/descriptions/longSlave.js        |  76 ++++++++++--
 src/npc/generate/generateMarketSlave.js  |   6 +-
 src/npc/generate/lawCompliance.js        |   2 -
 src/npc/generate/newSlaveIntro.js        |  50 ++++----
 src/npc/generate/slaveGenerationJS.js    | 141 -----------------------
 src/player/js/PlayerState.js             |   3 +-
 23 files changed, 163 insertions(+), 252 deletions(-)

diff --git a/devTools/types/FC/human.d.ts b/devTools/types/FC/human.d.ts
index 83a96210997..35c15fc8a87 100644
--- a/devTools/types/FC/human.d.ts
+++ b/devTools/types/FC/human.d.ts
@@ -12,6 +12,12 @@ declare global {
 			removedLimbs?: number[];
 		}
 
+		export interface GingeredSlave extends SlaveState {
+			// note that all members are optional...GingeredSlave and SlaveState are bidirectionally interchangable
+			gingering?: InstanceType<typeof App.Entity.GingeringParameters>;
+			beforeGingering?: SlaveState;
+		}
+
 		export type SlaveUpdate = DeepPartialSlaveState;
 
 		//#region SlaveState types
diff --git a/devTools/types/FC/misc.d.ts b/devTools/types/FC/misc.d.ts
index ffdc266b34a..1fe6353be8b 100644
--- a/devTools/types/FC/misc.d.ts
+++ b/devTools/types/FC/misc.d.ts
@@ -2,7 +2,8 @@ declare namespace FC {
 	type SlaveSchoolName = "GRI" | "HA" | "NUL" | "SCP" | "TCR" | "TFS" | "TGA" | "TSS" | "LDE" | "TUO";
 	type LawlessMarkets = "generic" | "gangs and smugglers" | "heap" | "indentures" | "low tier criminals" | "military prison" | "neighbor" |
 		"wetware" | "white collar" | SlaveSchoolName;
-	type SlaveMarketName = LawlessMarkets | "corporate";
+	type OrdinaryMarkets = "kidnappers" | "trainers" | "hunters" | "raiders" | "underage raiders" | "corporate";
+	type SlaveMarketName = LawlessMarkets | OrdinaryMarkets;
 	type Gingering = Zeroable<"antidepressant" | "depressant" | "stimulant" | "vasoconstrictor" | "vasodilator" | "aphrodisiac" | "ginger">;
 	type GingeringDetection = Zeroable<"slaver" | "mercenary" | "force">;
 	type SlaveActs = "PCChildrenFathered" | "PCKnockedUp" | "anal" | "births" | "birthsTotal" | "cum" | "laborCount" | "mammary" | "milk" | "oral" | "penetrative" | "pitKills" | "miscarriages" | "publicUse" | "slavesFathered" | "slavesKnockedUp" | "vaginal" | "abortions" | "birth";
diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js
index ea9907a967b..f4ffc5d9e72 100644
--- a/js/003-data/gameVariableData.js
+++ b/js/003-data/gameVariableData.js
@@ -1029,14 +1029,6 @@ App.Data.resetOnNGPlus = {
 	mercenariesHelpCorp: 0,
 	personalArms: 0,
 
-	/** @type {FC.Gingering} */
-	gingering: 0,
-	/** @type {FC.SlaveStateOrZero} */
-	beforeGingering: 0,
-	/** @type {FC.Bool} */
-	gingeringDetected: 0,
-	/** @type {FC.GingeringDetection} */
-	gingeringDetection: 0,
 	surgeryDescription: 0,
 	encyclopedia: "How to Play",
 
diff --git a/src/descriptions/familySummaries.js b/src/descriptions/familySummaries.js
index b23198a38f2..ab159c9683f 100644
--- a/src/descriptions/familySummaries.js
+++ b/src/descriptions/familySummaries.js
@@ -477,7 +477,7 @@ App.Desc.family = (function() {
 			}
 		}
 
-		if (slave.clone) {
+		if (typeof slave.clone === "string") {
 			r.push(`${He} is`);
 			if (slave.cloneID === -1) {
 				r.push(`your clone.`);
diff --git a/src/endWeek/endWeek.js b/src/endWeek/endWeek.js
index 871f5566d3a..afa7d21b135 100644
--- a/src/endWeek/endWeek.js
+++ b/src/endWeek/endWeek.js
@@ -29,7 +29,6 @@ globalThis.endWeek = (function() {
 	}
 
 	function resetSlaveMarkets() {
-		V.gingering = 0;
 		V.market = null;
 		for (const school of App.Data.misc.schools.keys()) {
 			V[school].schoolSale = 0;
diff --git a/src/endWeek/nextWeek/resetGlobals.js b/src/endWeek/nextWeek/resetGlobals.js
index e1a63cefc03..2b3143a1b5e 100644
--- a/src/endWeek/nextWeek/resetGlobals.js
+++ b/src/endWeek/nextWeek/resetGlobals.js
@@ -66,9 +66,6 @@ App.EndWeek.resetGlobals = function() {
 	V.relative = 0;
 	V.relative2 = 0;
 
-	// Slave Objects that never get zeroed so null them here. Second most memory eaten up.
-	V.beforeGingering = null;
-
 	// Strings Memory varies.
 	V.buyer = "";
 	V.desc = "";
diff --git a/src/js/SlaveState.js b/src/js/SlaveState.js
index fc2c38abf9e..ca30c0cf853 100644
--- a/src/js/SlaveState.js
+++ b/src/js/SlaveState.js
@@ -2537,8 +2537,8 @@ App.Entity.SlaveState = class SlaveState {
 		 *
 		 * 0: no; 1: yes, comforting; 2: yes, terrifying */
 		this.tankBaby = 0;
-		/** Is the slave a clone?
-		 * @type {FC.Bool}
+		/** Is the slave a clone?  If so, what is the original slave's name?
+		 * @type {FC.Zeroable<string>}
 		 * 0: no; 1: yes */
 		this.clone = 0;
 		/** ID she was cloned from */
diff --git a/src/js/assayJS.js b/src/js/assayJS.js
index 98536871a96..b4e64a44434 100644
--- a/src/js/assayJS.js
+++ b/src/js/assayJS.js
@@ -112,12 +112,18 @@ globalThis.applyGeneticColor = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.GingeredSlave} slave
  */
 globalThis.newSlave = function(slave) {
 	if (getSlave(slave.ID)) {
 		throw "Slave already exists";
 	}
+
+	// if the slave is gingered, remove the gingering proxy
+	if (slave.beforeGingering) {
+		slave = slave.beforeGingering;
+	}
+
 	if (slave.override_Race !== 1) {
 		slave.origRace = slave.race;
 	}
diff --git a/src/js/health.js b/src/js/health.js
index 20613e8d670..74e0157dedf 100644
--- a/src/js/health.js
+++ b/src/js/health.js
@@ -95,13 +95,14 @@ globalThis.improveCondition = function(slave, condition) {
 };
 
 /**
- * Updates slave.health.health
+ * Computes the aggregate health value for a slave given an assumed condition value.
+ * Generally should not be called directly (use updateHealth instead); needed for health gingering.
  * @param {App.Entity.SlaveState} slave
- * @returns {void}
+ * @param {number} condition
+ * @returns {number}
  */
-globalThis.updateHealth = function(slave) {
+globalThis.computeAggregateHealth = function(slave, condition) {
 	const H = slave.health;
-	const condition = H.condition;
 
 	// Converting the other variables to better fit the same scale as .condition
 	const damage = (40 - H.shortDamage - H.longDamage) * 2.5; // 100 / -inf
@@ -109,7 +110,17 @@ globalThis.updateHealth = function(slave) {
 	const illness = (5 - Math.pow(H.illness, 2)) * 20; // 100 / -400
 
 	// Assigning weights to the different components and aggregating
-	H.health = condition * 0.6 + damage * 0.2 + tired * 0.1 - illness * 0.1;
+	return condition * 0.6 + damage * 0.2 + tired * 0.1 - illness * 0.1;
+};
+
+/**
+ * Updates slave.health.health
+ * @param {App.Entity.SlaveState} slave
+ * @returns {void}
+ */
+globalThis.updateHealth = function(slave) {
+	const H = slave.health;
+	H.health = computeAggregateHealth(slave, H.condition);
 };
 
 /**
diff --git a/src/js/slaveSummaryHelpers.js b/src/js/slaveSummaryHelpers.js
index 44131d171cb..8f0f33ba1c9 100644
--- a/src/js/slaveSummaryHelpers.js
+++ b/src/js/slaveSummaryHelpers.js
@@ -1510,7 +1510,7 @@ App.UI.SlaveSummaryImpl = function() {
 		 * @returns {void}
 		 */
 		function short_clone(slave, c) {
-			if (slave.clone !== 0) {
+			if (typeof slave.clone === "string") {
 				makeSpan(c, "Clone");
 			}
 		}
@@ -1554,7 +1554,7 @@ App.UI.SlaveSummaryImpl = function() {
 		 * @returns {void}
 		 */
 		function long_clone(slave, c) {
-			if (slave.clone !== 0) {
+			if (typeof slave.clone === "string") {
 				makeSpan(c, `Clone of ${slave.clone}.`, "skyblue");
 			}
 		}
diff --git a/src/markets/bulkSlave/bulkSlaveIntro.js b/src/markets/bulkSlave/bulkSlaveIntro.js
index faf979a0d19..9e76f3dc949 100644
--- a/src/markets/bulkSlave/bulkSlaveIntro.js
+++ b/src/markets/bulkSlave/bulkSlaveIntro.js
@@ -86,12 +86,10 @@ App.Markets.bulkSlaveIntro = function() {
 		/* Set slave to the desired newSlave so that existing code can be used */
 		const _slave = V.market.newSlaves[V.market.newSlaveIndex];
 
-		/* Due to possible gingering, the Long Slave Description must be displayed before the New Slave Intro */
-		/* policies were applied earlier, if needed */
-		el.append(App.Desc.longSlave(_slave, {market: "generic"}));
+		el.append(App.Desc.longSlave(_slave, {market: V.market.slaveMarket}));
 
 		/* Use existing New Slave Intro */
-		el.append(App.UI.newSlaveIntro(_slave));/* calls removeGingering() if needed */
+		el.append(App.UI.newSlaveIntro(_slave));
 
 		/* Override nextButton setting from New Slave Intro */
 		V.nextButton = "Continue";
@@ -139,15 +137,10 @@ App.Markets.bulkSlaveIntro = function() {
 		for (let _i = 0; _i < V.market.numSlaves; _i++) {
 			let slave = (generateMarketSlave(V.market.slaveMarket, V.market.numArcology)).slave;
 			V.slavesSeen++;
-			if (App.Data.misc.lawlessMarkets.includes(V.market.slaveMarket)) {
-				_slaveCost = slaveCost(slave);
-			} else {
-				const _backup = slave; /* backup newly generated slave */
-				App.Desc.lawCompliance(slave, V.market.slaveMarket); /* includes CheckForGingering — slave stats may change, affecting price */
-				_slaveCost = slaveCost(slave);
-				removeGingering(); /* remove gingered state, if applied, so we can apply it again later */
-				slave = _backup; /* restore backup so we can apply Law Compliance again later */
+			if (!App.Data.misc.lawlessMarkets.includes(V.market.slaveMarket)) {
+				App.Desc.lawCompliance(slave, V.market.slaveMarket); /* slave stats may change, affecting price */
 			}
+			_slaveCost = slaveCost(slave);
 
 			/* Adjust _slaveCost according to V.slavesSeen */
 			if (V.slavesSeen > V.slaveMarketLimit) {
diff --git a/src/markets/marketUI.js b/src/markets/marketUI.js
index 3646424fa74..31a3a2f695b 100644
--- a/src/markets/marketUI.js
+++ b/src/markets/marketUI.js
@@ -1,6 +1,6 @@
 /**
  *
- * @param {string} slaveMarket
+ * @param {FC.SlaveMarketName} slaveMarket
  * @param {object} [param1]
  * @param {string} [param1.sTitleSingular]
  * @param {string} [param1.sTitlePlural]
@@ -150,9 +150,9 @@ App.Markets.purchaseFramework = function(slaveMarket, {sTitleSingular = "slave",
 };
 /**
  * @typedef {object} marketGlobal
- * @property {string} slaveMarket
+ * @property {FC.SlaveMarketName} slaveMarket
  * @property {string} introType
- * @property {Array} newSlaves
+ * @property {Array<FC.GingeredSlave>} newSlaves
  * @property {number} newSlaveIndex
  * @property {number} newSlavesDone
  * @property {number} numSlaves
@@ -161,7 +161,7 @@ App.Markets.purchaseFramework = function(slaveMarket, {sTitleSingular = "slave",
 
 /** @this {marketGlobal} */
 App.Markets.GlobalVariable = function() {
-	this.slaveMarket = "";
+	this.slaveMarket = "kidnappers";
 	this.introType = "";
 	this.newSlaves = [];
 	this.newSlaveIndex = 0;
diff --git a/src/npc/children/longChildDescription.js b/src/npc/children/longChildDescription.js
index 34ab09241ff..9d25f7664b8 100644
--- a/src/npc/children/longChildDescription.js
+++ b/src/npc/children/longChildDescription.js
@@ -426,10 +426,6 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 			r += `${His} asshole has seen hard use lately and looks a little sore. `;
 		}
 
-		if (market && V.gingering === "ginger") {
-			r += `${His} asshole looks unusually puffy and sore. ${He}'s either been cruelly assraped lately, or ${he}'s had an irritant placed in ${his} anus. `;
-		}
-
 		r += accessories.buttplug(child);
 
 		if (V.showBodyMods) {
@@ -1303,13 +1299,6 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 				} else if (child.prostate > 1) {
 					r += `${He}'s got a string of precum dangling from the tip of ${his} cock; ${his} artificially hyperactive prostate keeps ${him} that way. `;
 				}
-			} else if (market && V.gingering === "vasodilator") {
-				r += `${He}'s painfully erect. `;
-				if (child.prostate > 2) {
-					r += `The area above ${his} crotch has a slight swell to it from ${his} prostate implant. A constant dribble of precum drips from the tip of ${his} cock; ${his} artificially hyperactive prostate keeps ${him} that way. `;
-				} else if (child.prostate > 1) {
-					r += `${He}'s got a string of precum dangling from the tip of ${his} cock; ${his} artificially hyperactive prostate keeps ${him} that way. `;
-				}
 			} else if (child.aphrodisiacs > 1 || (child.inflationType === "aphrodisiac" && child.inflation > 1)) {
 				r += `The aphrodisiacs have ${his} cock painfully hard${child.drugs === "hormone blockers" || !(child.balls > 0 ? child.hormoneBalance < 100 : child.hormoneBalance <= -100) || child.ballType === "sterile" ? `, despite ${his} usual inability to achieve erection` : ``}. `;
 				if (child.prostate > 2) {
@@ -1609,7 +1598,7 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 			if (child.foreskin > 0) {
 				if (child.foreskin - child.dick < -1) {
 					r += `${His} cockhead is much too large for ${his} foreskin, probably as a result of recent penis growth it hasn't had time to stretch to accommodate yet. `;
-					if (canAchieveErection(child) && (child.devotion > 20 || child.aphrodisiacs > 0 || market && V.gingering === "vasodilator" || child.inflationType === "aphrodisiac" || child.drugs === "priapism agents")) {
+					if (canAchieveErection(child) && (child.devotion > 20 || child.aphrodisiacs > 0 || child.inflationType === "aphrodisiac" || child.drugs === "priapism agents")) {
 						r += `The bit of erect dickhead visible at the tip of the uncomfortably stretched skin is an angry color from being squeezed so hard. `;
 					} else if (canAchieveErection(child)) {
 						r += `${He} isn't erect right now, but getting a hard-on will probably be very uncomfortable for ${him}. `;
@@ -1618,7 +1607,7 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 					}
 				} else if (child.foreskin - child.dick < 0) {
 					r += `${His} foreskin is stretched by ${his} dickhead, probably as a result of recent penis growth it hasn't had time to get used to yet. `;
-					if (canAchieveErection(child) && (child.devotion > 20 || child.aphrodisiacs > 0 || market && V.gingering === "vasodilator" || child.inflationType === "aphrodisiac" || child.drugs === "priapism agents")) {
+					if (canAchieveErection(child) && (child.devotion > 20 || child.aphrodisiacs > 0 || child.inflationType === "aphrodisiac" || child.drugs === "priapism agents")) {
 						r += `${His} erection has stretched the skin there taut. `;
 					} else if (canAchieveErection(child)) {
 						r += `${He} isn't erect right now, but getting a hard-on will probably be a bit uncomfortable for ${him}. `;
@@ -1627,7 +1616,7 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 					}
 				} else if (child.foreskin - child.dick > 0) {
 					r += `${His} foreskin seems too large for ${his} dick, probably as a result of recent penis shrinkage. `;
-					if (canAchieveErection(child) && (child.devotion > 20 || child.aphrodisiacs > 0 || market && V.gingering === "vasodilator" || child.inflationType === "aphrodisiac" || child.drugs === "priapism agents")) {
+					if (canAchieveErection(child) && (child.devotion > 20 || child.aphrodisiacs > 0 || child.inflationType === "aphrodisiac" || child.drugs === "priapism agents")) {
 						r += `${His} erection cannot fully retract it, though it's loose enough that this doesn't look uncomfortable. `;
 					} else if (canAchieveErection(child)) {
 						r += `${He} isn't erect right now, making the tip of ${his} dick look shriveled. `;
@@ -1636,7 +1625,7 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 					}
 				} else if (child.foreskin - child.dick > 1) {
 					r += `${His} foreskin is far too large for ${his} dick, probably as a result of recent penis shrinkage. `;
-					if (canAchieveErection(child) && (child.devotion > 20 || child.aphrodisiacs > 0 || market && V.gingering === "vasodilator" || child.inflationType === "aphrodisiac" || child.drugs === "priapism agents")) {
+					if (canAchieveErection(child) && (child.devotion > 20 || child.aphrodisiacs > 0 || child.inflationType === "aphrodisiac" || child.drugs === "priapism agents")) {
 						r += `${His} erection cannot retract it at all, though it's loose enough that this doesn't look uncomfortable. Orgasming, though, will likely produce a dribbling mess. `;
 					} else if (canAchieveErection(child)) {
 						r += `${He} isn't erect right now, so the excess skin droops lamely off ${his} cockhead. `;
@@ -5429,7 +5418,7 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 						}
 					}
 				} else {
-					if (child.aphrodisiacs > 0 || (market && V.gingering === "vasodilator") || child.inflationType === "aphrodisiac") {
+					if (child.aphrodisiacs > 0 || child.inflationType === "aphrodisiac") {
 						r += `The combination of the aphrodisiacs and ${his} natural tendency to produce a lot of female lubricant is having a drastic effect. ${His} cunt is absolutely beribboned with femcum, and ${he} smells strongly of wet, clean pussy. `;
 					} else if (child.energy > 95) {
 						r += `${He} has a naturally wet cunt, and in combination with ${his} nymphomania, it's soaking. ${He} smells of good clean female arousal. `;
@@ -6127,7 +6116,7 @@ App.Facilities.Nursery.LongChildDescription = function(child, {market = 0, event
 
 	if (!market) {
 		if (V.clinic && V.clinicUpgradeScanner) {
-			r += `${capFirstChar(V.clinicName)}'s scanners `
+			r += `${capFirstChar(V.clinicName)}'s scanners `;
 			if (child.chem > 15) {
 				r += `score long term carcinogenic buildup in ${his} body at <span class="cyan">${Math.ceil(child.chem/10)}.</span> `;
 			} else {
diff --git a/src/npc/descriptions/boobs/boobs.js b/src/npc/descriptions/boobs/boobs.js
index 366846f2b8a..2d8c25c3ccc 100644
--- a/src/npc/descriptions/boobs/boobs.js
+++ b/src/npc/descriptions/boobs/boobs.js
@@ -218,8 +218,8 @@ App.Desc.boobs = function() {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @param {object} params
- 	 * @param {FC.Zeroable<FC.SlaveMarketName>} [params.market]
- 	 * @param {boolean} [params.eventDescription]
+	 * @param {FC.Zeroable<FC.SlaveMarketName>} [params.market]
+	 * @param {boolean} [params.eventDescription]
 	 * @returns {string}
 	 */
 	function describe(slave, {market, eventDescription} = {}) {
diff --git a/src/npc/descriptions/butt/anus.js b/src/npc/descriptions/butt/anus.js
index 1a5cbe7675f..ce85e1538c6 100644
--- a/src/npc/descriptions/butt/anus.js
+++ b/src/npc/descriptions/butt/anus.js
@@ -1,5 +1,5 @@
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.GingeredSlave} slave
  * @param {object} params
  * @param {FC.Zeroable<FC.SlaveMarketName>} [params.market]
  * @param {boolean} [params.eventDescription]
@@ -99,7 +99,7 @@ App.Desc.anus = function(slave, {market, eventDescription} = {}) {
 		r.push(`${His} asshole has seen hard use lately and looks a little sore.`);
 	}
 
-	if (market && V.gingering === "ginger") {
+	if (slave.gingering && slave.gingering.type === "ginger") {
 		r.push(`${His} asshole looks unusually puffy and sore. ${He}'s either been cruelly assraped lately, or ${he}'s had an irritant placed in ${his} anus.`);
 	}
 
diff --git a/src/npc/descriptions/crotch/dick.js b/src/npc/descriptions/crotch/dick.js
index 1ecbe0a4ab7..8ef311b5618 100644
--- a/src/npc/descriptions/crotch/dick.js
+++ b/src/npc/descriptions/crotch/dick.js
@@ -1,5 +1,5 @@
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.GingeredSlave} slave
  * @param {object} params
  * @param {FC.Zeroable<FC.SlaveMarketName>} [params.market]
  * @param {boolean} [params.eventDescription]
@@ -699,7 +699,7 @@ App.Desc.dick = function(slave, {market, eventDescription} = {}) {
 				} else if (slave.prostate > 1) {
 					r.push(`${He}'s got a string of precum dangling from the tip of ${his} cock; ${his} artificially hyperactive prostate keeps ${him} that way.`);
 				}
-			} else if ((market && V.gingering === "vasodilator")) {
+			} else if (slave.gingering && slave.gingering.type === "vasodilator") {
 				r.push(`${He}'s painfully erect.`);
 				if (slave.prostate > 2) {
 					r.push(`The area above ${his} crotch has a slight swell to it from ${his} prostate implant. A constant dribble of precum drips from the tip of ${his} cock; ${his} artificially hyperactive prostate keeps ${him} that way.`);
@@ -1178,7 +1178,7 @@ App.Desc.dick = function(slave, {market, eventDescription} = {}) {
 			if (slave.foreskin > 0) {
 				if (slave.foreskin - slave.dick < -1) {
 					r.push(`${His} cockhead is much too large for ${his} foreskin, probably as a result of recent penis growth it hasn't had time to stretch to accommodate yet.`);
-					if (canAchieveErection(slave) && ((slave.devotion > 20) || (slave.aphrodisiacs > 0) || (market && V.gingering === "vasodilator") || (slave.inflationType === "aphrodisiac") || (slave.drugs === "priapism agents"))) {
+					if (canAchieveErection(slave) && ((slave.devotion > 20) || (slave.aphrodisiacs > 0) || (slave.gingering && slave.gingering.type === "vasodilator") || (slave.inflationType === "aphrodisiac") || (slave.drugs === "priapism agents"))) {
 						r.push(`The bit of erect dickhead visible at the tip of the uncomfortably stretched skin is an angry color from being squeezed so hard.`);
 					} else if (canAchieveErection(slave)) {
 						r.push(`${He} isn't erect right now, but getting a hard-on will probably be very uncomfortable for ${him}.`);
@@ -1187,7 +1187,7 @@ App.Desc.dick = function(slave, {market, eventDescription} = {}) {
 					}
 				} else if (slave.foreskin - slave.dick === -1) {
 					r.push(`${His} foreskin is stretched by ${his} dickhead, probably as a result of recent penis growth it hasn't had time to get used to yet.`);
-					if (canAchieveErection(slave) && ((slave.devotion > 20) || (slave.aphrodisiacs > 0) || (market && V.gingering === "vasodilator") || (slave.inflationType === "aphrodisiac") || (slave.drugs === "priapism agents"))) {
+					if (canAchieveErection(slave) && ((slave.devotion > 20) || (slave.aphrodisiacs > 0) || (slave.gingering && slave.gingering.type === "vasodilator") || (slave.inflationType === "aphrodisiac") || (slave.drugs === "priapism agents"))) {
 						r.push(`${His} erection has stretched the skin there taut.`);
 					} else if (canAchieveErection(slave)) {
 						r.push(`${He} isn't erect right now, but getting a hard-on will probably be a bit uncomfortable for ${him}.`);
@@ -1196,7 +1196,7 @@ App.Desc.dick = function(slave, {market, eventDescription} = {}) {
 					}
 				} else if (slave.foreskin - slave.dick === 1) {
 					r.push(`${His} foreskin seems too large for ${his} dick, probably as a result of recent penis shrinkage.`);
-					if (canAchieveErection(slave) && ((slave.devotion > 20) || (slave.aphrodisiacs > 0) || (market && V.gingering === "vasodilator") || (slave.inflationType === "aphrodisiac") || (slave.drugs === "priapism agents"))) {
+					if (canAchieveErection(slave) && ((slave.devotion > 20) || (slave.aphrodisiacs > 0) || (slave.gingering && slave.gingering.type === "vasodilator") || (slave.inflationType === "aphrodisiac") || (slave.drugs === "priapism agents"))) {
 						r.push(`${His} erection cannot fully retract it, though it's loose enough that this doesn't look uncomfortable.`);
 					} else if (canAchieveErection(slave)) {
 						r.push(`${He} isn't erect right now, making the tip of ${his} dick look shriveled.`);
@@ -1205,7 +1205,7 @@ App.Desc.dick = function(slave, {market, eventDescription} = {}) {
 					}
 				} else if (slave.foreskin - slave.dick > 1) {
 					r.push(`${His} foreskin is far too large for ${his} dick, probably as a result of recent penis shrinkage.`);
-					if (canAchieveErection(slave) && ((slave.devotion > 20) || (slave.aphrodisiacs > 0) || (market && V.gingering === "vasodilator") || (slave.inflationType === "aphrodisiac") || (slave.drugs === "priapism agents"))) {
+					if (canAchieveErection(slave) && ((slave.devotion > 20) || (slave.aphrodisiacs > 0) || (slave.gingering && slave.gingering.type === "vasodilator") || (slave.inflationType === "aphrodisiac") || (slave.drugs === "priapism agents"))) {
 						r.push(`${His} erection cannot retract it at all, though it's loose enough that this doesn't look uncomfortable. Orgasming, though, will likely produce a dribbling mess.`);
 					} else if (canAchieveErection(slave)) {
 						r.push(`${He} isn't erect right now, so the excess skin droops lamely off ${his} cockhead.`);
diff --git a/src/npc/descriptions/crotch/vagina.js b/src/npc/descriptions/crotch/vagina.js
index bd8d936cf2f..45c1c6ba131 100644
--- a/src/npc/descriptions/crotch/vagina.js
+++ b/src/npc/descriptions/crotch/vagina.js
@@ -1,11 +1,8 @@
 /**
- * @param {App.Entity.SlaveState} slave
- * @param {object} params
- * @param {FC.Zeroable<FC.SlaveMarketName>} [params.market]
- * @param {boolean} [params.eventDescription]
+ * @param {FC.GingeredSlave} slave
  * @returns {string}
  */
-App.Desc.vagina = function(slave, {market, eventDescription} = {}) {
+App.Desc.vagina = function(slave) {
 	const r = [];
 	const {
 		he, him, his, He, His
@@ -189,7 +186,7 @@ App.Desc.vagina = function(slave, {market, eventDescription} = {}) {
 			} else {
 				if (slave.assignment === "work in the dairy" && V.dairyPregSetting > 1) {
 					r.push(`The dildo's ejaculate includes a drug that encourages vaginal lubrication, which is having a drastic effect on ${him}, since ${he}'s already very gifted in that regard. The dildo makes a wet noise every time it thrusts into ${him}, and femcum streams into a catch basin beneath ${him}. The smell of pussy is overwhelming.`);
-				} else if ((slave.aphrodisiacs > 0) || (market && V.gingering === "vasodilator") || (slave.inflationType === "aphrodisiac")) {
+				} else if ((slave.aphrodisiacs > 0) || (slave.gingering && slave.gingering.type === "vasodilator") || (slave.inflationType === "aphrodisiac")) {
 					r.push(`The combination of the aphrodisiacs and ${his} natural tendency to produce a lot of female lubricant is having a drastic effect. ${His} cunt is absolutely beribboned with femcum, and ${he} smells strongly of wet, clean pussy.`);
 				} else if (slave.energy > 95) {
 					r.push(`${He} has a naturally wet cunt, and in combination with ${his} nymphomania, it's soaking. ${He} smells of good clean female arousal.`);
diff --git a/src/npc/descriptions/longSlave.js b/src/npc/descriptions/longSlave.js
index 50c046a11c5..01f26a70524 100644
--- a/src/npc/descriptions/longSlave.js
+++ b/src/npc/descriptions/longSlave.js
@@ -1,9 +1,9 @@
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.GingeredSlave} slave
  * @param {FC.Desc.LongSlaveOptions} params
  * @returns {DocumentFragment}
  */
-App.Desc.longSlave = function(slave = V.activeSlave, {market = 0, eventDescription = false, prisonCrime, noArt} = {}) {
+App.Desc.longSlave = function(slave, {market = 0, eventDescription = false, prisonCrime, noArt} = {}) {
 	const {
 		He, His, him, he, his
 	} = getPronouns(slave);
@@ -49,7 +49,7 @@ App.Desc.longSlave = function(slave = V.activeSlave, {market = 0, eventDescripti
 	if (market && V.ui !== "start") {
 		if (applyLaw === 1) {
 			p.append(`has passed inspection to be sold in your arcology. `);
-			$(p).append(App.Desc.lawCompliance(slave, market)); // includes CheckForGingering
+			$(p).append(App.Desc.lawCompliance(slave, market));
 			p.append(` `);
 		} else {
 			p.append(`is for sale and is available to inspect. `);
@@ -58,6 +58,7 @@ App.Desc.longSlave = function(slave = V.activeSlave, {market = 0, eventDescripti
 				p.append(`${He} ${prisonCrime} `);
 			}
 		}
+		$(p).append(reportGingering(slave));
 		el.appendChild(p);
 
 		p = document.createElement("p");
@@ -672,7 +673,7 @@ App.Desc.longSlave = function(slave = V.activeSlave, {market = 0, eventDescripti
 	}));
 	r.push(App.Desc.mods(slave, "nipple"));
 	r.push(App.Desc.areola(slave, {
-		market: market, eventDescription: eventDescription, applyLaw: applyLaw
+		market: market, eventDescription: eventDescription
 	}));
 	r.push(App.Desc.mods(slave, "areolae"));
 
@@ -708,9 +709,7 @@ App.Desc.longSlave = function(slave = V.activeSlave, {market = 0, eventDescripti
 	r.push(App.Desc.dick(slave, {
 		market: market, eventDescription: eventDescription
 	}));
-	r.push(App.Desc.vagina(slave, {
-		market: market, eventDescription: eventDescription
-	}));
+	r.push(App.Desc.vagina(slave));
 	r.push(App.Desc.anus(slave, {
 		market: market, eventDescription: eventDescription
 	}));
@@ -728,4 +727,67 @@ App.Desc.longSlave = function(slave = V.activeSlave, {market = 0, eventDescripti
 	// clear sale and law flags, if set
 
 	return el;
+
+	/** Reports detected gingering status for a slave
+	 * @param {FC.GingeredSlave} slave
+	 */
+	function reportGingering(slave) {
+		let t = "";
+		if (slave.gingering) {
+			if (slave.gingering.detection === "slaver") {
+				switch (slave.gingering.type) {
+					case "antidepressant":
+						t += `${He} is acting dazed and unfocused. ${He}'s obviously been given antidepressants to make ${him} appear less fearful, and will be considerably less trusting than ${he} seems.`;
+						break;
+					case "depressant":
+						t += `${He} is acting languid and drugged. ${He}'s obviously been given a depressant to make ${him} appear less hateful, and will be considerably less accepting of slavery than ${he} seems.`;
+						break;
+					case "stimulant":
+						t += `${He} is acting twitchy and hyperactive. ${He}'s obviously been given a stimulant to make ${him} seem healthier and more energetic, and is a lot less healthy than ${he} looks.`;
+						break;
+					case "vasoconstrictor":
+						t += `${His} lips have the slightest blue tinge, making it obvious ${he}'s been given a vasoconstrictor. ${His} cock is a lot less of a girldick than it looks right now.`;
+						break;
+					case "vasodilator":
+						t += `${He} has an impressive erection, but it seems quite unconnected to the rest of ${him}, as if ${he} doesn't know what to do with it. ${He}'s obviously been given a vasodilator to make ${his} dick seem a little less pathetic.`;
+						break;
+					case "aphrodisiac":
+						t += `${His} pupils are slightly dilated, ${his} breath comes in fast pants, and ${his} skin is flushed. ${He}'s obviously been given as big of a dose of aphrodisiacs as ${he} can handle without a heart attack.`;
+						break;
+					default:
+						t += `${He} is acting oddly, presenting ${his} ass in an awkward way and acting uncomfortable. ${He}'s obviously had an irritant shoved up ${his} butt to make ${him} act like an anal whore.`;
+				}
+				t += ` It's a trick you're very familiar with, given your <span class="springgreen">training as a slaver.</span>`;
+			} else if (slave.gingering.detected) {
+				switch (slave.gingering.type) {
+					case "antidepressant":
+						t += `${He} is acting dazed and unfocused, like ${he}'s been given antidepressants to make ${him} appear less fearful. ${He} may be considerably less trusting than ${he} seems. `;
+						break;
+					case "depressant":
+						t += `${He} is acting languid and drugged, like ${he}'s been given a depressant to make ${him} appear less hateful. ${He} may be considerably less accepting of slavery than ${he} seems. `;
+						break;
+					case "stimulant":
+						t += `${He} is acting twitchy and hyperactive, like ${he}'s been given a stimulant to make ${him} seem healthier and more energetic. ${He} may be considerably less vital than ${he} seems. `;
+						break;
+					case "vasoconstrictor":
+						t += `${His} lips have the slightest blue tinge, suggesting that ${he} may have been given a vasoconstrictor. If ${he} has, ${his} cock may be considerably less feminine and demure than it now seems. `;
+						break;
+					case "vasodilator":
+						t += `${He} has an impressive erection, but it seems quite unconnected to the rest of ${him}, as if ${he} doesn't know what to do with it. ${He} may have been given a vasodilator. If ${he} has, ${his} cock may be considerably less impressive than it now seems. `;
+						break;
+					case "aphrodisiac":
+						t += `${His} pupils are slightly dilated, ${his} breath comes in fast pants, and ${his} skin is flushed. These are the characteristic symptoms of a dose of aphrodisiacs limited only by a desire to avoid giving ${him} a heart attack. `;
+						break;
+					default:
+						t += `${He} is acting oddly, presenting ${his} ass in an awkward way and acting uncomfortable. ${He} may be considerably less interested in anal sex than ${he} seems. `;
+				}
+				if (slave.gingering.detection === "mercenary") {
+					t += `The nervous seller confirms this in response to a direct inquiry. Your intimidating reputation from your <span class="springgreen">extensive combat training</span> has its uses.`;
+				} else if (slave.gingering.detection === "force") {
+					t += `The nervous seller confirms this in response to a direct inquiry. Your reputation as a <span class="springgreen"> ${PCTitle() ? "man" : "woman"} of blood</span> has its uses.`;
+				}
+			}
+		}
+		return t;
+	}
 };
diff --git a/src/npc/generate/generateMarketSlave.js b/src/npc/generate/generateMarketSlave.js
index f27e294a772..8ad6a40d508 100644
--- a/src/npc/generate/generateMarketSlave.js
+++ b/src/npc/generate/generateMarketSlave.js
@@ -1,8 +1,8 @@
 /* eslint-disable camelcase */
 /**
- * @param {string} [market="kidnappers"]
+ * @param {FC.SlaveMarketName} [market="kidnappers"]
  * @param {number} [numArcology=1] Defaults to 1 (V.arcologies[1]) since it refers to neighboring arcology, and V.arcologies[0] is the player's arcology.
- * @returns {{text: string, slave: object}}
+ * @returns {{text: string, slave: FC.GingeredSlave}}
  */
 globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1) {
 	let r = ``;
@@ -3198,5 +3198,5 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1
 			break;
 		}
 	}
-	return {text: r, slave: slave};
+	return {text: r, slave: getGingeredSlave(slave, market)};
 };
diff --git a/src/npc/generate/lawCompliance.js b/src/npc/generate/lawCompliance.js
index 8dd108b5742..459c1e4c8b0 100644
--- a/src/npc/generate/lawCompliance.js
+++ b/src/npc/generate/lawCompliance.js
@@ -147,8 +147,6 @@ App.Desc.lawCompliance = function(slave, market = 0) {
 		r.push(eugenicsSMRsCount());
 	}
 
-	r.push(checkForGingering(slave, market)); /* may store a backup of slave and make temporary changes; call removeGingering() to retrieve backup before making changes to slave */
-
 	return r.join(" ");
 
 	function FSSlimnessEnthusiastSMR() {
diff --git a/src/npc/generate/newSlaveIntro.js b/src/npc/generate/newSlaveIntro.js
index 235abc56aec..0c149226885 100644
--- a/src/npc/generate/newSlaveIntro.js
+++ b/src/npc/generate/newSlaveIntro.js
@@ -1,5 +1,5 @@
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.GingeredSlave} slave
  * @param {App.Entity.SlaveState} [slave2] recruiter slave, if present in the scene
  * @param {Object} [obj]
  * @param {boolean} [obj.tankBorn]
@@ -23,7 +23,7 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 	let brandTarget = V.brandTarget.primary;
 	let scarTarget = V.scarTarget.primary;
 
-	newSlave(slave); // Add the slave to V.slaves
+	newSlave(slave);
 
 	modSetup();
 
@@ -31,6 +31,10 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 		el.append(inspect());
 	}
 
+	if (slave.beforeGingering) {
+		slave = slave.beforeGingering; // cancel gingering proxy, if it's still attached
+	}
+
 	el.append(choices());
 
 	App.Utils.updateUserButton();  // Make sure the user button is up to date, since V.nextButton may have changed since it was created.
@@ -171,70 +175,66 @@ App.UI.newSlaveIntro = function(slave, slave2, {tankBorn = false, momInterest =
 			r.push(`looking shyly at you and blushing.`);
 		}
 
-		if (V.gingering !== 0 && V.beforeGingering !== 0 && V.beforeGingering.ID === slave.ID) {
-			// extra checks to ensure gingering state is not left over from a different slave that was inspected but not purchased
+		if (slave.gingering) {
 			let seed = "sale";
-			if (V.gingeringDetected === 1) {
-				if (V.gingeringDetection === "slaver") {
+			if (slave.gingering.detected) {
+				if (slave.gingering.detection === "slaver") {
 					seed = "sale, as your slaving experience revealed";
-				} else if (V.gingeringDetection === "mercenary") {
+				} else if (slave.gingering.detection === "mercenary") {
 					seed = "sale, as the seller admitted in the face of your intimidating reputation";
-				} else if (V.gingeringDetection === "force") {
+				} else if (slave.gingering.detection === "force") {
 					seed = "sale, as the seller admitted in the face of your deadly reputation";
 				} else {
 					seed = "sale, as you suspected";
 				}
 			}
 
-			if (V.gingering === "antidepressant") {
+			if (slave.gingering.type === "antidepressant") {
 				r.push(`${His} intake toxicology reveals that ${he} was`);
-				if (V.gingeringDetected === 1) {
+				if (slave.gingering.detected) {
 					r.push(`indeed`);
 				}
 				r.push(`given antidepressants to make ${him} seem less fearful for ${seed}. ${He} is much less trusting than ${he} appeared in the market.`);
-			} else if (V.gingering === "depressant") {
+			} else if (slave.gingering.type === "depressant") {
 				r.push(`${His} intake toxicology reveals that ${he} was`);
-				if (V.gingeringDetected === 1) {
+				if (slave.gingering.detected) {
 					r.push(`indeed`);
 				}
 				r.push(`given a depressant to make ${him} seem less hateful for ${seed}. ${He} is much less obedient than ${he} appeared in the market.`);
-			} else if (V.gingering === "stimulant") {
+			} else if (slave.gingering.type === "stimulant") {
 				r.push(`${His} intake toxicology reveals that ${he} was`);
-				if (V.gingeringDetected === 1) {
+				if (slave.gingering.detected) {
 					r.push(`indeed`);
 				}
 				r.push(`given a stimulant to make ${him} seem healthier for ${seed}. ${He} is much less vital than ${he} appeared in the market.`);
-			} else if (V.gingering === "vasoconstrictor") {
+			} else if (slave.gingering.type === "vasoconstrictor") {
 				r.push(`${His} intake toxicology reveals that ${he} was`);
-				if (V.gingeringDetected === 1) {
+				if (slave.gingering.detected) {
 					r.push(`indeed`);
 				}
 				r.push(`given a vasoconstrictor to make ${his} cock seem more feminine for ${seed}. It's larger and more apt to become hard than it appeared in the market.`);
-			} else if (V.gingering === "vasodilator") {
+			} else if (slave.gingering.type === "vasodilator") {
 				r.push(`${His} intake toxicology reveals that ${he} was`);
-				if (V.gingeringDetected === 1) {
+				if (slave.gingering.detected) {
 					r.push(`indeed`);
 				}
 				r.push(`given a vasodilator to give ${him} an excessive erection for ${seed}. ${His} dick is somewhat smaller than it appeared in the market, and ${he}'s not really hard all the time.`);
-			} else if (V.gingering === "aphrodisiac") {
+			} else if (slave.gingering.type === "aphrodisiac") {
 				r.push(`${His} intake toxicology reveals that ${he} was`);
-				if (V.gingeringDetected === 1) {
+				if (slave.gingering.detected) {
 					r.push(`indeed`);
 				}
 				r.push(`given aphrodisiacs to make ${him} horny and attracted to everyone for ${seed}. ${His} true sex drive and sexuality remain to be discovered.`);
 			} else {
 				r.push(`A close inspection of ${his} anus reveals that ${he} was`);
-				if (V.gingeringDetected === 1) {
+				if (slave.gingering.detected) {
 					r.push(`indeed`);
 				}
 				r.push(`doctored with an irritant to make ${him} present ${his} butt when shown for ${seed}. ${He} is not an actual anal sex enthusiast.`);
 			}
+			slave = slave.beforeGingering; // cancel gingering proxy from here on.
 		}
 
-		removeGingering();
-		// retrieve original slave without gingering effects
-
-
 		if (V.seeRace === 1) {
 			if (slave.override_Race !== 1) {
 				slave.origRace = slave.race;
diff --git a/src/npc/generate/slaveGenerationJS.js b/src/npc/generate/slaveGenerationJS.js
index adfa6f02920..9c8dbf6aada 100644
--- a/src/npc/generate/slaveGenerationJS.js
+++ b/src/npc/generate/slaveGenerationJS.js
@@ -1340,146 +1340,6 @@ globalThis.nationalityToAccent = function(slave) {
 	}
 };
 
-/*
-Backup and then apply gingering modifiers to slave - no changes should be made to slave until after calling removeGingering() to restore the backup
-Called from lawCompliance
-*/
-globalThis.checkForGingering = function(slave, market = 0) {
-	let r = "";
-	const {he, him, his, He, His} = getPronouns(slave);
-	const applyLaw = applyLawCheck(market);
-
-	/* reset in case gingered slaves were viewed but not purchased (no newSlaveIntro) */
-	V.gingering = 0;
-	V.gingeringDetected = 0;
-	V.gingeringDetection = 0;
-	if (applyLaw === 1 && V.policies.SMR.honestySMR === 1) {
-		/* SMR prohibits gingering and is enforced for this slave - do nothing */
-	} else if (slave.indenture > 0) {
-		/* indentured servants cannot be gingered */
-	} else if (isShelterSlave(slave)) {
-		/* is a Shelter slave - do nothing */
-	} else {
-		V.beforeGingering = clone(slave);
-		if (slave.trust < -20 && jsRandom(1, 3) === 1) {
-			V.gingering = "antidepressant";
-			slave.trust += jsRandom(10, 40);
-		} else if (slave.devotion < -20 && jsRandom(1, 3) === 1) {
-			V.gingering = "depressant";
-			slave.devotion += jsRandom(10, 40);
-		} else if (slave.health.condition < 60 && jsRandom(1, 3) === 1) {
-			V.gingering = "stimulant";
-			improveCondition(slave, jsRandom(20, 40));
-		} else if (slave.balls > 0 && slave.dick > 2 && jsRandom(1, 3) === 1) {
-			V.gingering = "vasoconstrictor";
-			slave.dick -= jsRandom(1, 2);
-		} else if (slave.balls > 0 && slave.dick < 5 && jsRandom(1, 3) === 1) {
-			V.gingering = "vasodilator";
-			slave.dick += jsRandom(1, 2);
-		} else if (slave.attrKnown === 0 && jsRandom(1, 3) === 1) {
-			V.gingering = "aphrodisiac";
-			slave.aphrodisiacs = 2;
-			slave.attrKnown = 1;
-			slave.attrXX = jsRandom(60, 90);
-			slave.attrXY = jsRandom(60, 90);
-			slave.energy = jsRandom(50, 90);
-		} else if (slave.anus > 0 && slave.fetishKnown === 0 && jsRandom(1, 3) === 1) {
-			V.gingering = "ginger";
-			slave.fetish = "buttslut";
-			slave.fetishKnown = 1;
-			slave.fetishStrength = 65;
-		}
-	}
-	if (V.gingering !== 0) {
-		if (V.PC.skill.slaving >= 100) {
-			V.gingeringDetected = 1;
-			V.gingeringDetection = "slaver";
-			switch (V.gingering) {
-				case "antidepressant":
-					r += `${He} is acting dazed and unfocused. ${He}'s obviously been given antidepressants to make ${him} appear less fearful, and will be considerably less trusting than ${he} seems.`;
-					break;
-				case "depressant":
-					r += `${He} is acting languid and drugged. ${He}'s obviously been given a depressant to make ${him} appear less hateful, and will be considerably less accepting of slavery than ${he} seems.`;
-					break;
-				case "stimulant":
-					r += `${He} is acting twitchy and hyperactive. ${He}'s obviously been given a stimulant to make ${him} seem healthier and more energetic, and is a lot less healthy than ${he} looks.`;
-					break;
-				case "vasoconstrictor":
-					r += `${His} lips have the slightest blue tinge, making it obvious ${he}'s been given a vasoconstrictor. ${His} cock is a lot less of a girldick than it looks right now.`;
-					break;
-				case "vasodilator":
-					r += `${He} has an impressive erection, but it seems quite unconnected to the rest of ${him}, as if ${he} doesn't know what to do with it. ${He}'s obviously been given a vasodilator to make ${his} dick seem a little less pathetic.`;
-					break;
-				case "aphrodisiac":
-					r += `${His} pupils are slightly dilated, ${his} breath comes in fast pants, and ${his} skin is flushed. ${He}'s obviously been given as big of a dose of aphrodisiacs as ${he} can handle without a heart attack.`;
-					break;
-				default:
-					r += `${He} is acting oddly, presenting ${his} ass in an awkward way and acting uncomfortable. ${He}'s obviously had an irritant shoved up ${his} butt to make ${him} act like an anal whore.`;
-			}
-			r += ` It's a trick you're very familiar with, given your <span class="springgreen">training as a slaver.</span>`;
-		} else {
-			/* not slaver */
-			if (V.PC.skill.warfare >= 100 && jsRandom(1, 2) === 1) {
-				V.gingeringDetected = 1;
-				V.gingeringDetection = "mercenary";
-			} else if (V.PC.rumor === "force" && jsRandom(1, 2) === 1) {
-				V.gingeringDetected = 1;
-				V.gingeringDetection = "force";
-			} else if (jsRandom(1, 3) === 1) {
-				V.gingeringDetected = 1;
-			}
-			if (V.gingeringDetected === 1) {
-				switch (V.gingering) {
-					case "antidepressant":
-						r += `${He} is acting dazed and unfocused, like ${he}'s been given antidepressants to make ${him} appear less fearful. ${He} may be considerably less trusting than ${he} seems. `;
-						break;
-					case "depressant":
-						r += `${He} is acting languid and drugged, like ${he}'s been given a depressant to make ${him} appear less hateful. ${He} may be considerably less accepting of slavery than ${he} seems. `;
-						break;
-					case "stimulant":
-						r += `${He} is acting twitchy and hyperactive, like ${he}'s been given a stimulant to make ${him} seem healthier and more energetic. ${He} may be considerably less vital than ${he} seems. `;
-						break;
-					case "vasoconstrictor":
-						r += `${His} lips have the slightest blue tinge, suggesting that ${he} may have been given a vasoconstrictor. If ${he} has, ${his} cock may be considerably less feminine and demure than it now seems. `;
-						break;
-					case "vasodilator":
-						r += `${He} has an impressive erection, but it seems quite unconnected to the rest of ${him}, as if ${he} doesn't know what to do with it. ${He} may have been given a vasodilator. If ${he} has, ${his} cock may be considerably less impressive than it now seems. `;
-						break;
-					case "aphrodisiac":
-						r += `${His} pupils are slightly dilated, ${his} breath comes in fast pants, and ${his} skin is flushed. These are the characteristic symptoms of a dose of aphrodisiacs limited only by a desire to avoid giving ${him} a heart attack. `;
-						break;
-					default:
-						r += `${He} is acting oddly, presenting ${his} ass in an awkward way and acting uncomfortable. ${He} may be considerably less interested in anal sex than ${he} seems. `;
-				}
-				if (V.gingeringDetection === "mercenary") {
-					r += `The nervous seller confirms this in response to a direct inquiry. Your intimidating reputation from your <span class="springgreen">extensive combat training</span> has its uses.`;
-				} else if (V.gingeringDetection === "force") {
-					r += `The nervous seller confirms this in response to a direct inquiry. Your reputation as a <span class="springgreen"> ${PCTitle() ? "man" : "woman"} of blood</span> has its uses.`;
-				}
-			}
-		} /* gingering detected */
-	} /* gingering !== 0 */
-	return r;
-};
-
-/*
-Retrieve original slave without gingering modifiers
-Call as removeGingering()
-Called from newSlaveIntro, bulkSlaveGenerate
-*/
-globalThis.removeGingering = function() {
-	if (V.gingering !== 0 && V.beforeGingering !== 0 && V.activeSlave !== 0 && V.beforeGingering.ID === V.activeSlave.ID) {
-		/* extra checks to ensure gingering state is not left over from a different slave that was inspected but not purchased */
-		V.activeSlave = V.beforeGingering;
-		V.beforeGingering = 0;
-	} else {
-		/* clear left over state from a different slave without modifying activeSlave
-		 */
-		V.gingering = 0;
-		V.beforeGingering = 0;
-	}
-};
-
 /**
  * @param {App.Entity.SlaveState} slave*/
 globalThis.randomizeAttraction = function(slave) {
@@ -1581,7 +1441,6 @@ globalThis.applyAgeImplantOlder = function(slave) {
  * @param {FC.Zeroable<FC.SlaveMarketName>} [market]
  * @returns {number} [1|0]
  */
-
 globalThis.applyLawCheck = function(market) {
 	if (typeof market !== "string" || App.Data.misc.lawlessMarkets.includes(market)) {
 		return 0;
diff --git a/src/player/js/PlayerState.js b/src/player/js/PlayerState.js
index cd477ab4150..63e88a47b9a 100644
--- a/src/player/js/PlayerState.js
+++ b/src/player/js/PlayerState.js
@@ -1974,7 +1974,8 @@ App.Entity.PlayerState = class PlayerState {
 		 *
 		 * 0: no; 1: yes, comforting; 2: yes, terrifying */
 		this.tankBaby = 0;
-		/** */
+		/** Are you a clone, and of whom?
+		 * @type {FC.Zeroable<string>} */
 		this.clone = 0;
 		/** */
 		this.geneMods = {
-- 
GitLab