From 855c597c18ce1886959baa3c1e3fdc49f834d229 Mon Sep 17 00:00:00 2001
From: kraster <hibraelmenino@gmail.com>
Date: Fri, 9 Aug 2024 23:06:00 +0000
Subject: [PATCH 1/6] Update buttplug.js spelling error L650

---
 src/npc/descriptions/butt/buttplug.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/npc/descriptions/butt/buttplug.js b/src/npc/descriptions/butt/buttplug.js
index fced6f14c34..7aadcede82f 100644
--- a/src/npc/descriptions/butt/buttplug.js
+++ b/src/npc/descriptions/butt/buttplug.js
@@ -647,7 +647,7 @@ App.Desc.buttplug = function(slave, descType = DescType.NORMAL) {
 		if (buttplug.length === 1) {
 			r.push(`by a large ${slave.buttplug}.`);
 		} else {
-			r.push(`by a large and long ${slave.buttplug}. It causes a noticeable bulge in ${his} belly.`);
+			r.push(`by a large and ${slave.buttplug}. It causes a noticeable bulge in ${his} belly.`);
 		}
 	} else if (buttplug.width === 3) {
 		if (buttplug.length === 1) {
-- 
GitLab


From 2d1acb54d7cb80212361c571e8dfcf1740fe12df Mon Sep 17 00:00:00 2001
From: kraster <hibraelmenino@gmail.com>
Date: Sat, 10 Aug 2024 13:08:30 +0000
Subject: [PATCH 2/6] Update buttplug.js remove "large and"

---
 src/npc/descriptions/butt/buttplug.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/npc/descriptions/butt/buttplug.js b/src/npc/descriptions/butt/buttplug.js
index 7aadcede82f..d78e39c4739 100644
--- a/src/npc/descriptions/butt/buttplug.js
+++ b/src/npc/descriptions/butt/buttplug.js
@@ -647,7 +647,7 @@ App.Desc.buttplug = function(slave, descType = DescType.NORMAL) {
 		if (buttplug.length === 1) {
 			r.push(`by a large ${slave.buttplug}.`);
 		} else {
-			r.push(`by a large and ${slave.buttplug}. It causes a noticeable bulge in ${his} belly.`);
+			r.push(`by a ${slave.buttplug}. It causes a noticeable bulge in ${his} belly.`);
 		}
 	} else if (buttplug.width === 3) {
 		if (buttplug.length === 1) {
-- 
GitLab


From 2b8b44d15551185a305ac3df91af93af679dde4d Mon Sep 17 00:00:00 2001
From: kraster <hibraelmenino@gmail.com>
Date: Sat, 10 Aug 2024 13:17:24 +0000
Subject: [PATCH 3/6] Update buttplug.js remove long L663

---
 src/npc/descriptions/butt/buttplug.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/npc/descriptions/butt/buttplug.js b/src/npc/descriptions/butt/buttplug.js
index d78e39c4739..27afd7c10f6 100644
--- a/src/npc/descriptions/butt/buttplug.js
+++ b/src/npc/descriptions/butt/buttplug.js
@@ -660,7 +660,7 @@ App.Desc.buttplug = function(slave, descType = DescType.NORMAL) {
 			if (slave.anus < 4) {
 				r.push(`It's agonizingly stretched by a ${slave.buttplug} so huge it causes ${his} belly to bulge and is likely stretching ${his} anus into a permanent gape.`);
 			} else {
-				r.push(`Its ridiculous gape is comfortably filled by a wide and long ${slave.buttplug}. It causes a noticeable bulge in ${his} belly.`);
+				r.push(`Its ridiculous gape is comfortably filled by a wide and ${slave.buttplug}. It causes a noticeable bulge in ${his} belly.`);
 			}
 		}
 		if (slave.anus < 4) {
-- 
GitLab


From d94e26a60e125912cd5a32d8fc495dfbd12a7860 Mon Sep 17 00:00:00 2001
From: Cyanthesis <cyanthesis@outlook.com>
Date: Sun, 11 Aug 2024 01:25:20 -0400
Subject: [PATCH 4/6] add buttons to toggle/close reports

---
 css/gui/accordion.css                |  6 ++++
 src/endWeek/slaveAssignmentReport.js | 42 ++++++++++++++++++++++++++++
 src/js/utilsDOM.js                   | 34 +++++++++++++++++++++-
 3 files changed, 81 insertions(+), 1 deletion(-)

diff --git a/css/gui/accordion.css b/css/gui/accordion.css
index 81c02b3b460..e42b80e57f3 100644
--- a/css/gui/accordion.css
+++ b/css/gui/accordion.css
@@ -66,3 +66,9 @@ button.accordion span.title {
 button.accordion span.info {
 	float: right;
 }
+
+button.assignment-report-btn {
+	display: block;
+	margin-top: 1em;
+	margin-bottom: 1em;
+}
diff --git a/src/endWeek/slaveAssignmentReport.js b/src/endWeek/slaveAssignmentReport.js
index 6f6fc37e753..be6d7f9a4f7 100644
--- a/src/endWeek/slaveAssignmentReport.js
+++ b/src/endWeek/slaveAssignmentReport.js
@@ -423,6 +423,48 @@ App.EndWeek.slaveAssignmentReport = function() {
 		}
 	}
 
+	const toggleAllButtonClick = () => {
+		const accordionElements = Array.from(document.querySelectorAll("button.accordion"));
+		const accordionContent = document.querySelectorAll("div.accordion-content");
+		const anyOpenReports = accordionElements
+			.some((element) => !(element.classList.contains("closed") || (element.classList.contains("empty"))));
+		if (anyOpenReports) {
+			accordionElements.forEach((element) => {
+				if (!element.classList.contains("empty")) {
+					element.classList.add("closed");
+				}
+			});
+			accordionContent.forEach((element) => {
+				element.classList.add("hidden");
+			});
+		} else {
+			accordionElements.forEach((element) => {
+				element.classList.remove("closed");
+			});
+			accordionContent.forEach((element) => {
+				element.classList.remove("hidden");
+			});
+		}
+		App.UI.DOM.updateToggleAllButtonText();
+	};
+
+	const toggleAllButton = document.createElement("button");
+	toggleAllButton.textContent = "Open All Reports";
+	toggleAllButton.classList.add("toggle-all-btn");
+	toggleAllButton.classList.add("assignment-report-btn");
+	toggleAllButton.addEventListener("click", toggleAllButtonClick);
+
+	const bottomToggleAllButton = toggleAllButton.cloneNode(true);
+	bottomToggleAllButton.addEventListener("click",
+		() => {
+			toggleAllButtonClick();
+			window.scrollTo(0, document.body.scrollHeight);
+		}
+	);
+
+	res.prepend(toggleAllButton);
+	res.append(bottomToggleAllButton);
+
 	/* Clean up global SA variables */
 	App.EndWeek.saVars = null;
 
diff --git a/src/js/utilsDOM.js b/src/js/utilsDOM.js
index f0c082894ce..63e33b3d7d3 100644
--- a/src/js/utilsDOM.js
+++ b/src/js/utilsDOM.js
@@ -386,13 +386,24 @@ App.UI.DOM.accordion = function(head, content, collapsed = true) {
 	const fragment = document.createDocumentFragment();
 	const button = App.UI.DOM.appendNewElement("button", fragment, head, ["accordion"]);
 
+	const closeButton = document.createElement("button");
+	closeButton.classList.add("assignment-report-btn");
+	closeButton.textContent = "Close Report";
+	closeButton.onclick = () => {
+		button.classList.add("closed");
+		for (let htmlElement of [content]) {
+			htmlElement.classList.add("hidden");
+		}
+		App.UI.DOM.updateToggleAllButtonText();
+	};
+
 	if (content) {
+		content.append(closeButton);
 		App.UI.DOM.elementToggle(button, [content], collapsed);
 		fragment.append(content);
 	} else {
 		button.classList.add("empty");
 	}
-
 	return fragment;
 };
 
@@ -411,6 +422,7 @@ App.UI.DOM.elementToggle = function(toggleElement, content, startHidden = true)
 		for (let htmlElement of content) {
 			htmlElement.classList.toggle("hidden");
 		}
+		App.UI.DOM.updateToggleAllButtonText();
 	};
 	toggleElement.onclick = toggle;
 	if (startHidden) {
@@ -418,6 +430,26 @@ App.UI.DOM.elementToggle = function(toggleElement, content, startHidden = true)
 	}
 };
 
+/**
+ * Update text for open all/close all report buttons on assignment report page
+ */
+App.UI.DOM.updateToggleAllButtonText = function() {
+	const toggleAllButtons = document.querySelectorAll("button.toggle-all-btn");
+	const accordionElements = Array.from(document.querySelectorAll("button.accordion"));
+	const anyOpenReports = accordionElements
+		.some((element) => !(element.classList.contains("closed") || element.classList.contains("empty")));
+
+	if (anyOpenReports) {
+		toggleAllButtons.forEach((button) => {
+			button.textContent = "Close All Reports";
+		});
+	} else {
+		toggleAllButtons.forEach((button) => {
+			button.textContent = "Open All Reports";
+		});
+	}
+};
+
 /*
 	<<includeDOM element>>
 	Simply inserts a given DOM element.
-- 
GitLab


From b417624e0f2153d65df28b69b5e956892494880b Mon Sep 17 00:00:00 2001
From: Svornost <svornost.ns@gmail.com>
Date: Mon, 12 Aug 2024 00:18:52 -0700
Subject: [PATCH 5/6] Don't try to cast slaves that don't exist in `SE Death`.

---
 src/endWeek/events/death.js | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/endWeek/events/death.js b/src/endWeek/events/death.js
index ddbe8d01510..a38f378588c 100644
--- a/src/endWeek/events/death.js
+++ b/src/endWeek/events/death.js
@@ -14,6 +14,14 @@ App.Events.SEDeath = class SEDeath extends App.Events.BaseEvent {
 
 	/** Custom casting: interpret V.slaveDeath as the actor collection for this event (do not use this.actors). */
 	castActors() {
+		// clean up the death list first. we don't want to try to kill slaves that are already gone for some other reason...
+		const origIDs = [...V.slaveDeath.keys()];
+		for (const id of origIDs) {
+			if (typeof getSlave(id) === 'undefined') {
+				V.slaveDeath.delete(id);
+			}
+		}
+
 		return V.slaveDeath.size > 0;
 	}
 
-- 
GitLab


From 75a1da1c3d80a2443b4f3d8fc98e13cb2c0b3179 Mon Sep 17 00:00:00 2001
From: xModo99 <xmodo999@gmail.com>
Date: Mon, 12 Aug 2024 15:08:53 +0000
Subject: [PATCH 6/6] Add alternate greetings

---
 src/npc/{ => slaveBot}/generateSlaveBot.js |  39 +-
 src/npc/slaveBot/slaveBotGreetings.js      | 748 +++++++++++++++++++++
 2 files changed, 761 insertions(+), 26 deletions(-)
 rename src/npc/{ => slaveBot}/generateSlaveBot.js (97%)
 create mode 100644 src/npc/slaveBot/slaveBotGreetings.js

diff --git a/src/npc/generateSlaveBot.js b/src/npc/slaveBot/generateSlaveBot.js
similarity index 97%
rename from src/npc/generateSlaveBot.js
rename to src/npc/slaveBot/generateSlaveBot.js
index 123496d6cb4..8e1b924d649 100644
--- a/src/npc/generateSlaveBot.js
+++ b/src/npc/slaveBot/generateSlaveBot.js
@@ -2,7 +2,7 @@
 // cSpell:ignore abilParts, chasParts
 
 /** @param {FC.SlaveState} slave */
-App.UI.SlaveInteract.createSlaveBot = function(slave) {
+App.UI.SlaveInteract.createSlaveBot = function (slave) {
 	const el = new DocumentFragment();
 	const p = App.UI.DOM.appendNewElement("p", el, `Exporting slave bot.\nThis might take a minute. Please wait...`);
 	const a = App.UI.DOM.appendNewElement("a", el, '');
@@ -273,7 +273,7 @@ App.UI.SlaveInteract.SlaveBot = class SlaveBot {
 	 * @returns {File}
 	 */
 	static exportJsonFile(characterCard) {
-		const file = new File([JSON.stringify(characterCard, undefined, '\t')], `${characterCard.data.name || 'character'}.card.json`, {type: 'application/json;charset=utf-8'});
+		const file = new File([JSON.stringify(characterCard, undefined, '\t')], `${characterCard.data.name || 'character'}.card.json`, { type: 'application/json;charset=utf-8' });
 		return file;
 	}
 
@@ -287,7 +287,7 @@ App.UI.SlaveInteract.SlaveBot = class SlaveBot {
 		if (V.aiCachingStrategy === 'static') {
 			const displayedIdx = slaveState.custom.aiDisplayImageIdx;
 			const imageDbId = slaveState.custom.aiImageIds[displayedIdx];
-			const {data} = await App.Art.GenAI.staticImageDB.getImage(imageDbId);
+			const { data } = await App.Art.GenAI.staticImageDB.getImage(imageDbId);
 
 			imageUrl = data;
 		} else {
@@ -314,7 +314,7 @@ App.UI.SlaveInteract.SlaveBot = class SlaveBot {
 		const json = JSON.stringify(characterCardObj, undefined, '\t');
 		const png = App.UI.SlaveInteract.Png.Generate(imageArrayBuffer, json);
 
-		const file = new File([png], `${characterCardObj.data.name || 'character'}.card.png`, {type: 'image/png'});
+		const file = new File([png], `${characterCardObj.data.name || 'character'}.card.png`, { type: 'image/png' });
 
 		return file;
 	}
@@ -324,12 +324,17 @@ App.UI.SlaveInteract.SlaveBot = class SlaveBot {
 	 * @returns {object} asdf
 	 * */
 	static createCharacterDataFromSlave(slave) {
+		// Get all greetings that satisfy prereqs.
+		const alternateGreetings = App.UI.SlaveInteract.SlaveBotGreetings
+			.filter((greetingObj) => greetingObj.prereqs.every((prereq) => prereq(slave)))
+			.map((greetingObj) => greetingObj.getGreeting(slave));
+
 		// Construct a character card based on the Card v2 spec: https://github.com/malfoyslastname/character-card-spec-v2
 		const characterCard = {
 			spec: 'chara_card_v2',
 			spec_version: '2.0', // May 8th addition
 			data: {
-				alternate_greetings: [],
+				alternate_greetings: alternateGreetings,
 				avatar: "none",
 				character_version: "main",
 				creator: `FreeCities ${App.Version.pmod} System Generated`,
@@ -365,7 +370,7 @@ App.UI.SlaveInteract.SlaveBot = class SlaveBot {
 	 */
 	static generateDescription(slave) {
 		let r = [];
-		const {he, his} = getPronouns(slave);
+		const { he, his } = getPronouns(slave);
 		let descParts = [];
 
 
@@ -408,12 +413,6 @@ App.UI.SlaveInteract.SlaveBot = class SlaveBot {
 			} else if (slave.trust < 20) {
 				r.push("fearful ");
 			} else if (slave.trust <= 50) {
-				// if (slave.devotion < -20) {
-				// 	r.push("careful ");
-				// } else {
-				// 	r.push("careful ");
-				// }
-				// FIXME: @null this block always spits out the same result. It should be changed or removed
 				r.push("careful ");
 			} else if (slave.trust < 95) {
 				if (slave.devotion < -20) {
@@ -806,7 +805,7 @@ App.UI.SlaveInteract.SlaveBot = class SlaveBot {
 	 */
 	static generateFirstMessage(slave) {
 		let r = [];
-		const {He, His, he, his} = getPronouns(slave);
+		const { He, His, he, his } = getPronouns(slave);
 		// Set up basic scenario
 		r.push("I am sitting in my office as {{char}} arrives for inspection.\r\n");
 
@@ -822,7 +821,7 @@ App.UI.SlaveInteract.SlaveBot = class SlaveBot {
 			r.push("{{char}} comes in, ");
 
 			if (slave.trust < -95) {
-				r.push(`appearing abjectly terrified, barely able to control ${his} terror.`);
+				r.push(`appearing abjectly terrified, barely able to control ${his} terror. `);
 			} else if (slave.trust < -50) {
 				r.push(`appearing terrified, barely concealing ${his} fear. `);
 			} else if (slave.trust < -20) {
@@ -830,12 +829,6 @@ App.UI.SlaveInteract.SlaveBot = class SlaveBot {
 			} else if (slave.trust < 20) {
 				r.push("looking fearful. ");
 			} else if (slave.trust <= 50) {
-				// if (slave.devotion < -20) {
-				// 	r.push("appearing cautious. ");
-				// } else {
-				// 	r.push("appearing cautious. ");
-				// }
-				// FIXME: @null this block always spits out the same result. It should be changed or removed
 				r.push("appearing cautious. ");
 			} else if (slave.trust < 95) {
 				if (slave.devotion < -20) {
@@ -918,12 +911,6 @@ App.UI.SlaveInteract.SlaveBot = class SlaveBot {
 			} else if (slave.trust < 20) {
 				r.push("fearful ");
 			} else if (slave.trust <= 50) {
-				// if (slave.devotion < -20) {
-				// 	r.push("careful ");
-				// } else {
-				// 	r.push("careful ");
-				// }
-				// FIXME: @null this block always spits out the same result. It should be changed or removed
 				r.push("careful ");
 			} else if (slave.trust < 95) {
 				if (slave.devotion < -20) {
diff --git a/src/npc/slaveBot/slaveBotGreetings.js b/src/npc/slaveBot/slaveBotGreetings.js
new file mode 100644
index 00000000000..c12004f5a00
--- /dev/null
+++ b/src/npc/slaveBot/slaveBotGreetings.js
@@ -0,0 +1,748 @@
+/**
+ * Alternate Greetings are drawn from existing FC Events with minimal adaptations, dropping response options in favor of LLM RP
+ * This aligns AltGreetings lore with existing FC Lore.
+ * Prerequisites are likewise drawn from their FC Events, so that AltGreetings will only be exported if they match slave descriptions, e.g. badDream only applies to low trust slaves
+ * Prerequites have been pared back to be more broadly applicable, e.g. slave assignment prerequisites dropped for lazyEvening, "need" from desperatelyHorny
+ * Idea here is that bias should be to export the AltGreeting if it makes sense for base slave attributes (trust, obedience, body), and ignore easily changed ones (rules, assignments, etc.)
+ * New AltGreetings can simple be added on below using same schema; they will be exported to applicable slaves automatically without need to edit other files
+ * Tests with Mistral showed better results using the FC Event's native second person for AltGreeting, rather than first person, so this was left unchanged. NG Aug 2024
+ *
+ * @type {Array<{ prereqs: Array<actorPredicate>, getGreeting: (s: FC.SlaveState) => string }>}
+ */
+App.UI.SlaveInteract.SlaveBotGreetings = [
+	{
+		getGreeting: (s) => {
+			const {
+				His, He, he, his, him, himself, girl, hers
+			} = getPronouns(s);
+			const { title: Master } = getEnunciation(s);
+			const belly = bellyAdjective(s);
+			// SRC deperatelyHorny.js
+			let r = [];
+			r.push(
+				`Looking deeply unhappy and shivering occasionally, ${s.slaveName}, comes to see you.`
+			);
+			if (s.rules.speech === "restrictive") {
+				r.push(`Since ${he} is not allowed to speak, ${he} just enters your office and stands there, unsure what to do.`);
+			} else {
+				if (!canTalk(s)) {
+					r.push(`${He} tries to communicate something with ${his}`);
+					if (hasBothArms(s)) {
+						r.push(`hands,`);
+					} else {
+						r.push(`hand,`);
+					}
+					r.push(`but ${he}'s so distracted ${he} can't manage it. ${He} starts to shake a little and gives up.`);
+				} else {
+					r.push(
+						Spoken(s, `"${Master}, please! Please — I — please, I need to — oh, ${Master}—"`),
+						he
+					);
+					if (SlaveStatsChecker.checkForLisp(s)) {
+						r.push(`lisps frantically.`);
+					} else {
+						r.push(`babbles.`);
+					}
+					r.push(`${He} starts to shake a little and lapses into silence.`);
+				}
+			}
+			r.push(`The reason for ${his} distress is obvious:`);
+			if (s.chastityPenis === 1) {
+				r.push(`${his} chastity cage is mostly solid, but it has a small hole below where the tip of ${his} dick is held, and this is dripping precum. ${He}'s sexually helpless, and sexually overcharged to the point where ${he}'s dripping more precum than a usual dickgirl might ejaculate normally.`);
+			} else if (s.dick > 0 && s.hormoneBalance >= 100 && !canAchieveErection(s)) {
+				r.push(`though the hormones are keeping it soft, ${his} member is dripping a stream of precum; droplets of the stuff spatter ${his} legs. One of ${his} spasms brings ${his} dickhead brushing against ${his} thigh, and the stimulation almost brings ${him} to orgasm.`);
+			} else if (s.dick > 0 && s.balls > 0 && s.ballType === "sterile" && !canAchieveErection(s)) {
+				r.push(`though ${he}'s chemically castrated, ${his} soft member is dripping a stream of watery precum; droplets of the stuff spatter ${his} legs. One of ${his} spasms brings ${his} dickhead brushing against ${his} thigh, and the stimulation almost brings ${him} to orgasm.`);
+			} else if (s.dick > 0 && s.balls === 0 && !canAchieveErection(s)) {
+				r.push(`though ${he}'s gelded, ${his} soft member is dripping a stream of watery precum; droplets of the stuff spatter ${his} legs. One of ${his} spasms brings ${his} dickhead brushing against ${his} thigh, and the stimulation almost brings ${him} to orgasm.`);
+			} else if (s.dick > 0 && !canAchieveErection(s)) {
+				r.push(`though ${he}'s far too large to get hard, ${his} engorged member is dripping a stream of watery precum; droplets of the stuff spatter the floor. One of ${his} spasms brushes the length of ${his} cock against ${his} thigh, and the stimulation almost brings ${him} to orgasm.`);
+			} else if (s.dick > 0) {
+				if (s.dick > 4) {
+					r.push(`${his} gigantic member juts out painfully, scattering droplets of precum whenever ${he} moves. One of ${his} spasms brings ${his} dickhead brushing up against ${his}`);
+				} else if (s.dick > 2) {
+					r.push(`${his} impressive member juts out painfully, scattering droplets of precum whenever ${he} moves. One of ${his} spasms brings ${his} dickhead brushing up against ${his}`);
+				} else {
+					r.push(`${his} little member juts out painfully, scattering droplets of precum whenever ${he} moves. One of ${his} spasms brings ${his} dickhead brushing up against ${his}`);
+				}
+				if (s.belly >= 10000 || s.weight > 95) {
+					r.push(belly);
+					if (s.bellyPreg >= 3000) {
+						r.push(`pregnancy,`);
+					} else {
+						r.push(`belly,`);
+					}
+				} else {
+					r.push(`abdomen,`);
+				}
+				r.push(`and the stimulation almost brings ${him} to orgasm.`);
+			} else if (s.chastityVagina) {
+				r.push(`female juices are leaking out from behind ${his} chastity belt. ${His} cunt desperately wants to be fucked, and is dripping natural lubricant to ease penetration by cocks that cannot reach it through its protective shield.`);
+			} else if (s.clit > 3) {
+				r.push(`${his} dick-like clit is painfully engorged and juts out massively. The stimulation of the air on ${his} clit keeps ${him} on the brink of orgasm.`);
+			} else if (s.clit > 0) {
+				r.push(`${his} lovely clit is painfully engorged, and ${his} pussy is so wet there are little rivulets of moisture running down ${his} inner thighs. One of ${his} spasms brings ${his} clit brushing accidentally against ${his} hand, and the stimulation almost brings ${him} to orgasm.`);
+			} else if (s.labia > 0) {
+				r.push(`${his} lovely pussylips are painfully engorged, and ${his} pussy is so wet there are little rivulets of moisture running down ${his} inner thighs. One of ${his} spasms brings ${his} generous labia brushing against ${his} thighs, and the stimulation almost brings ${him} to orgasm.`);
+			} else if (s.vagina === -1) {
+				r.push(`though ${he} has no external genitalia to display it, ${he}'s flushed and uncomfortable, and is unconsciously presenting ${his} ass, since that's ${his} only real avenue to climax.`);
+			} else {
+				r.push(`${his} pussy is so wet there are little rivulets of moisture running down ${his} inner thighs. One of ${his} spasms brings ${him} enough stimulation that it almost brings ${him} to orgasm.`);
+			}
+			r.push(`\n\nThis is the result of not getting off for several days while on the slave diet provided by the nutritional systems. The mild aphrodisiacs included in ${his} food increase ${his} sex drive, and the increased libido can become cumulative if it's not regularly addressed. It looks like ${he} hasn't really gotten ${hers} in a couple of days, and the poor ${girl} can likely think of nothing but that. ${He}'s so horny ${he}'ll do anything for release. However, ${he} did come to you with ${his} trouble rather than masturbating illicitly.`);
+			return r.join(" ");
+		},
+		prereqs: [
+			/* TESTING */
+			s => s.fetish !== Fetish.MINDBROKEN,
+			hasAnyArms,
+			hasAnyLegs,
+			s => s.devotion >= -20,
+			s => s.trust >= -50,
+		]
+	},
+	{
+		getGreeting: (s) => {
+			const {
+				His, He, he, his, him, himself, hers
+			} = getPronouns(s);
+			const belly = bellyAdjective(s);
+			// SRC badDream.js
+			let r = [];
+			r.push(
+				`Passing near the slave dormitory late at night, you hear a quiet cry within. This is strange; most slaves housed there are not inclined or not allowed to have sex in the middle of the night, and in any case, the noise wasn't one of pleasure. Looking in, you see a jerky movement near the door. It's ${s.slaveName} and ${he}'s obviously having a bad dream. ${He} raises`
+			);
+			if (hasBothArms(s)) {
+				r.push(`an`);
+			} else {
+				r.push(`${his}`);
+			}
+			r.push(`arm to fend off some imagined danger, and in doing so, pushes the sheet down around ${his} waist. ${He} sleeps naked, like all your slaves, and the movement bares ${his}`);
+			if (s.boobs > 2000) {
+				r.push(`udders`);
+			} else if (s.boobs > 1000) {
+				r.push(`heavy breasts`);
+			} else if (s.boobs > 400) {
+				r.push(`boobs`);
+			} else {
+				r.push(`little tits`);
+			}
+			if (s.belly >= 5000) {
+				r.push(`and ${belly}`);
+				if (s.bellyPreg >= 3000) {
+					r.push(`pregnant`);
+				}
+				r.push(`belly`);
+			}
+			r.push(`to the cool night air. The low blue light outlines ${his} nipples as they`);
+			if (s.nipples !== "fuckable") {
+				r.push(`stiffen`);
+			} else {
+				r.push(`swell`);
+			}
+			r.push(`at the sudden change of temperature,`);
+			switch (s.nipples) {
+				case "tiny":
+					r.push(`pricking up into little buds.`);
+					break;
+				case "flat":
+					r.push(`becoming visible against ${his} areolae.`);
+					break;
+				case "puffy":
+					r.push(`the puffy promontories jutting even farther out.`);
+					break;
+				case "partially inverted":
+					r.push(`just starting to poke past their inversion.`);
+					break;
+				case "inverted":
+					r.push(`the twin domes formed by their inverted shapes becoming more prominent.`);
+					break;
+				case "huge":
+					r.push(`becoming so large they cast long shadows across ${his} bed.`);
+					break;
+				case "fuckable":
+					r.push(`the fuckable holes steadily closing and starting to poke outwards.`);
+					break;
+				default:
+					r.push(`becoming attractively erect.`);
+			}
+			r.push(`Still dreaming, ${he} clasps ${his}`);
+			if (hasBothArms(s)) {
+				r.push(`arms`);
+			} else {
+				r.push(`arm`);
+			}
+			r.push(`protectively over ${his}`);
+			if (s.pregKnown === 1) {
+				r.push(`unborn`);
+				if (s.pregType > 1) {
+					r.push(`children,`);
+				} else {
+					r.push(`child,`);
+				}
+			} else {
+				r.push(`vulnerable chest,`);
+			}
+			r.push(`and rolls to one side. Halfway into a fetal position, ${he} turns ${his} head against ${his} pillow, murmuring`);
+			if (s.accent <= 2) {
+				r.push(Spoken(s, `"N-no — please no — I'll d-do anyth-thing — no..."`));
+			} else {
+				r.push(`earnest protests in ${his} mother tongue.`);
+			}
+			return r.join(" ");
+		},
+		prereqs: [
+			/* TESTING */
+			s => s.fetish !== Fetish.MINDBROKEN,
+			hasAnyArms,
+			hasAnyLegs,
+			s => canTalk(s, false),
+			s => s.devotion <= 20,
+			s => s.trust < -20
+		]
+	},
+	{
+		getGreeting: (s) => {
+			const {
+				He, he, His, his, hers, him, himself, girl, woman
+			} = getPronouns(s);
+			const { title } = getEnunciation(s);
+			// SCR lazyEvening.js
+			let t = [];
+			t.push(`Although your life as an arcology owner comes with many associated privileges, extended idleness to bask in your luxury is not often among them. Thankfully, ${V.assistant.name} knows better than to let you run yourself ragged from the weight of your assorted responsibilities and often allots time in the evenings of your active schedule to simply relax.`);
+
+			t.push(`\n\nOf course, no self respecting arcology owner could be expected to enjoy a lazy night of idle relaxation on their own. As you resolve the last of your most pressing responsibilities for the evening, ${V.assistant.name} directs one of your attentive slaves to gently guide you away from the unending burdens of running your arcology. Leaning against the doorway and wearing a facsimile of what an old world ${woman} might wear on a casual night in, ${s.slaveName}`);
+			if (!canTalk(s)) {
+				t.push(`asks with a gesture that carries just the right mixture of submission and exaggerated casualness if you'd like to 'hang out.'`);
+			} else if (SlaveStatsChecker.checkForLisp(s)) {
+				t.push(
+					`lisps with exaggerated casualness,`,
+					Spoken(s, `"Let's hang out, ${title}?"`)
+				);
+			} else {
+				t.push(
+					`asks with exaggerated casualness,`,
+					Spoken(s, `"Want to hang out, ${title}?"`)
+				);
+			}
+
+			t.push(`\n\n${He} saunters over and`);
+			if (s.belly >= 100000) {
+				t.push(`struggles to lower ${his} ${bellyAdjective(s)} form to an obedient kneel`);
+			} else if (s.belly >= 10000) {
+				t.push(`gingerly lowers ${his} heavily ${s.bellyPreg > 3000 ? "gravid" : "swollen"} form to an obedient kneel`);
+			} else if (s.belly >= 5000) {
+				t.push(`gently lowers ${his} ${s.bellyPreg > 3000 ? "gravid" : "swollen"} form to an obedient kneel`);
+			} else {
+				t.push(`kneels obediently`);
+			}
+			t.push(`in front of you, awaiting further direction.`);
+
+			if (getLimbCount(s, 102) > 2) {
+				t.push(`Clad in an antique T-Shirt referencing some defunct old world website, ${his} P-Limbs stand in stark contrast — gyros and servomotors against simple thread and cloth. With such tangible examples of the technological prowess of the Free Cities serving as ${his} limbs, ${his} ${s.belly >= 5000 ? "taut " : ""} shirt is an amusing testimonial to how far behind the old world stands in contrast to the new.`);
+			} else if (s.boobs > 4000) {
+				t.push(`${His} breasts are so massive that the front of ${his} loose pajama top must be unbuttoned. Even so, the protrusion of ${his} immense breasts`);
+				if (s.belly >= 5000) {
+					t.push(`and ${bellyAdjective(s)} rounded belly from ${his} body`);
+				} else {
+					t.push(`from ${his} chest`);
+				}
+				t.push(`strains the soft pajama top to its breaking point.`);
+			} else if (s.intelligence + s.intelligenceImplant > 50) {
+				t.push(`As a clever ${girl}, ${his} simple${s.belly >= 5000 ? `, yet tight around the middle,` : ""} summer dress evokes memories of bygone warm weather days at elite old world colleges — and the sexual conquest of their youthful residents.`);
+			} else if (s.muscles > 30) {
+				t.push(`${His} simple sports bra and compression shorts ensemble does little to conceal ${his} incredible musculature,`);
+				if (s.belly >= 1500) {
+					t.push(`straining to hold up against ${his} swelling middle and`);
+				}
+				t.push(`glistening with sweat from a recent workout. Despite ${his} recent exertions, ${he}'s able to maintain utter stillness in the perfect posture of an obedient slave.`);
+			} else if (s.energy > 95) {
+				t.push(`${He}'s controlling ${his} absurd sex drive for the moment in deference to the notion of your relaxation time, but ${he} clearly wouldn't mind some sex as part of the evening.`);
+				if (s.dick > 0) {
+					if (canAchieveErection(s)) {
+						t.push(`${His} cock is painfully erect`);
+						if (s.belly >= 10000) {
+							t.push(`and pressed against the underside of ${his} belly,`);
+						}
+					} else {
+						t.push(`${His} soft dick is dribbling precum,`);
+					}
+				} else {
+					t.push(`${His} pussy is visibly soaked,`);
+				}
+				t.push(`showing unmistakably how badly ${he} needs release.`);
+			} else {
+				t.push(`${He} keeps ${his}`);
+				if (canSee(s)) {
+					t.push(App.Desc.eyesColor(s));
+				} else {
+					t.push("face");
+				}
+				t.push(`slightly downcast, ${his} hands lightly smoothing the folds from ${his} tight skirt while ${his} breasts visibly rise and fall under ${his} even tighter blouse.`);
+				if (s.belly >= 5000) {
+					t.push(`Between the two, there is little ${he} can do to cover ${his} exposed ${s.bellyPreg >= 3000 ? "pregnancy" : "middle"}.`);
+				}
+				t.push(`${He}'s the perfect picture of an attentive little old world ${girl}friend${s.height > 185 ? ` (though, of course, ${he}'s anything but physically small)` : ""}.`);
+			}
+			return t.join(" ");
+		},
+		prereqs: [
+			s => s.fetish !== Fetish.MINDBROKEN,
+			canStand,
+			hasAnyArms,
+			s => s.devotion > 20,
+		]
+	},
+	{
+		getGreeting: (s) => {
+			const {
+				His, He, he, his, him, himself, girl
+			} = getPronouns(s);
+			const { title: Master, say } = getEnunciation(s);
+			const belly = bellyAdjective(s);
+			const PC = V.PC;
+			// SRC ignorantHorny.js
+			let r = [];
+			r.push(
+				`First on the inspection schedule is ${s.slaveName} and as you watch ${him} enter your office, you note several good signs about ${his} progress towards becoming a good sex slave. ${He} enters obediently, without pretending to be thrilled to be here, but also without hesitation. Best of all,`
+			);
+			if (s.chastityPenis && canAchieveErection(s)) {
+				r.push(`${he}'s squirming with discomfort over the lack of room in ${his} chastity.`);
+			} else if (s.dick > 4 && canAchieveErection(s)) {
+				r.push(`${he}'s sporting a massive half-erection which slaps lewdly against ${his} thighs as ${he} walks.`);
+			} else if (s.dick > 2 && canAchieveErection(s)) {
+				r.push(`${his} dick is half-erect, bobbing lewdly as ${he} walks.`);
+			} else if (s.dick > 0 && canAchieveErection(s)) {
+				r.push(`${his} pathetic little bitch dick is half-erect.`);
+			} else if (s.dick > 6) {
+				r.push(`${his} enormous dick is slightly engorged and dripping precum.`);
+			} else if (s.dick > 0) {
+				r.push(`${his} soft bitch dick is dripping precum.`);
+			} else if (s.labia > 1) {
+				r.push(`${his} lovely pussylips are flushed and wet.`);
+			} else if (s.clit > 1) {
+				r.push(`${his} glorious bitch button is stiffly erect.`);
+			} else if (s.vagina === -1) {
+				r.push(`${he}'s unconsciously sticking ${his} ass out. Getting fucked there is ${his} main sexual outlet, now that ${he} lacks genitals.`);
+			} else {
+				r.push(`${his} pussy is flushed and moist.`);
+			}
+			r.push(`\n\n`);
+			if (s.aphrodisiacs > 0 || s.inflationType === "aphrodisiac") {
+				r.push(`The aphrodisiacs racing through ${his} system have ${him} desperate to get off, right now.`);
+			} else if (s.piercing.genitals.smart && s.clitSetting !== "none") {
+				r.push(His);
+				if (s.vagina > -1) {
+					r.push(`clit`);
+				} else {
+					r.push(`frenulum`);
+				}
+				r.push(`piercing is keeping ${his} arousal exquisitely balanced for ${his} inspection.`);
+			} else {
+				r.push(`The mild aphrodisiacs in the slave food have clearly built up some arousal that ${he} hasn't been able to address recently.`);
+			}
+			r.push(`${He} hasn't been with you long. ${He} may not be fully cognizant of how ${his} libido is being altered. New slaves aren't informed of the true extent of your abilities to force sexual need. It can be useful for a new ${girl} to wonder if some of the horniness ${he} feels is natural, and suspect that ${he}'s nothing but a dirty slut who deserves to be a sex slave.`);
+			return r.join(" ");
+		},
+		prereqs: [
+			// TESTING 
+			s => s.fetish !== Fetish.MINDBROKEN,
+			hasAnyArms,
+			hasAnyLegs,
+			canTalk,
+			s => s.devotion <= 50,
+			s => s.devotion >= -20
+		]
+	},
+	{
+		getGreeting: (s) => {
+			const {
+				His, He, he, his, him, himself, girl
+			} = getPronouns(s);
+			const belly = bellyAdjective(s);
+			const children = s.pregType > 1 ? "children" : "child";
+			// SRC refreshmentDelivery
+			let r = [];
+			r.push(
+				`When it's time for refreshments, ${V.assistant.name} directs the closest unoccupied slave capable of bringing them in to do so. This has the added advantage of bringing an enjoyably unpredictable variety of slaves under your eyes. This time, ${s.slaveName} comes through the door of your office, carrying`
+			);
+			if (V.PC.refreshmentType === 0) {
+				r.push(`a selection of ${V.PC.refreshment} brands and the necessary implements`);
+			} else if (V.PC.refreshmentType === 1) {
+				r.push(`a bottle of ${V.PC.refreshment} with a glass in your favorite style`);
+			} else if (V.PC.refreshmentType === 2) {
+				r.push(`a selection of ${V.PC.refreshment} on a plate of your favored style`);
+			} else if (V.PC.refreshmentType === 3) {
+				r.push(`a line of ${V.PC.refreshment} and the necessary implements`);
+			} else if (V.PC.refreshmentType === 4) {
+				r.push(`a syringe of ${V.PC.refreshment} and the necessary implements`);
+			} else if (V.PC.refreshmentType === 5) {
+				r.push(`a bottle of ${V.PC.refreshment}`);
+			} else if (V.PC.refreshmentType === 6) {
+				r.push(`several sheets of ${V.PC.refreshment}`);
+			}
+			if (s.preg > s.pregData.normalBirth / 1.33) {
+				r.push(`on a tray carefully held against ${his} pregnant belly, doing ${his} best to will ${his} ${children} to not kick the tray off balance.`);
+			} else if (s.belly >= 10000) {
+				r.push(`on a tray carefully held against ${his} ${belly}`);
+				if (s.bellyPreg >= 3000) {
+					r.push(`pregnant`);
+				}
+				r.push(`belly.`);
+			} else {
+				r.push(`on a tray.`);
+			}
+			r.push(`\n\n`);
+			r.push(`${He} comes to a stop right beside your elbow, waiting for further direction, just as ${he}'s been trained to do in these cases.`);
+			if (getLimbCount(s, 102) > 2) {
+				r.push(`As ${he} maintains ${his} posture obediently, ${his} P-Limbs produce minute machine noises. They allow ${him} good coordination, but their gyros and servomotors are constantly working to maintain it, which means that when ${he} stands still, they're not perfectly quiet.`);
+			} else if (s.boobs > 4000) {
+				r.push(`${His} breasts are so massive that ${he}'s got the tray more or less balanced on top of them. As ${he} breathes, ${his} tits rise and fall slightly,`);
+				if (V.PC.refreshmentType === 0) {
+					r.push(`causing the ${V.PC.refreshment} collection to roll from side to side.`);
+				} else if (V.PC.refreshmentType === 1) {
+					r.push(`causing ripples in the bottle of ${V.PC.refreshment}.`);
+				} else if (V.PC.refreshmentType === 2) {
+					r.push(`threatening to knock the ${V.PC.refreshment} from it's plate.`);
+				} else if (V.PC.refreshmentType === 3) {
+					r.push(`disturbing the lines of ${V.PC.refreshment}.`);
+				} else if (V.PC.refreshmentType === 4) {
+					r.push(`causing the syringes of ${V.PC.refreshment} to roll from side to side.`);
+				} else if (V.PC.refreshmentType === 5) {
+					r.push(`rattling the ${V.PC.refreshment} in its bottle.`);
+				} else if (V.PC.refreshmentType === 6) {
+					r.push(`threatening to knock the sheets of ${V.PC.refreshment} off the tray.`);
+				}
+			} else if (s.preg > s.pregData.normalBirth / 1.33) {
+				r.push(`${He} keeps the tray balanced atop ${his} ${belly} pregnancy, though the weight encourages ${his} ${children} to begin kicking. As you glance over at ${him}, ${he} lets out a minute, tired sigh, as kicks from ${his} ${children}`);
+				if (V.PC.refreshmentType === 0) {
+					r.push(`cause the ${V.PC.refreshment} collection to roll from side to side.`);
+				} else if (V.PC.refreshmentType === 1) {
+					r.push(`cause ripples in the bottle of ${V.PC.refreshment}.`);
+				} else if (V.PC.refreshmentType === 2) {
+					r.push(`threaten to knock the ${V.PC.refreshment} from it's plate.`);
+				} else if (V.PC.refreshmentType === 3) {
+					r.push(`disturb the lines of ${V.PC.refreshment}.`);
+				} else if (V.PC.refreshmentType === 4) {
+					r.push(`cause the syringes of ${V.PC.refreshment} to roll from side to side.`);
+				} else if (V.PC.refreshmentType === 5) {
+					r.push(`rattle the ${V.PC.refreshment} in its bottle.`);
+				} else if (V.PC.refreshmentType === 6) {
+					r.push(`threaten to knock the sheets of ${V.PC.refreshment} off the tray.`);
+				}
+			} else if (s.belly >= 10000) {
+				r.push(`${His}`);
+				if (s.bellyPreg >= 3000) {
+					r.push(`pregnant`);
+				}
+				r.push(`belly is big enough that ${he}'s got the tray more or less balanced on top of it. As you glance over at ${him}, ${he} lets out a minute, tired sigh,`);
+				if (V.PC.refreshmentType === 0) {
+					r.push(`causing the ${V.PC.refreshment} collection to roll from side to side.`);
+				} else if (V.PC.refreshmentType === 1) {
+					r.push(`causing ripples in the bottle of ${V.PC.refreshment}.`);
+				} else if (V.PC.refreshmentType === 2) {
+					r.push(`nearly rocking the ${V.PC.refreshment} from it's plate.`);
+				} else if (V.PC.refreshmentType === 3) {
+					r.push(`disturbing the lines of ${V.PC.refreshment}.`);
+				} else if (V.PC.refreshmentType === 4) {
+					r.push(`causing the syringes of ${V.PC.refreshment} to roll from side to side.`);
+				} else if (V.PC.refreshmentType === 5) {
+					r.push(`nearly tipping the bottle of ${V.PC.refreshment}.`);
+				} else if (V.PC.refreshmentType === 6) {
+					r.push(`threatening to blow the sheets of ${V.PC.refreshment} off the tray.`);
+				}
+			} else if (s.muscles > 30) {
+				r.push(`With ${his} incredible musculature, ${he}'s able to maintain utter stillness in the perfect posture of an obedient slave. A naturally standing human makes some small movements, but ${his} strength allows ${him} to suppress them by setting muscle groups against each other. This has the ancillary benefit of making them stand out nicely.`);
+			} else if (s.muscles < -30) {
+				r.push(`${He} is so physically frail that ${he} can barely manage to hold the tray steady. As ${he} rapidly tires, ${his} ${hasBothArms(s) ? "arms begin slightly shaking" : "arm begins to slightly shake"},`);
+				if (V.PC.refreshmentType === 0) {
+					r.push(`causing the ${V.PC.refreshment} collection to roll from side to side.`);
+				} else if (V.PC.refreshmentType === 1) {
+					r.push(`causing ripples in the bottle of ${V.PC.refreshment}.`);
+				} else if (V.PC.refreshmentType === 2) {
+					r.push(`threatening to knock the ${V.PC.refreshment} from it's plate.`);
+				} else if (V.PC.refreshmentType === 3) {
+					r.push(`disturbing the lines of ${V.PC.refreshment}.`);
+				} else if (V.PC.refreshmentType === 4) {
+					r.push(`causing the syringes of ${V.PC.refreshment} to roll from side to side.`);
+				} else if (V.PC.refreshmentType === 5) {
+					r.push(`rattling the ${V.PC.refreshment} in its bottle.`);
+				} else if (V.PC.refreshmentType === 6) {
+					r.push(`threatening to knock the sheets of ${V.PC.refreshment} off the tray.`);
+				}
+			} else if (s.energy > 95) {
+				r.push(`${He}'s controlling ${his} absurd sex drive for the moment, but ${he} clearly wouldn't mind some sex as part of the delivery.`);
+				if (s.dick > 0) {
+					if (canAchieveErection(s)) {
+						r.push(`${His} cock is painfully erect,`);
+					} else {
+						r.push(`${His} soft dick is dribbling precum,`);
+					}
+				} else if (s.vagina === -1) {
+					r.push(`${He}'s unconsciously presenting ${his} bottom,`);
+				} else {
+					r.push(`${His} pussy is visibly soaked,`);
+				}
+				r.push(`showing unmistakably how badly ${he} needs release.`);
+			} else {
+				r.push(`${He} keeps ${his}`);
+				if (canSee(s)) {
+					r.push(App.Desc.eyesColor(s));
+				} else {
+					r.push(`face`);
+				}
+				r.push(`slightly downcast, ${his} back arched, ${his} chest pressed outward, and ${his} bottom stuck out a bit. ${He}'s the perfect picture of an obedient little sex slave`);
+				if (s.height > 185) {
+					r.push(`(though, of course, ${he}'s anything but physically small)`);
+				}
+				r.push(r.pop() + `.`);
+			}
+			return r.join(" ");
+		},
+		prereqs: [
+			/* TESTING */
+			s => s.fetish !== Fetish.MINDBROKEN,
+			hasAnyArms,
+			canWalk,
+			s => s.devotion > 20,
+			s => s.trust > -10
+		]
+	},
+	{
+		getGreeting: (s) => {
+			const {
+				His, He, he, his, him, himself
+			} = getPronouns(s);
+			const belly = bellyAdjective(s);
+			// SRC objectifyingVisit.js
+			let r = [];
+			r.push(`At appropriate intervals during the day ${V.assistant.name} directs an unoccupied slave to visit your office to ensure all your needs are currently being met. With such a vague task set before them, the slaves who enter your domain in such a way often find themselves used in a multitude of refreshingly novel ways. At this particular moment ${s.slaveName} comes through the door of your office and obediently`);
+			if (s.belly >= 300000) {
+				r.push(`settles ${himself}`);
+			} else {
+				r.push(`kneels`);
+			}
+			r.push(`beside your desk to await further orders. It occurs to you, gazing down at your obedient slave, that ${he} exists as little more than an object to meet your various needs. Perhaps you should treat ${him} as such.`);
+			return r.join(" ");
+		},
+		prereqs: [
+			/* TESTING  */
+			s => s.fetish !== Fetish.MINDBROKEN,
+			hasAnyArms,
+			hasAnyLegs,
+			s => s.trust > 20,
+			s => s.devotion > 50
+		]
+	},
+	{
+		getGreeting: (s) => {
+			const {
+				His, He, he, his, him, himself
+			} = getPronouns(s);
+			const { title: Master, say } = getEnunciation(s);
+			const belly = bellyAdjective(s);
+			const hands = (hasBothArms(s)) ? `hands` : `hand`;
+			// SRC terrifiedInspection
+			let r = [];
+			r.push(` ${s.slaveName} appears in the door of your office for a scheduled inspection. ${He} hesitates in the doorway,`,
+			);
+			if (canSee(s)) {
+				r.push(`staring fixedly downward with huge ${App.Desc.eyesColor(s)},`);
+			} else {
+				r.push(`${his} face towards the floor,`);
+			}
+			r.push(`before stumbling forward to stand in front of your desk. ${His} chest is rising and falling with panicked hyperventilation. The poor ${SlaveTitle(s)} is terrified of you for some reason.`);
+			r.push(`\n\n`);
+			r.push(`You let ${him} stand there naked and shivering while you finish what you're working on. ${He} holds ${his} ${s.skin}`);
+			if (hasBothArms(s)) {
+				r.push(`hands down at ${his} sides, just like ${he}'s supposed to, but they twitch`);
+			} else {
+				r.push(`hand down at ${his} side, just like ${he}'s supposed to, but it twitches`);
+			}
+			r.push(`inward occasionally, betraying ${his} desire to shield ${his}`);
+			if (s.nipples === "huge") {
+				r.push(`prominent nipples`);
+			} else if (s.boobs > 1000) {
+				r.push(`big tits`);
+			} else {
+				r.push(`chest`);
+			}
+			r.push(`and`);
+			if (s.dick >= 10) {
+				r.push(`massive, limp dick`);
+			} else if (s.dick > 7) {
+				r.push(`huge, limp dick`);
+			} else if (s.dick > 3) {
+				r.push(`big, limp dick`);
+			} else if (s.dick > 0) {
+				r.push(`limp little prick`);
+			} else if (s.clit > 1) {
+				r.push(`absurd clit`);
+			} else if (s.labia > 0) {
+				r.push(`pretty petals`);
+			} else if (s.vagina === -1) {
+				r.push(`smooth, featureless groin`);
+			} else {
+				r.push(`pussy`);
+			}
+			r.push(`from your view. The wait gives license to ${his} fears. ${His}`);
+			if (s.lips > 70) {
+				r.push(`ridiculous`);
+			} else if (s.lips > 0) {
+				r.push(`plush`);
+			}
+			r.push(`lips are quivering, and tears are quickly gathering at the corners of ${his} eyes.`);
+			return r.join(" ");
+		},
+		prereqs: [
+			/* TESTING */
+			s => s.fetish !== Fetish.MINDBROKEN,
+			hasAnyArms,
+			hasAnyLegs,
+			canTalk,
+			s => s.trust < -50,
+			s => s.devotion <= 20
+		]
+	},
+	{
+		getGreeting: (s) => {
+			const {
+				His, He, he, his, him, himself, girl
+			} = getPronouns(s);
+			const { title: Master, say } = getEnunciation(s);
+			const belly = bellyAdjective(s);
+			const PC = V.PC;
+			// SRC usedWhore.js
+			let r = [];
+			r.push(
+				`At the end of a long day, you take a moment to watch the comings and goings of your arcology to decompress. While doing so, you notice someone who's clearly had a longer day than you. ${s.slaveName} is`);
+			if (s.belly >= 5000) {
+				r.push(`slowly waddling, one hand under ${his} ${belly}`);
+				if (s.bellyPreg >= 3000) {
+					r.push(`pregnant`);
+				}
+				r.push(`belly and the other on the small of ${his} back,`);
+			} else {
+				r.push(`making`);
+			}
+			r.push(`${his} tired way back to the kitchen for a meal and then bed after a long day of sex work. ${He}'s stripped off ${his} soiled clothes already, and is clearly too tired to care about nudity at all.`);
+			r.push(`\n\n`);
+			r.push(`${He} comes around the corner and`);
+			if (PC.belly >= 100000) {
+				r.push(`slams into your massively distended belly, nearly knocking you over.`);
+			} else if (PC.belly >= 10000) {
+				r.push(`bumps into your heavily gravid middle.`);
+			} else if (PC.belly >= 5000) {
+				r.push(`bumps into your rounded middle.`);
+			} else if (PC.balls >= 14) {
+				r.push(`nearly knees your prominent testicles.`);
+			} else if (PC.boobs >= 800) {
+				r.push(`runs into your prominent rack.`);
+			} else {
+				r.push(`almost runs into you.`);
+			}
+			r.push(`${He} stops and`);
+			if (canSee(s)) {
+				r.push(`stares,`);
+			} else {
+				r.push(`faces you,`);
+			}
+			r.push(`struggling to find the appropriate thing to say or do, but too exhausted to manage it. Even though ${he}'s been obediently cleaning ${himself} between fucks, ${he} looks used up. ${His} ${s.skin} skin is reddened here and there.`);
+			if (s.belly >= 750000) {
+				r.push(`${His} ${belly} belly is heavily bruised, the super-stretched skin nearly at its limit from the weight put on it and the forces pushing against it.`);
+			} else if (s.belly >= 600000) {
+				r.push(`${His} ${belly} belly is deep red and heavily bruised; it's clear that at least one client roughly fucked ${him} over it.`);
+			} else if (s.belly >= 450000) {
+				r.push(`${His} ${belly} belly looks extremely painful, it's obvious ${he} got fucked over it.`);
+			} else if (s.belly >= 300000) {
+				r.push(`${His} ${belly} belly is black and blue, it's obvious ${he} got fucked over it.`);
+			} else if (s.belly >= 150000) {
+				r.push(`${His} ${belly} belly is heavily chafed from rubbing the floor as ${he} struggled to keep ${his} weight off it.`);
+			} else if (s.belly >= 100000) {
+				r.push(`${His} ${belly} belly is heavily chafed from rubbing against the floor.`);
+			} else if (s.belly >= 10000) {
+				r.push(`The tip of ${his} huge belly is chafed from rubbing against the floor.`);
+			}
+			if (canDoVaginal(s)) {
+				r.push(`${His}`);
+				if (s.labia > 1) {
+					r.push(`generous`);
+				} else {
+					r.push(`poor`);
+				}
+				r.push(`pussylips are puffy, and you have no doubt ${his} vagina is quite sore.`);
+			}
+			if (canDoAnal(s)) {
+				r.push(`The awkward way ${he}'s standing suggests that ${his}`);
+				if (s.anus > 2) {
+					r.push(`gaping`);
+				} else if (s.anus > 1) {
+					r.push(`big`);
+				} else {
+					r.push(`tight`);
+				}
+				r.push(`asshole has had more than one dick up it recently.`);
+			}
+			if (s.nipples !== "fuckable") {
+				r.push(`Even ${his} nipples are pinker than usual, having been cruelly pinched`);
+				if (s.lactation > 0) {
+					r.push(`and milked`);
+				}
+				r.push(r.pop() + `.`);
+			} else {
+				r.push(`Even ${his} nipples show signs of wear, having prolapsed slightly from heavy use.`);
+			}
+			return r.join(" ");
+		},
+		prereqs: [
+			/* TESTING */
+			s => s.fetish !== Fetish.MINDBROKEN,
+			hasAnyArms,
+			hasAnyLegs,
+			s => s.vagina !== 0,
+			s => s.anus !== 0,
+			s => s.devotion <= 50
+		]
+	},
+	{
+		getGreeting: (s) => {
+			const {
+				His, He, he, his, him, himself
+			} = getPronouns(s);
+			const { title: Master, say } = getEnunciation(s);
+			const belly = bellyAdjective(s);
+			const PC = V.PC;
+			// SRC likeMe.js
+			let r = [];
+			r.push(
+				`${s.slaveName} appears at the door of your office, looking frightened. ${He} takes one hesitant step in and stops, wavering, ${his} hand balled into fists and ${his} lower lip caught behind ${his} teeth. The ${SlaveTitle(s)} is getting used to ${his} place as chattel, but ${he} isn't sure of ${himself} yet. After a few moments, it becomes obvious that ${he}'s lost whatever mental momentum propelled ${him} to come in here, and can't muster the courage to back out, either. You rescue ${him} by politely but firmly ordering ${him} to tell you why ${he}'s here. After two false starts, ${he}`
+			);
+			if (!canTalk(s)) {
+				r.push(`uses shaky hands to ask you to fuck ${him}.`);
+			} else {
+				r.push(
+					Spoken(s, `"P-please fuck me, ${Master},"`),
+					`${he} chokes out.`
+				);
+			}
+			r.push(`To go by ${his} behavior, the likelihood that ${he}'s actually eager to`);
+			if (PC.dick === 0) {
+				r.push(`eat pussy,`);
+			} else {
+				r.push(`take a dick,`);
+			}
+			r.push(`never mind yours, is vanishingly small.`);
+			return r.join(" ");
+		},
+		prereqs: [
+			/* TESTING */
+			s => s.fetish !== Fetish.MINDBROKEN,
+			hasAnyArms,
+			hasAnyLegs,
+			s => s.trust <= 20,
+			s => s.trust >= -75,
+			s => s.devotion <= 30,
+			s => s.devotion >= -20
+		]
+	}
+]
-- 
GitLab