code:
App.Events.rePregInventorShowOff = class rePregInventorShowOff extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.pregInventor === 1,
		];
	}

	actorPrerequisites() {
		return [
			[
				s => s.ID === V.pregInventorID,
				s => s.bellyPreg >= 600000,
				s => s.fetish !== "mindbroken",
				s => s.fuckdoll === 0,
				s => s.devotion > 50
			],
		];
	}

	execute(node) {
		/** @type {Array<App.Entity.SlaveState>} */
		let [slave] = this.actors.map(a => getSlave(a));
		const {
			He, His,
			he, his, him, himself, woman, hers
		} = getPronouns(slave);
		const legs = hasBothLegs(slave) ? `legs` : `leg`;
		const arms = hasBothArms(slave) ? `arms` : `arm`;
		const {title: Master, say: say} = getEnunciation(slave);
		App.Events.drawEventArt(node, slave);
		const tvCost = 10000;
		let r = [];

		r.push(
			`Your broodmother,`,
			App.UI.DOM.combineNodes(App.UI.DOM.slaveDescriptionDialog(slave), `,`),
			`has been using the resources you gave ${him} to expand the possibilities for sex with hyperpregnant slaves. ${He} has been working hard and is finally ready to show off ${his} results. Your assistant gives you a list of the slave's innovations and you decide to give one a try:`
		);
		App.Events.addParagraph(node, r);

		const responses = [
			new App.Events.Result(`Have ${him} show off ${his} developments in the sport of advanced maternity swing gymnastics.`, swing),
			new App.Events.Result(`Have ${him} give you a trained assisted strip show`, strip),
		];
		if (V.spa !== 0) {
			responses.push(new App.Events.Result(`Enjoy a game of 'jelly' wrestling in your new curative gelatin pool.`, wrestle));
		}

		App.Events.addResponses(node, responses);

		function swing() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`${He} is brought into your office alongside ${his} invention: a customized maternity swing. It is a true marvel of Free Cities engineering, resembling something designed for use with large marine mammals rather than a sex aid for a pregnant ${woman}. It has been specially rigged to support both its user and their sexual partner, and to suspend them in the air, enabling them to explore sex positions that would otherwise be rendered impossible by a hyperpregnant slave's mass and size. Just watching the effort your menials expend squeezing the ${SlaveTitle(slave)} into a device that would dwarf a normal person is enough to get you excited, and you're fully ready to enjoy some personal time with ${him} by the time they've hooked you both into the device. The maternity swing is controlled via a vocal command system and, as your menials retreat to give you time alone, you instruct it to lift both you and ${him} into the air.`);
			App.Events.addParagraph(frag, r);
			r = [];
			r.push(`The reinforced silk supports strain slightly under the weight of your slave's belly, but they make no noise, and you soon find yourself suspended in midair with ${his}`);
			if (slave.vagina >= 10) {
				r.push(`huge, weeping pussy lips`);
			} else if (slave.vagina >= 6) {
				r.push(`loose pussy`);
			} else if (slave.vagina >= 3) {
				r.push(`pussy`);
			} else {
				r.push(`tight little pussy`);
			}
			r.push(`at perfect eye level. You go down on ${him} to get ${him} primed and enjoy the feeling of`);
			if (hasAnyLegs(slave)) {
				r.push(`${his} ${legs} wrapping around your head`);
			} else {
				r.push(`${his} stumps squeezing the sides of your head`);
			}
			r.push(`as you bring ${him} to climax.`);
			seX(slave, "vaginal", V.PC, "penetrative");
			App.Events.addParagraph(frag, r);
			r = [];
			r.push(`With gentle coaching from your slave, you rotate the two of you in the air so that ${he} can ride you reverse cowgirl style. ${VCheck.Vaginal(slave, 2)} You then switch ${him} around, allowing ${his} belly to eclipse your vision entirely as ${he} rides you in the traditional cowgirl position. The contents of ${his} womb have exploded its weight to the point that this position would have previously been hazardous to both your health and ${hers}, if not completely impossible, and the illusion of having sex while perpetually on the knife's edge of being flattened by literal tons of baby packed slave flesh sends you over the edge. You`);
			if (V.PC.dick !== 0) {
				r.push(`ejaculate into ${him}, your cum dripping out of ${his} vagina, splattering on the ground below.`);
			} else {
				r.push(`orgasm as you transition into scissoring with your tightly packed broodmare, keeping the fantasy of being crushed by ${his} body foremost in your mind.`);
			}
			App.Events.addParagraph(frag, r);
			r = [];
			r.push(`You explore many other sexual positions before commanding the maternity swing to take you back to earth. You extricate yourself from the device, but leave ${him} inside of it. ${He} does a little twirl in the device, showing off the shape of ${his} hyper-inflated body${(hasAnyLegs(slave)) ? `, the tips of ${his} toes barely touching the ground` : ``}.`);
			App.Events.addParagraph(frag, r);
			r = [];
			if (canTalk(slave)) {
				r.push(
					Spoken(slave, `"So what did you think, ${Master}?"`),
					`${he} asks. ${He} purses ${his} lips, waiting for your response.`
				);
			} else {
				r.push(`${He} motions to you, making it clear ${he}'s waiting for your judgment.`);
			}
			slave.devotion += 5;
			r.push(followUp());
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function strip() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`The first thing that you notice when your slave walks through the door is the way ${he} struts in with apparent ease. It's been quite a while since you've seen ${him} walk with any sort of elegance, but ${he} does so now. ${He} spins around, giving you a look at ${his}`);
			if (slave.butt > 11) {
				r.push(`debilitating, insanely enormous ass`);
			} else if (slave.butt > 5) {
				r.push(`huge ass`);
			} else if ((slave.buttImplant / slave.butt) > .60) {
				r.push(`implant swollen ass cheeks`);
			} else if (slave.butt > 2) {
				r.push(`plump ass`);
			} else {
				r.push(`slender ass`);
			}
			r.push(`and then shakes ${his} booty, glancing over ${his} shoulder to `);
			if (canSee(slave)) {
				r.push(`see`);
			} else {
				r.push(`judge`);
			}
			r.push(`how you react. You motion for ${him} to continue and ${he} turns around and approaches you, stopping only when ${his} massive belly is looming in front of you, almost touching you. You look over the apex of ${his} stomach to consider the "invention" ${he}'s developed to enable ${his} miraculous mobility.`);
			App.Events.addParagraph(frag, r);
			r = [];
			r.push(`A significant number of menial slaves have been repurposed and specially trained to aid your hyperbroodmother and ${his} incredible belly. These menials,`);
			if (V.arcologies[0].FSPaternalist > 60) {
				r.push(`outfitted with expensive safety gear to protect them during their potentially dangerous endeavors,`);
			} else if (V.arcologies[0].FSRepopulationFocus > 60) {
				r.push(`themselves pregnant, though not nearly as large,`);
			} else if (V.arcologies[0].FSRestart > 60) {
				r.push(`low-quality stock unfit to serve as breeders,`);
			} else if (V.arcologies[0].FSPastoralist > 60) {
				r.push(`their huge, milky tits squashed up against your slave's body, leaking milk,`);
			} else if (V.arcologies[0].FSAssetExpansionist > 60) {
				r.push(`their huge tits and asses serving as exotic cushions for the tender flesh of your massively bloated hyperbroodmother,`);
			} else if (V.arcologies[0].FSTransformationFetishist > 60) {
				r.push(`their huge implanted tits and asses clearly designed to maximize their potential as cushions for your massively bloated hyperbroodmother,`);
			} else if (V.arcologies[0].FSPhysicalIdealist > 60) {
				r.push(`their impressive muscles rippling as they exert themselves,`);
			} else if (V.arcologies[0].FSHedonisticDecadence > 60) {
				r.push(`surprisingly strong, given how plush they are, and well suited for their job,`);
			} else if (V.arcologies[0].FSChattelReligionist > 60) {
				r.push(`dressed in skimpy monks habits and eyes flashing with exalted fervor as they go about their duties,`);
			} else if (V.arcologies[0].FSYouthPreferentialist > 60) {
				r.push(`just barely the legal age for consent in your arcology and clearly eager to prove themselves,`);
			} else if (V.arcologies[0].FSMaturityPreferentialist > 60) {
				r.push(`plush MILFs who support your hyperbroodmother's insane pregnancy with a hint of maternal affection,`);
			} else if (V.arcologies[0].FSSlimnessEnthusiast > 60) {
				r.push(`lithe and possessed of wiry strength,`);
			} else if (V.arcologies[0].FSStatuesqueGlorification > 60) {
				r.push(`impressively tall and quite capable of handling your massively bloated hyperbroodmother,`);
			} else if (V.arcologies[0].FSPetiteAdmiration > 60) {
				r.push(`tiny and trying their hardest to move ${him},`);
			} else if (V.arcologies[0].FSSlaveProfessionalism > 60) {
				r.push(`quick witted slaves who flawlessly redirect attention to your hyperpregnant star,`);
			} else if (V.arcologies[0].FSIntellectualDependency > 60) {
				r.push(`very aroused and having trouble staying focused when so intimately close to such an expanse of flesh,`);
			} else if (V.arcologies[0].FSRomanRevivalist > 60) {
				r.push(`dressed in a skimpy reproduction of roman legionary garb,`);
			} else if (V.arcologies[0].FSNeoImperialist > 60) {
				r.push(`dressed in skimpy bodysuits that outline their tight bodies,`);
			} else if (V.arcologies[0].FSAztecRevivalist > 60) {
				r.push(`clad only in exotic feathers,`);
			} else if (V.arcologies[0].FSEgyptianRevivalist > 60) {
				r.push(`dressed in `);
				if (hasAnyLegs(slave)) {
					r.push(`ankle-length`);
				} else {
					r.push(`long`);
				}
				r.push(`tarkhans made of brass and turquoise colored beads,`);
			} else if (V.arcologies[0].FSEdoRevivalist > 60) {
				r.push(`dressed in skimpy noh theater costumes,`);
			} else if (V.arcologies[0].FSArabianRevivalist > 60) {
				r.push(`their sinful figures made modest by roomy abayas,`);
			} else if (V.arcologies[0].FSChineseRevivalist > 60) {
				r.push(`clad in traditional silk chang'ao and lotus shoes,`);
			} else {
				r.push(`their clothing specifically chosen to supplement and flatter your hyperbroodmother's own outfit,`);
			}
			r.push(`act to support ${his} movements as ${he} teases you, seemingly heedless of their own safety. Their ego has been subsumed in pursuit of their duties and, as they fall into place to hold up ${his} gargantuan belly with each of ${his} slightest, most thoughtless movements, they give you the impression of being more extensions of ${his} will than independent beings. Your hyperbroodmother leans forward, just the slightest bit, as you consider ${his} assistants, and presses ${his} unfathomable stomach into your crotch. As ${he} does so, two of ${his} assistants slide under ${his} belly with practiced ease, cushioning it with their bodies to prevent it from touching the cold ground. No sound passes their lips as the gargantuan organ crushes down on them, but you can hear their bones creak.`);
			App.Events.addParagraph(frag, r);
			r = [];
			if (canTalk(slave)) {
				r.push(Spoken(slave, `"Oooh, someone likes what they see,"`));
				r.push(`${he} ${say}s.`);
			} else {
				r.push(`${He} can't speak, but ${he} does grin and roll ${his} belly up and down your lap for a moment, ${his} servants lifting and supporting ${him} from the periphery such that ${he} seems to be in casual control of ${his} immobilizing bulk.`);
			}
			App.Events.addParagraph(frag, r);
			r = [];
			r.push(`It is only then that you realize that`);
			if (V.PC.dick !== 0) {
				r.push(`your dick is as hard as a length of steel.`);
			} else {
				r.push(`your kitty is positively drowning in fem-cum.`);
			}
			r.push(`You move to touch ${his} belly, but ${he} steps backward, leaving it just out of reach.`);
			App.Events.addParagraph(frag, r);
			r = [];
			if (canTalk(slave)) {
				r.push(
					Spoken(slave, `"If you'll permit, ${Master},"`),
					`${he} ${say}s teasingly,`,
					Spoken(slave, `"I'd like to show off my 'invention' just a little longer."`)
				);
			} else {
				r.push(`${He} smirks and`);
				if (hasAnyArms(slave)) {
					r.push(`motions to you that ${he}'d like to tease you just a little longer.`);
				} else {
					r.push(`one of ${his} servants, seeming to read their mistress's mind, motions to you that your slave has something big to show off still.`);
				}
			}
			App.Events.addParagraph(frag, r);
			r = [];
			r.push(`You motion for ${him} to continue.`);
			if (hasAnyArms(slave)) {
				r.push(`${He} lifts ${his} ${arms} over ${his} head and begins to spin again, giving you a glorious view of ${his}`);
			} else {
				r.push(`${His} servants spin ${him} again, giving you a glorious view of ${his}`);
			}
			if (slave.boobs >= 20000) {
				r.push(`eye wateringly massive tits`);
			} else if (slave.boobs >= 3000) {
				r.push(`huge tits`);
			} else if ((slave.boobsImplant / slave.boobs) >= .60) {
				r.push(`luscious, augmented tits`);
			} else {
				r.push(`petite breasts`);
			}
			r.push(`and`);
			if (slave.butt > 11) {
				r.push(`couch smothering ass cheeks.`);
			} else if (slave.butt > 5) {
				r.push(`enormous ass.`);
			} else if ((slave.buttImplant / slave.butt) > .60) {
				r.push(`implant-filled ass.`);
			} else if (slave.butt > 2) {
				r.push(`delicious looking ass.`);
			} else {
				r.push(`small ass.`);
			}
			r.push(`As ${he} spins, ${his} servants support ${his} motions, using their own bodies to cushion and propel ${him} in the direction ${he} wants. They move in a limp manner that seems to blend into ${his} body, keeping the focus of your attention on your slave's form rather than theirs. One enters your office with a portable stripper stage, complete with pole, and your slave makes ${his} way over to it.`);
			if (canTalk(slave)) {
				r.push(
					Spoken(slave, `"There were some... sacrifices,"`),
					`${he} ${say}s,`,
					Spoken(slave, `"to get where we are today."`)
				);
				if (hasAnyArms(slave)) {
					r.push(`${He} raises ${his} ${arms} as ${his} myriad servants plaster themselves to ${his} monolithic body, raising ${his} considerable bulk to a sufficient height to allow ${him} to take hold of the pole.`);
				} else {
					r.push(`${He} raises a dainty stub and one of ${his} myriad servants, pressed back to back with ${him} to help support ${his} weight as the others push ${him} into position, snakes a hand upward, creating the illusion that, for just this moment, your amputee broodmother is whole once more and grabbing onto the pole.`);
				}
			} else {
				if (hasAnyArms(slave)) {
					r.push(`${He} motions to you that there were some sacrifices, raising ${his} ${arms} as ${his} myriad servants plaster themselves under ${his} monolithic belly, raising ${his} considerable bulk to sufficient height to allow ${him} to take hold of the pole.`);
				} else {
					r.push(`The servant serving as the "mouth" for your mute, limbless hyperpregnant slave motions to you that there were some sacrifices. Your slave raises a dainty stub and one of ${his} myriad servants, pressed back to back with ${him} to help support ${his} weight as the others push ${him} into position, snakes a hand upward, creating the illusion that, for just this moment, your amputee broodmother is whole once more and grabbing onto the pole.`);
				}
			}
			App.Events.addParagraph(frag, r);
			r = [];
			if (canTalk(slave)) {
				r.push(Spoken(slave, `"I think you'll find, though..."`), `${he} ${say}s.`);
			} else if (hasAnyArms(slave)) {
				r.push(`${He} motions that "${he} believes you'll find," then falls into a coy silence.`);
			} else {
				r.push(`${His} mouthpiece motions that your slave "believes you'll find," then falls into a coy silence.`);
			}
			App.Events.addParagraph(frag, r);
			r = [];
			r.push(`${He}'s spinning around the pole now, reminding you of ${his} earlier motions. ${He} seems weightless, ${his} massive bulk perfectly supported regardless of the personal cost to those supporting ${him}. Your gaze turns to several motionless servants who have been knocked unconscious by ${his} careening bulk. They're piled up against a side wall, but inconspicuous. You can't recall when they collapsed, or when they were dragged away. The passiveness with which your slave's glorified human clothing moves makes even the collapsed menials seem natural and perfectly reasonable — just something that happens when your hyperbroodmother exercises ${his} body, sometimes. Not an abuse of another person. More like flexing a limb.`);
			App.Events.addParagraph(frag, r);
			r = [];
			r.push(`${His} servants surge upward, piling on top of each other and rotating ${him}. ${He} flips upside down and, for a moment, you worry that ${he} might fall with disastrous consequences. The mass of human bodies working in tandem to protect and enable ${him} executes its motions in perfect synchrony, however, and you are treated to the sight of an impossibly pregnant slave spinning upside down, hooking one`);
			if (hasAnyLegs(slave)) {
				r.push(legs);
			}
			r.push(`around a stripper pole, and performing a slow, effortless body inversion, ${his} massive upside down belly rotating just a split second slower than the rest of ${him}. ${He} rotates some more and then flips back into a normal standing position, leaning over ${his} stomach and once again slightly crushing ${his} now visibly exhausted servants as ${he} performs a mock bow.`);
			App.Events.addParagraph(frag, r);
			r = [];
			if (canTalk(slave)) {
				r.push(
					Spoken(slave, `"That it was worth it!"`),
					`${he} ${say}s, finishing ${his} earlier statement.`,
					Spoken(slave, `"So, what do you think?"`),
					`${he} asks. ${He} seems not even slightly out of breath.`
				);
			} else if (hasAnyArms(slave)) {
				r.push(`${He} motions to you, communicating the last part of ${his} earlier message: "that it was worth it!" ${He} then indicates that ${he} is waiting for your opinion. You note that ${he} hasn't even broken a sweat.`);
			} else {
				r.push(`${His} mouthpiece motions to you, communicating the last part of the message your slave started earlier: "that it was worth it!" The menial then indicates that your slave is waiting for your opinion of ${his} work. You note that your hyperbroodmother hasn't even broken a sweat.`);
			}
			r.push(followUp());
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function wrestle() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`Your slave asks you to meet ${him} in your spa. Upon entering, you take a moment to enjoy the`);
			if (V.spaDecoration === "Paternalist") {
				r.push(`sight of the opulently appointed pools and the intellectually stimulating shows streaming from the many screens set on the walls of the room.`);
			} else if (V.spaDecoration === "Repopulationist") {
				r.push(`sight of all of the maternity aid devices scattered throughout the room. Whatever the nature of ${his} invention, your slave's toy is guaranteed to fit in well in these particular baths.`);
			} else if (V.spaDecoration === "Eugenics") {
				r.push(`sight of the dualistic, caste based facilities.`);
			} else if (V.spaDecoration === "Pastoralist") {
				r.push(`faint smell of milk that wafts through the room with the steam and the sight of the many aid devices that your hypermassive slaves absolutely require to make use of the facilities.`);
			} else if (V.spaDecoration === "Asset Expansionist") {
				r.push(`sight of the aid equipment that your hypermassive slaves absolutely require to make use of the facilities.`);
			} else if (V.spaDecoration === "Transformation Fetishist") {
				r.push(`sight of the various surgical recovery devices scattered throughout the room.`);
			} else if (V.spaDecoration === "Physical Idealist") {
				r.push(`sight of the various light impact workout machines scattered throughout the room.`);
			} else if (V.spaDecoration === "Hedonistic") {
				r.push(`smell of the lavishly appointed cornucopias of food scattered around the facility's many opulent pools.`);
			} else if (V.spaDecoration === "Chattel Religionist") {
				r.push(`sight of the ritual pools and the various icons of the faith scattered throughout the room.`);
			} else if (V.spaDecoration === "Youth Preferentialist") {
				r.push(`carnival atmosphere created by the waterpark theming of the facilities.`);
			} else if (V.spaDecoration === "Gender Radicalist") {
				r.push(`sight of the extreme penetration based pornography feeds streaming from the many screens set on the walls of the room.`);
			} else if (V.spaDecoration === "Gender Fundamentalist") {
				r.push(`sight of the traditionalist pornographic feeds streaming from the many screens set on the walls of the room.`);
			} else if (V.spaDecoration === "Maturity Preferentialist") {
				r.push(`sight of the many businesslike, beautifying devices and service stations scattered throughout the room.`);
			} else if (V.spaDecoration === "Slimness Enthusiast") {
				r.push(`comfortable atmosphere of the facilities.`);
			} else if (V.spaDecoration === "Degradationist") {
				r.push(`sight of the all-seeing cameras scattered throughout the room. You give a nod to one of the obvious ones, knowing there's an audience watching.`);
			} else if (V.spaDecoration === "Roman Revivalist") {
				r.push(`sight of the sexual mosaics at the bottom of its spacious baths.`);
			} else if (V.spaDecoration === "Aztec Revivalist") {
				r.push(`sight of its golden idols and exotic animal trophies as well as the warm smell of tropical herbs.`);
			} else if (V.spaDecoration === "Egyptian Revivalist") {
				r.push(`heavy perfumed air pervading the room and the sight of its warm, reed lined pools.`);
			} else if (V.spaDecoration === "Edo Revivalist") {
				r.push(`steam rising up off of the stone-lined onsen pools.`);
			} else if (V.spaDecoration === "Arabian Revivalist") {
				r.push(`vibrant tilework and the smell of the heavy perfume in the steamy air.`);
			} else if (V.spaDecoration === "Chinese Revivalist") {
				r.push(`stultifying, gloomy atmosphere pervading the room.`);
			} else if (V.spaDecoration === "Body Purist") {
				r.push(`comfortable atmosphere of the facilities.`);
			} else if (V.spaDecoration === "Neo-Imperialist") {
				r.push(`sight of the verdant greenery, brilliant high-tech lighting, and steaming central bath.`);
			} else {
				r.push(`sight of its spacious baths and pleasant atmosphere.`);
			}
			r.push(`Your eyes then fall on what must be ${his} invention: a new pool, set in a corner. It's not Olympic size, but it is quite large compared to most of your other pools — a large oval — and it is completely filled with a clear, gooey substance. Lounging in it, facing you and with ${his} massive belly poking out just far enough for you to enjoy the sight of ${his} bulging "outie" belly button, is your slave, wearing an attractive bikini that seems to be soaked through with whatever goo is filling the pool. ${He}`);
			if (hasAnyArms(slave)) {
				r.push(`waves at you and then gently rolls forward onto ${his} astounding pregnancy,`);
			} else {
				r.push(`waves a stub at you and then pokes it at a holographic remote array hovering nearby. A mobility assistance device in the pool rolls ${him} forward onto ${his} astounding pregnancy,`);
			}
			if (slave.boobs >= 20000) {
				r.push(`causing ${his} insanely enormous tits to flop onto the tile at the pool's edge with a loud "thwack."`);
			} else if (slave.boobs >= 3000) {
				r.push(`resting ${his} enormous breasts on the pool's edge, causing them to push up into ${his} chin as ${he} looks up at you.`);
			} else if ((slave.boobsImplant / slave.boobs) >= .60) {
				r.push(`resting ${his} huge, implant-distended tits on the pool's edge, causing them to push up into ${his} chin as ${he} looks up at you.`);
			} else {
				r.push(`giving you a nice view of ${his} cute tits.`);
			}
			App.Events.addParagraph(frag, r);
			r = [];
			if (canTalk(slave)) {
				r.push(
					Spoken(slave, `"Hi, ${Master},"`),
					`${he} ${say}s.`,
					App.UI.DOM.makeElement("span", Spoken(slave, `"Oooooh...`), "italic"),
					Spoken(slave, `you have no idea how good this feels. My aching belly is warmed all through — well? Why don't you come in and I'll explain things."`),
				);
			} else if (hasAnyArms(slave)) {
				r.push(`${He} motions to you in more formal greetings and then lets out an involuntary moan of pleasure, rubbing at the sides of ${his} tremendous belly. ${He} beckons you to enter the pool.`);
			} else {
				r.push(`${He} is limbless as well as mute, so ${he} can't greet you more formally, but ${his} pleasurable, incomprehensible moaning and the way ${he} presses ${his} stumps into ${his} monstrously inflated, baby packed belly makes it clear to you that ${he}'s happy to see you. You decide to get into the pool to try out your slave's invention for yourself.`);
			}
			App.Events.addParagraph(frag, r);
			r = [];
			r.push(`You strip and put on one of the swimming outfits that are stored in the baths for your personal use, then slide yourself into the pool, squeezing in between its wall and your hyperswollen broodmother. The gel has a medicinal scent masked by lavender and is the perfect warmth to ease your muscles as you slide into it. Your skin tingles at its touch.`);
			App.Events.addParagraph(frag, r);
			r = [];
			if (canTalk(slave)) {
				r.push(
					Spoken(slave, `"It's curative jelly,"`),
					`your slave explains.`,
					Spoken(slave, `"I'm so big, now, it takes most of the day to moisturize my poor belly, even with help. With this jelly pool, it only takes a few minutes. I'm sure this pool can help all sorts of slaves with big assets so that they can keep themselves looking pretty for their ${Master}."`)
				);
			} else {
				if (hasAnyArms(slave)) {
					r.push(`${He} motions to you, explaining in sign that the pool is filled with curative gel. It's designed to help slaves with enormous assets moisturize their oversized bodies without having to spend all day applying it manually.`);
				} else {
					r.push(`Your personal assistant chimes in to explain that the pool is filled with curative gel. It's designed to help slaves with enormous assets moisturize their oversized bodies without having to spend all day applying it manually.`);
				}
			}
			App.Events.addParagraph(frag, r);
			r = [];
			if (hasAnyArms(slave)) {
				r.push(`${He} presses a few buttons on a holographic remote array`);
			} else {
				r.push(`${He} nods a signal`);
			}
			r.push(`and a series of silk-lined spherical rollers at the base of the pool come to life, humming as they spin ${his} laden body around. ${He} pushes into your chest, rotating forward so that ${his}`);
			if (slave.boobs >= 20000) {
				r.push(`colossal breasts spread out around you, completely surrounding your head. With some effort, you part ${his} heavy cleavage enough to be able to continue listening to ${him} without being smothered.`);
			} else if (slave.boobs >= 3000) {
				r.push(`massive chest fills the space between you, blocking your view of ${his} face. You spread ${his} cleavage enough to be able to continue listening to ${him}.`);
			} else if ((slave.boobsImplant / slave.boobs) >= .60) {
				r.push(`fat, implanted tits fill the space between you, blocking your view of ${his} face. With some effort, you spread ${his} tightly packed, spherical cleavage enough to be able to continue listening to ${him}.`);
			} else {
				r.push(`spherical belly pushes into your crotch.`);
			}
			if (hasAnyArms(slave)) {
				r.push(`${He} then reaches out and, after you nod that ${he} can continue, ${he} caresses your face.`);
			} else {
				r.push(`${He} then reaches out to caress your face, but blushes and stops the motion as ${he} remembers that ${he} is physically unequipped to do so.`);
			}
			r.push(`${His} weight falls onto you and pushes you into the cushioned wall of the pool. The wall gives beneath your combined bulk, swelling down and outward to accommodate and support you.`);
			App.Events.addParagraph(frag, r);
			r = [];
			if (canTalk(slave)) {
				r.push(
					Spoken(slave, `"Do you like it, ${Master}?"`),
					`${he} asks.`,
					Spoken(slave, `"It's built to grow and change as your slaves do. It should be the perfect size to support them, no matter what that size might be. And if we ever get too big for even that, well..."`),
					`${he} smiles and you realize that, between the feeling of ${his} heavy, slick mass pressing into you and the rejuvenating effect of the gel,`);
				if (V.PC.dick !== 0) {
					r.push(`you're hard as a rock and`);
				} else {
					r.push(`your pussy is absolutely weeping and you are`);
				}
				r.push(`as refreshed and eager to fuck as you've been in quite some time.`);
				r.push(Spoken(slave, `"We can always just make it... bigger."`));
			} else {
				if (hasAnyArms(slave)) {
					r.push(`${He} motions to you, explaining that the pool is designed to grow to accommodate and support its users, then smiles. You realize that, between the feeling of ${his} heavy, slick mass pressing into you and the rejuvenating effect of the gel,`);
					if (V.PC.dick !== 0) {
						r.push(`you're hard as a rock${(V.PC.vagina > -1) ? `, your pussy is absolutely weeping,` : ``} and`);
					} else {
						r.push(`your pussy is absolutely weeping and you are`);
					}
					r.push(`as refreshed and eager to fuck as you've been in quite a while.`);
				} else {
					r.push(`Your personal assistant explains that the pool has been designed to grow to accommodate and support its users. You're only half-listening to what ${he} is saying, however, as you have suddenly realized that, between the feeling of your slave's heavy, slick mass pressing into you and the rejuvenating effect of the gel,`);
					if (V.PC.dick !== 0) {
						r.push(`you're hard as a rock and`);
					} else {
						r.push(`your pussy is absolutely weeping and you are`);
					}
					r.push(`as refreshed and eager to fuck as you've been in quite a while.`);
				}
			}
			App.Events.addParagraph(frag, r);
			r = [];
			r.push(`Your arousal gives you an idea, and you push back on your hyperbroodmother's colossal belly. ${He} steps away from you until ${he} is in the center of the pool, a look of confusion on ${his} face. You take control of the remote and then manipulate the reticulating frame supporting the pool such that it lifts the floor, slowly rendering both you and your colossal-bellied breeder knee deep in the warm gel. You hunker down into an aggressive, combative stance and`);
			if (hasAnyCyberneticEyes(slave)) {
				r.push(`${his} ${App.Desc.eyesColor(slave, "synthetic")} flash white for a moment as a look of understanding dawns on ${his} face.`);
			} else {
				r.push(`a look of understanding lights up in ${his} ${App.Desc.eyesColor(slave)}.`);
			}
			if (!canTalk(slave)) {
				if (hasAnyArms(slave)) {
					r.push(`${He} waves ${his} ${arms} in mock dismay`);
					if (slave.skill.combat > 0) {
						r.push(`and lowers ${his} guard`);
					}
					r.push(`as you prepare to wrestle ${him} in the pool of goop.`);
				} else {
					r.push(`${He} waves ${his} stubs in mock dismay as you prepare to wrestle ${him} in the pool of goop.`);
				}
			} else {
				r.push(Spoken(slave, `"Oh no,"`), `${he} ${say}s in mock dismay${(slave.skill.combat > 0) ? `, lowering ${his} guard` : ``}. "My ${Master} is going to wrestle me into submission in this hot, heavy, goo pool. Whatever will I do?"`);
			}
			r.push(`You circle around ${him}, slowly approaching ${him}, and ${he} uses the pool's mobility assistance tools to rotate ${his} body so that ${he} can just barely keep you in ${his} gaze, drizzling gel over ${his} belly as ${he} keeps it between you and ${him} to use as a protective barrier. When you're close enough to touch the apex of ${his} fecund body, you leap forward through the gel, diving to one side and disappearing under it. Your momentum carries you a reasonable distance despite the resistance of the thick substance and you pop back up directly behind ${him}. You grab ${him} under ${his} armpits, pressing your`);
			if (V.PC.dick !== 0) {
				r.push(`rigid dick against ${his}`);
			} else {
				r.push(`engorged pussy lips against ${his}`);
			}
			if (slave.butt > 7) {
				r.push(`enormous, gel-slicked ass,`);
			} else if (slave.butt > 4) {
				r.push(`plush, gel-slicked ass,`);
			} else if ((slave.buttImplant / slave.butt) > .60) {
				r.push(`implant-filled, gel-slicked ass,`);
			} else if (slave.butt > 2) {
				r.push(`perfect, gel-slicked ass,`);
			} else {
				r.push(`small, gel-slicked ass,`);
			}
			r.push(`and throw your weight backward to bring you both to the ground. ${He}'s far too enormous to make this achievement doable with anything less than superhuman strength, but the mobility assistance devices engage as you move, and the two of you slowly collapse into the warm jelly.`);
			r.push(VCheck.Vaginal(slave, 1));
			r.push(`After you've fucked ${him} near senseless, enjoying ${his} struggles to keep abreast of the smothering gel as you abuse ${his} pussy, you both retire to the side of the pool and ${he} presses into you, nuzzling your neck and`);
			if (canTalk(slave)) {
				r.push(`asking you what you think of ${his} invention.`);
			} else {
				if (hasAnyArms(slave)) {
					r.push(`motioning to you, asking you what you think of ${his} invention.`);
				} else {
					r.push(`waving a stub in the air. As if on cue, your personal servant asks you what you think of your broodmother's invention.`);
				}
			}
			r.push(followUp());
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function followUp() {
			const div = document.createElement("div");
			const responses = [
				new App.Events.Result(`Insult ${him} and halt all further training.`, halt),
				new App.Events.Result(`Compliment ${him} but keep ${his} discoveries to yourself.`, keep),
			];
			if (V.FCTV.receiver > 0) {
				responses.push(new App.Events.Result(`Organize a televised demonstration of ${his} skills.`, tv, `This will cost ${cashFormat(tvCost)}`));
			}

			App.Events.addResponses(div, responses);
			return div;

			function halt() {
				const frag = new DocumentFragment();
				let r = [];
				r.push(`As much as ${his} antics amused you, it's clear that ${slave.slaveName} wasted your money. You calmly explain to ${him} that the next time ${he} has a "brilliant" idea, ${he} should keep it to ${himself}, then arrange to have ${his} "discoveries" disposed of.`);
				if (slave.trust < -95) {
					r.push(`The look of pride and accomplishment on ${his} face transforms into a look of crushing disappointment. You slap ${him} on the ass and then have your menials escort ${him} back to ${his} duties. The next time you see ${him}, the spark of life and vitality that drove ${him} has been fully extinguished. <span class="mindbreak">${slave.slaveName} has broken.</span> Anything ${he} might have learned from this experience is lost in ${his} empty mind. ${He} will never question ${his} place, or anything else, again.`);
					applyMindbroken(slave);
				} else if (slave.trust < -20) {
					r.push(`The look of pride and accomplishment on ${his} face transforms into a look of crushing disappointment. ${He} apologizes for wasting your time and, cognizant of the power you hold over ${him}, promises never to do so again. <span class="trust dec">${slave.slaveName} is now more fearful.</span> Though ${he} never bothers you with ${his} "ideas" again, you can tell <span class="mediumorchid">${he} no longer regards you as highly.</span>`);
					slave.trust -= 4;
					slave.devotion -= 10;
				} else {
					r.push(`The look of pride and accomplishment on ${his} face transforms into a look of disappointment. <span class="trust dec">${slave.slaveName} finds you less trust worthy</span> as a result of your unkindness, but ${he} soon gets over ${his} disappointment and begins thinking of ways to truly impress you.`);
					slave.trust -= 4;
				}
				App.Events.addParagraph(frag, r);
				return frag;
			}

			function keep() {
				const frag = new DocumentFragment();
				let r = [];
				r.push(`You are impressed by ${his} ideas and arrange to have them implemented in a limited way in your arcology. You also arrange to keep ${his} discoveries secret, so as to hoard all the enjoyment of them for yourself. ${slave.slaveName} doesn't mind. ${He} is <span class="devotion inc">simply happy</span> to have pleased you and <span class="trust inc">trusts your intentions will benefit ${him}.</span>`);
				V.pregInventions = 1;
				slave.trust += 2;
				slave.devotion += 5;
				App.Events.addParagraph(frag, r);
				return frag;
			}

			function tv() {
				const frag = new DocumentFragment();
				let r = [];
				r.push(`You are so impressed by ${his} ideas that you arrange to have ${him} demonstrate ${his} discoveries on a prominent FCTV talk show. It will take some time, and you'll have to insure that ${he}'s at least reasonably well known before the show's executives will agree to allow ${him} on-air, but you're certain that ${slave.slaveName}'s name will soon be on the lips of pregnancy-loving slaveowners and Free Cities citizens around the world. In the meantime, you implement ${his} ideas around the arcology. ${He} is <span class="devotion inc">thrilled</span> to have pleased you so much that you would <span class="trust inc">put such faith in ${his} ideas.</span>`);
				cashX(-tvCost, "event", slave);
				V.pregInventor = 2;
				V.pregInventions = 1;
				slave.trust += 4;
				slave.devotion += 10;
				App.Events.addParagraph(frag, r);
				return frag;
			}
		}
	}
};


code:
App.Events.RERebels = class RERebels extends App.Events.BaseEvent {
	actorPrerequisites() {
		/**
		 * @type {Array<FC.Assignment>}
		 */
		const jobs = [Job.ARCADE];
		if (V.dairyRestraintsSetting >= 2) {
			jobs.push(Job.DAIRY);
		}
		const req = [
			(s) => !jobs.includes(s.assignment),
			(s) => s.devotion < -20,
			canWalk,
			hasAnyArms,
			canTalk,
			canSee,
			canHear
		];
		return [req, req];
	}

	execute(node) {
		const r = [];

		V.nextButton = "Continue";
		V.nextLink = "RIE Eligibility Check";

		const thingOne = getSlave(this.actors[0]);
		const thingTwo = getSlave(this.actors[1]);

		const {
			He,
			he, his, him
		} = getPronouns(thingOne);

		const {
			He2,
			he2, his2, him2,
		} = getPronouns(thingTwo).appendSuffix("2");

		App.Events.drawEventArt(node, [thingOne, thingTwo], "no clothing");

		r.push(
			`You have a rebel problem.`,
			App.UI.DOM.slaveDescriptionDialog(thingOne),
			`and`,
			contextualIntro(thingOne, thingTwo, "DOM"),
			`are both unbroken, and they seem to draw strength from each other. They're discreet about it, but the arcology's always-vigilant systems occasionally catch them nodding to one another after one of them is punished, or giving each other quiet words of encouragement when they think no one is listening. This is extremely dangerous and should be addressed promptly.`
		);

		App.Events.addParagraph(node, r);

		const choices = [];
		choices.push(new App.Events.Result(`Set them against each other, in public`, publicly));
		choices.push(new App.Events.Result(`Set them against each other, in private`, privately));
		if (V.seeExtreme === 1 && thingTwo.vagina > 0 && thingOne.vagina > 0) {
			choices.push(new App.Events.Result(`Let them compete against each other to decide who lives`, deathMatch));
		}
		if (V.arcade > 0) {
			choices.push(new App.Events.Result(`Sentence them to a month in the arcade`, arcade));
		}

		App.Events.addResponses(node, choices);

		function publicly() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You haul your little rebel bitches out in public, one by one, bound, with bags over their heads. They find themselves chained in a low position so their mouths are publicly available. Then, you whisper to each of them that whichever slut sucks off the most passersby gets to rest tomorrow — and whichever sucks least gets a beating. It doesn't take long before they forget their friendship and try to outdo each other, and their desperate efforts are certainly appreciated by the citizens getting free blowjobs. It's childishly easy to declare the contest over when they happen to be tied, and announce that no one will be punished or rewarded. They hate you less and each other more.`);
			for (const thing of [thingOne, thingTwo]) {
				thing.devotion += 4;
				seX(thing, "oral", "public", "penetrative", 6);
				repX(250, "event", thing);
			}

			App.Events.addParagraph(frag, r);
			return frag;
		}

		function privately() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`Back in the old world, the saying went that turnabout was fair play. In the Free Cities, turnabout is often a cast-iron bitch. Whenever you have an idle moment, all week, you set them against one another in some degrading or painful contest. They are made to spank each other, with the slave who hits lightest getting a spanking from you. They are made to compete to see who can suck other slaves off quickest, with the loser forced to orally service the winner. So on, and so on; by the end of the week they forget their friendship and try to outdo each other to avoid punishment.`);
			for (const thing of [thingOne, thingTwo]) {
				thing.trust -= 5;
				seX(thing, "oral", "public", "penetrative", 6);
				repX(250, "event", thing);
			}
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function deathMatch() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You haul your bound little rebel bitches into one of the deepest, most out of the way rooms of your penthouse with bags over their heads. When you pull them off, they are met with the sight of a gallows, complete with a pair of nooses. You haul them, one at a time, up onto a stool and loop the rope around their necks. They scream and beg the whole time for you to reconsider, before turning on each other to try and avoid their fate. It won't be that easy for them. You hold up a pair of spoons and explain the rules of the game. They'll hold them in their pussies, and whoever loses their grip and drops it first, dies.`);
			App.Events.addParagraph(frag, r);
			r = [];
			if (thingOne.vagina > 3) {
				r.push(`You start with ${thingOne.slaveName} and no sooner than you turn to ${thingTwo.slaveName} do you hear the telltale clatter of the spoon hitting the floor. With a simple kick, the unfortunately loose ${thingOne.slaveName} is left struggling in the air. ${thingTwo.slaveName} watches in horror as the life drains from ${his2} former accomplice. ${He2} promises to never cross you again.`);
				thingTwo.trust -= 20;
				removeSlave(thingOne);
			} else if (thingTwo.vagina > 3) {
				r.push(`You start with ${thingOne.slaveName} before moving to ${thingTwo.slaveName} as ${he} holds ${his} life between ${his} netherlips. Setting the spoon inside ${thingTwo.slaveName}, you prepare to kick the stools out from under them; but the telltale clatter of the spoon hitting the floor saves you the trouble. With a simple kick, the unfortunately loose ${thingTwo.slaveName} is left struggling in the air. ${thingOne.slaveName} watches in horror as the life drains from ${his} former accomplice. ${He} promises to never cross you again.`);
				thingOne.trust -= 20;
				removeSlave(thingTwo);
			} else if (random(1, 100) === 69) {
				r.push(`You start with ${thingOne.slaveName} before moving to ${thingTwo.slaveName} as ${he} holds ${his} life between ${his} netherlips. Once both spoons are inserted, you sit back and watch them squirm at the cold metal in their most sensitive recesses. They are both desperate to survive and clamp down as hard as they can, but it can't go on forever as the sounds of a spoon clattering to the floor fills the room. Both slaves freeze as they realize the other has lost their grip on the silverware, uncertain of what comes next. You answer the question by knocking the stools out from under them, allowing them both to hang. They came into this together and they are going out together.`);
				removeSlave(thingOne);
				removeSlave(thingTwo);
			} else if (thingOne.vagina === thingTwo.vagina && random(1, 100) > 50) {
				r.push(`You start with ${thingOne.slaveName} before moving to ${thingTwo.slaveName} as ${he} holds ${his} life between ${his} netherlips. Once both spoons are inserted, you sit back and watch them squirm at the cold metal in their most sensitive recesses. They are both`);
				if (thingOne.vagina === 1) {
					r.push(`quite tight, so it's no surprise when they put up a good show.`);
				} else {
					r.push(`not the tightest slaves, so it's a surprise they manage to hold on as long as they do.`);
				}
				r.push(`But it can't go on forever as the sound of the spoon clattering to the floor fills the room.`);
				if (random(1, 100) <= 50) {
					r.push(kickBucket(thingTwo, thingOne));
				} else {
					r.push(kickBucket(thingOne, thingTwo));
				}
			} else if (thingTwo.vagina > thingOne.vagina && random(1, 100) > 50) {
				r.push(`You start with ${thingOne.slaveName} before moving to ${thingTwo.slaveName} as ${he} holds ${his} life between ${his} netherlips. Once both spoons are inserted, you sit back and watch them squirm at the cold metal in their most sensitive recesses. ${thingOne.slaveName} is the clear favorite in this game, but the looser ${thingTwo.slaveName} refuses to give in, using ${his2} experience to clamp down as hard as ${he2} can. But it can't go on forever as the sound of the spoon clattering to the floor fills the room.`);
				if (random(1, 100) <= 90) {
					r.push(kickBucket(thingTwo, thingOne));
				} else {
					r.push(kickBucket(thingOne, thingTwo));
					if (thingTwo.vagina >= 3) {
						r.push(`You can't say you expected this outcome, but it was amusing all the same to discover the blown out whore has some talent.`);
					} else {
						r.push(`You're glad no bets were riding on this.`);
					}
				}
			} else {
				r.push(`You start with ${thingOne.slaveName} before moving to ${thingTwo.slaveName} as ${he} holds ${his} life between ${his} netherlips. Once both spoons are inserted, you sit back and watch them squirm at the cold metal in their most sensitive recesses. In a show of underhandedness, ${thingTwo.slaveName} kicks ${thingOne.slaveName}, knocking ${him} off balance and sending ${him} hanging. ${thingTwo.slaveName} watches as the life drains from ${his2} accomplice, horrified at what ${he2} just did. The ordeal leaves ${him2} behaving strangely.`);
				thingTwo.trust = -100;
				thingTwo.behavioralFlaw = "odd";
				removeSlave(thingOne);
			}

			App.Events.addParagraph(frag, r);
			return frag;

			/**
			 * @param {App.Entity.SlaveState} dead
			 * @param {App.Entity.SlaveState} survivor
			 * @returns {DocumentFragment}
			 */
			function kickBucket(dead, survivor) {
				const {him} = getPronouns(dead);
				const {his2, him2} = getPronouns(survivor).appendSuffix("2");
				const frag = new DocumentFragment();
				let r = [];
				r.push(`You kick the stool out from under ${dead.slaveName} and let ${him} hang. ${survivor.slaveName} watches in horror as the life drains from ${his2} former accomplice, terrified that you'd so callously toy with their lives. The ordeal leaves ${him2} behaving strangely.`);
				App.Events.addParagraph(frag, r);
				survivor.trust -= -20;
				survivor.behavioralFlaw = "odd";
				removeSlave(dead);
				return frag;
			}
		}

		function arcade() {
			for (const thing of [thingOne, thingTwo]) {
				assignJob(thing, "be confined in the arcade");
				thing.sentence = 4;
			}
			return `They scream and beg when they realize what their punishment is to be, but you are obdurate. Each tries to inform on the other to avoid such a fate, but to no avail. After they're properly confined, the only sign of their discomfiture is a slight movement of their butts as they wriggle desperately against their restraints.`;
		}
	}
};

repo_name: Elohiem/fc

license: mit


code:
App.Events.RERelationshipAdvice = class RERelationshipAdvice extends App.Events.BaseEvent {
	actorPrerequisites() {
		return[[
			(s) => s.fetish !== "mindbroken",
			hasAnyArms,
			canWalk,
			canTalk,
			canSee,
			(s) => s.assignment !== Job.QUARTER,
			(s) => s.relationship >= 2,
			(s) => s.relationship < 5,
			(s) => s.devotion > 20,
			(s) => s.trust >= -20
		]];
	}

	execute(node) {
		const r = [];

		V.nextButton = "Continue";
		V.nextLink = "Next Week";

		const slave = getSlave(this.actors[0]);
		const relSlave = getSlave(slave.relationshipTarget);

		const {
			He,
			he, his, him, himself, girl
		} = getPronouns(slave);
		const {title: Master} = getEnunciation(slave);

		const {
			He2,
			he2, his2, him2, hers2, woman2, wife2, girl2,
		} = getPronouns(relSlave).appendSuffix("2");

		App.Events.drawEventArt(node, [slave, relSlave], "no clothing");

		r.push(
			App.UI.DOM.slaveDescriptionDialog(slave),
			`is standing for an inspection. ${He}'s a good ${girl}, and is cooperating, but ${he} seems preoccupied. After ignoring it for a while, you give in to curiosity and flatly ask ${him} what's going on.`,
			Spoken(slave, `"I'm sorry, ${Master},"`),
			`${he}`
		);
		if (SlaveStatsChecker.checkForLisp(slave)) {
			r.push(`lisps,`);
		} else {
			r.push(`mutters,`);
		}
		r.push(
			`biting ${his} lip.`,
			Spoken(slave, `"It's`),
			App.UI.DOM.combineNodes( // TODO: how the heck would we get them to lisp the name
				App.UI.DOM.slaveDescriptionDialog(relSlave),
				`."`
			),
		);
		r.push(`${He} hesitates, so you prompt ${him}, asking if ${he}'s having trouble with ${his}`);
		if (slave.relationship === 2) {
			r.push(`friend.`);
		} else if (slave.relationship === 3) {
			r.push(`friend with benefits.`);
		} else if (slave.relationship === 4) {
			r.push(`lover.`);
		}
		r.push(
			`${He} quickly shakes ${his} head no.`,
			Spoken(slave, `"N-no, ${Master}, it's just —"`),
			`${He} subsides into silence again, blushing and staring`
		);
		if (!canSee(slave)) {
			r.push(`blankly`);
		}
		r.push(`at ${his} feet. Comprehension dawning, you ask ${him} if`);
		if (slave.relationship === 2) {
			r.push(`${he} wants to be more than friends with ${relSlave.slaveName}.`);
		} else if (slave.relationship === 3) {
			r.push(`${he}'s wanting to bring emotions into relationship with ${relSlave.slaveName}, rather than keep it friendly and sexual.`);
		} else if (slave.relationship === 4) {
			r.push(`${he} wants to make an honest ${woman2} out of ${relSlave.slaveName}.`);
		}
		r.push(`${He} nods ${his} head quickly, still staring`);
		if (!canSee(slave)) {
			r.push(`blankly`);
		}
		r.push(`at ${his} feet. ${He} shuts ${his} eyes tight and waits for you to weigh in on the situation.`);
		App.Events.addParagraph(node, r);

		const choices = [];
		choices.push(new App.Events.Result(`Break them up`, breakUp));
		choices.push(new App.Events.Result(`Build ${his} confidence`, confidence));
		choices.push(new App.Events.Result(`Bring the other ${girl2} in`, bringIn));
		App.Events.addResponses(node, choices);

		function breakUp() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`In a cold tone of voice, you admit your irritation with this school ${girl} nonsense, and tell ${him} ${he}'s to stop spending time with ${relSlave.slaveName}. ${He}'s unable to prevent ${his} eyes from flicking up at you in shock and horror, but ${he} instantly lowers them again, the tears coming fast. You dismiss ${him}, and ${he} turns to go, but is so discombobulated by anguish that ${he} trips over ${his} own feet and falls with a slap of naked ${slave.skin} flesh against the floor. Their relationship is over.`);

			slave.devotion -= 5;
			slave.relationship = 0;
			slave.relationshipTarget = 0;
			relSlave.relationship = 0;
			relSlave.relationshipTarget = 0;

			App.Events.addParagraph(frag, r);
			return frag;
		}

		function confidence() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`In a warm tone of voice, you tell ${him} you approve of ${his} relationship with ${relSlave.slaveName}. ${He} raises ${his} chin and looks at you with growing adoration as you point out how lucky ${relSlave.slaveName} is to have ${him}. You tell ${him} that you're not planning to intervene personally, but that you think ${he} really ought to pursue the relationship, that they're good for each other, and that you're confident ${relSlave.slaveName} feels the same way. ${He} thanks you prettily and leaves at a flat run, in a hurry to tell ${his}`);
			if (slave.relationship === 2) {
				r.push(`sexy friend`);
			} else if (slave.relationship === 3) {
				r.push(`friend with benefits`);
			} else if (slave.relationship === 4) {
				r.push(`dear lover`);
			}
			r.push(`how ${he} feels about ${him2}.`);
			if (slave.relationship === 2) {
				r.push(`The next time you see them together, they're looking like they've been getting a little less sleep lately, but can't seem to keep their hands off each other. ${slave.slaveName} mouths a silent thanks to you when ${relSlave.slaveName} isn't looking.`);
			} else if (slave.relationship === 3) {
				r.push(`The next time you see them together, they're holding hands at breakfast, looking almost ashamed of themselves, but not letting go. ${slave.slaveName} mouths a silent thanks to you when ${relSlave.slaveName} isn't looking.`);
			} else if (slave.relationship === 4) {
				r.push(`${He} comes running right back, a happy ${relSlave.slaveName}`);
				if (canWalk(relSlave)) {
					r.push(`running in with ${him}.`);
				} else {
					r.push(`being helped in by ${his2} lover.`);
				}
				r.push(`You marry them solemnly, and they embrace tightly, hugging each other close. ${slave.slaveName} comes to face you over ${his} ${wife2}'s shoulder, and ${he} mouths a silent, tearful thanks to you.`);
			}

			slave.devotion += 5;
			slave.relationship += 1;
			relSlave.relationship += 1;

			App.Events.addParagraph(frag, r);
			return frag;
		}

		function bringIn() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You tell ${slave.slaveName} to wait, and page ${relSlave.slaveName} up to your office. ${slave.slaveName} looks terrified, but tries to conceal ${his} emotions behind a happy greeting for ${his}`);
			if (slave.relationship === 2) {
				r.push(`friend`);
			} else if (slave.relationship === 3) {
				r.push(`friend with benefits`);
			} else if (slave.relationship === 4) {
				r.push(`lover`);
			}
			r.push(
				`when ${he2} comes in. ${relSlave.slaveName} knows ${him} well enough to detect ${his} inner turmoil, and asks ${him} what's wrong. ${slave.slaveName} flinches and looks to you in desperation, but you just nod at ${him} to spit it out. After two false starts, ${he} manages to say,`,
				Spoken(slave, `"${relSlave.slaveName}, I really want`)
			);

			if (slave.relationship === 2) {
				if (slave.fetish === "buttslut") {
					r.push(
						Spoken(slave, `to fuck your butt."`),
						`${relSlave.slaveName} looks relieved that that's all it is, and ${agrees()}`,
					);
					r.push(`${He2} kisses ${slave.slaveName} and then grinds ${his2} ass against ${slave.slaveName}'s crotch.`);
				} else if (slave.fetish === "cumslut") {
					if (relSlave.dick === 0) {
						r.push(`to eat you out."`);
					} else {
						r.push(`to blow you."`);
					}
					r.push(`${relSlave.slaveName} looks relieved that that's all it is, and ${agrees()} ${He2}`);
					if (relSlave.dick === 0) {
						r.push(`offers ${his2} pussy`);
					} else {
						r.push(`flops ${his2} dick at ${slave.slaveName}`);
					}
					r.push(`comically.`);
				} else if (slave.fetish === "humiliation") {
					r.push(
						Spoken(slave, `to fuck you in public."`),
						` ${relSlave.slaveName} looks relieved that that's all it is, and ${agrees()}`
					);
				} else if (slave.fetish === "masochist") {
					r.push(
						Spoken(slave, `you to hurt me. Like, really hurt me."`),
						` ${relSlave.slaveName} looks relieved that that's all it is, and ${agrees()} ${He2} pinches one of ${slave.slaveName}'s nipples experimentally.`
					);
				} else if (slave.fetish === "sadist") {
					r.push(
						Spoken(slave, `to hold you down."`),
						` ${relSlave.slaveName} looks relieved that that's all it is, and ${agrees()} ${He2} ${canWalk(relSlave) ? "steps in close" : "wiggles closer"} to ${slave.slaveName},`
					);
					if (hasAnyArms(relSlave)) {
						r.push(`takes ${slave.slaveName}'s ${hasBothArms(slave) ? "hands, and places them" : "hand, and places it"} around ${his2} own throat.`);
					} else {
						r.push(`and sticks out ${his2} neck for ${slave.slaveName}`);
					}
				} else if (slave.fetish === "dom") {
					r.push(
						Spoken(slave, `to be your top."`),
						` ${relSlave.slaveName} looks relieved that that's all it is, and ${agrees()} ${He2} sidles up to ${slave.slaveName}, looking up at ${him} submissively.`
					);
				} else if (slave.fetish === "submissive") {
					r.push(
						Spoken(slave, `to be your bottom."`),
						` ${relSlave.slaveName} looks relieved that that's all it is, and says, ${agrees()} `
					);
					if (hasAnyArms(relSlave)) {
						r.push(`${He2} takes ${slave.slaveName}'s face in ${his2} ${hasBothArms(relSlave) ? "hands" : "hand"}`);
					} else {
						r.push(`${He2} leans in`);
					}
					r.push(`and kisses ${him} dominantly.`);
				} else if (slave.fetish === "boobs") {
					r.push(
						Spoken(slave, `to fuck your boobs."`),
						`${relSlave.slaveName} looks relieved that that's all it is, and says, ${agrees()}`
					);
					if (hasAnyArms(relSlave)) {
						r.push(`${He2} takes ${slave.slaveName}'s`);
						if (hasBothArms(slave)) {
							r.push(`hands and places them`);
						} else {
							r.push(`hand and places it`);
						}
						r.push(`right on ${his2} breasts.`);
					} else {
						r.push(`${He2} sticks out ${his2} breasts for ${slave.slaveName} and is not disappointed.`);
					}
				} else {
					r.push(
						Spoken(slave, `to fuck you."`),
						` ${relSlave.slaveName} looks relieved that that's all it is, and ${agrees()}`
					);
					if (hasAnyArms(relSlave)) {
						r.push(`${He2} takes ${slave.slaveName}'s`);
						if (hasBothArms(slave)) {
							r.push(`hands and places them`);
						} else {
							r.push(`hand and places it`);
						}
						r.push(`right on ${his2} breasts.`);
					} else {
						r.push(`${He2} sticks out ${his2} breasts for ${slave.slaveName} and is not disappointed.`);
					}
				}
				r.push(`${slave.slaveName} bursts out laughing. They're now <span class="relationship">friends with benefits.</span>`);
			} else if (slave.relationship === 3) {
				r.push(
					Spoken(slave, `t-to b-be your ${girl} friend."`),
					`${He} takes a deep breath.`,
					Spoken(slave, `"It's fun, just`)
				);
				if (slave.fetish === "buttslut") {
					r.push(`fucking your butt.`);
				} else if (slave.fetish === "cumslut") {
					if (relSlave.dick === 0) {
						r.push(`eating you out.`);
					} else {
						r.push(`blowing you.`);
					}
				} else if (slave.fetish === "humiliation") {
					r.push(`fucking you in public.`);
				} else if (slave.fetish === "masochist") {
					r.push(`having you hurt me.`);
				} else if (slave.fetish === "sadist") {
					r.push(`holding you down.`);
				} else if (slave.fetish === "dom") {
					r.push(`topping you.`);
				} else if (slave.fetish === "submissive") {
					r.push(`being your bottom.`);
				} else if (slave.fetish === "boobs") {
					r.push(`fucking your boobs.`);
				} else {
					r.push(`having sex with you.`);
				}
				r.push(
					Spoken(slave, `But I — I really like you."`),
					` ${relSlave.slaveName} looks relieved, and`
				);
				if (relSlave.voice !== 0) {
					r.push(
						`says,`,
						Spoken(slave, `"I really like you too. And you're really cute! I'd love to be your ${girl2} friend."`),
						`${He2}`
					);
				} else {
					r.push(`lovingly`);
				}
				if (hasAnyArms(relSlave)) {
					r.push(`takes ${slave.slaveName}'s hands in ${hers2}, and then`);
				}
				r.push(`kisses ${him} on the cheek. ${slave.slaveName} crushes ${relSlave.slaveName} in a hug, pressing a squeak out of ${him2}. They're now <span class="relationship">lovers.</span>`);
			} else if (slave.relationship === 4) {
				r.push(
					`- " ${He} stops ${himself}.`,
					Spoken(slave, `"No, I want to do this right."`)
				);
				if (hasAnyArms(relSlave)) {
					r.push(`${He} takes ${relSlave.slaveName}'s hand, and then drops to one knee.`);
				} else {
					r.push(`${He} drops to one knee, holding out ${his} hand to ${relSlave.slaveName}.`);
				}
				r.push(`After a moment of uncomprehending shock, ${relSlave.slaveName} begins to cry.`,
					Spoken(slave, `"Will you marry me?"`),
					`${relSlave.slaveName} turns to you and`
				);
				if (!canTalk(relSlave)) {
					r.push(`wordlessly`);
				}
				r.push(`asks if it's all right with you; you ${canSee(relSlave) ? "nod" : "affirm"}, and ${he2} turns back to ${slave.slaveName}.`);
				if (!canTalk(relSlave)) {
					r.push(`${He2} gestures distractedly that ${slave.slaveName} is being silly, and of course ${he2}'ll marry ${him}, because ${he2} loves ${him}.`);
				} else {
					r.push(Spoken(slave, `"O-of course I'll m-marry you, silly ${girl}. I love you."`));
				}
				r.push(`${slave.slaveName} jumps up and crushes ${relSlave.slaveName} in a hug, kissing ${him2} frantically through ${his} tears. You marry them solemnly, and they embrace tightly, hugging each other close. ${slave.slaveName} comes to face you over ${his} ${wife2}'s shoulder, and ${he} mouths a silent thanks to you.`);
			}
			r.push(`If ${slave.slaveName} had doubts about you, <span class="trust inc">they've been addressed.</span>`);

			slave.trust += 10;
			slave.relationship += 1;
			relSlave.relationship += 1;

			App.Events.addParagraph(frag, r);
			return frag;

			function agrees() {
				const r = [];
				if (relSlave.voice !== 0) {
					r.push(
						`says,`,
						Spoken(relSlave, `"Okay!"`)
					);
				} else {
					r.push(`nods.`);
				}
				return r.join(" ");
			}
		}
	}
};


code:
App.Events.RERelativeRecruiter = class RERelativeRecruiter extends App.Events.BaseEvent {
	eventPrerequisites() {
		return []; // always valid if sufficient actors can be cast successfully
	}

	actorPrerequisites() {
		return [
			[ // first actor - recruiter
				s => s.fetish !== "mindbroken",
				s => s.fuckdoll === 0,
				s => s.devotion > 50,
				s => s.canRecruit === 1,
				s => totalRelatives(s) === 0 || V.limitFamilies !== 1,
				s => this._chooseTargetRelative(s)
			]
		];
	}

	/** pick a target relative and store it in the event parameters
	 * @param {App.Entity.SlaveState} slave who's doing the recruiting (should be first actor)
	 * @returns {boolean} success or failure
	 */
	_chooseTargetRelative(slave) {
		// make sure the slave has a genepool entry (everyone should)
		const gp = V.genePool.find(s => s.ID === slave.ID);
		if (!gp) {
			console.log(`Slave with ID ${slave.ID} is missing their genepool entry.`);
			slave.canRecruit = 0;
			return false;
		}
		const choices = this._getTargetRelativeChoices(slave, gp);
		if (choices.length === 0) {
			slave.canRecruit = 0; // slave has exhausted possible relatives, can't recruit any longer
			return false;
		}
		this.params.relative = choices.random();
		return true;
	}

	/** find all eligible target relatives for a slave; one will be selected randomly (or by cheating)
	 * @param {App.Entity.SlaveState} slave who's doing the recruiting (should be first actor)
	 * @param {App.Entity.SlaveState} [gp] genepool entry for this slave, if known
	 * @returns {string[]}
	 */
	_getTargetRelativeChoices(slave, gp) {
		let recruit = [];
		if (!gp) {
			gp = V.genePool.find(s => s.ID === slave.ID);
		}

		const pushWeight = (value, weight=1) => recruit.push(...Array(weight).fill(value));

		if (slave.mother === 0 && V.seeDicks !== 100) {
			const momAge = getParentAgeRange(slave, false);
			if (momAge.max >= momAge.min) {
				pushWeight("mother", 3);
			}
		}
		if (slave.father === 0 && V.seeDicks !== 0) {
			const dadAge = getParentAgeRange(slave, true);
			if (dadAge.max >= dadAge.min) {
				pushWeight("father");
			}
		}

		// TODO: age should probably be checking genepool, not current state, since the child would have been born before the event slave was in your possession
		if (slave.daughters < 3 && (slave.actualAge > V.minimumSlaveAge + V.fertilityAge) && isFertile(gp) && slave.trueVirgin !== 1) {
			if (V.seeDicks !== 100) {
				pushWeight("daughter", 2);
			}
			if (V.seeDicks !== 0) {
				pushWeight("son");
			}
		} else if (slave.daughters < 3 && (slave.actualAge > V.minimumSlaveAge + V.potencyAge) && gp.balls > 0) {
			if (V.seeDicks !== 100) {
				pushWeight("daughter", 2);
			}
			if (V.seeDicks !== 0) {
				pushWeight("son");
			}
		}

		if (slave.sisters < 3) {
			if (slave.actualAge < V.retirementAge - 2) {
				if (V.seeDicks !== 100) {
					pushWeight("older sister", 2);
				}
				if (V.seeDicks !== 0) {
					pushWeight("older brother", 2);
				}
			}
			if (slave.actualAge > V.minimumSlaveAge + 1) {
				if (V.seeDicks !== 100) {
					pushWeight("younger sister", 2);
				}
				if (V.seeDicks !== 0) {
					pushWeight("younger brother", 2);
				}
			}
			pushWeight("twin");
		}

		return recruit;
	}

	/** returns a description for a given background
	 * @param {App.Entity.SlaveState} slave (relative)
	 * @param {string} background
	 * @returns {string} description
	 */
	_getBackgroundDescription(slave, background) {
		const {His, he, his} = getPronouns(slave);
		const backgroundDescriptions = {
			"prostitute": `${he} was used as a prostitute by ${his} previous owner`,
			"shemale prostitute": `${he} was used as a shemale prostitute by ${his} previous owner`,
			"bed MILF": `${he} was used as a bed slave by ${his} MILF-loving owner`,
			"gelded servant": `${he} was gelded and used as a house servant`,
			"sex toy": `${he} was kept as a personal sex toy by ${his} previous owner`,
			"flat toy": `${he} was kept as a bedslave by an owner that loves flat chests`,
			"bimbo toy": `${he} was kept as a personal toy by ${his} bimbo-loving owner`,
		};
		if (backgroundDescriptions[background]) {
			return `${His} listing states that ${backgroundDescriptions[background]}.`;
		}
		return ``; // twin, for example, has no specific background
	}

	/** returns the possible backgrounds for a given relative type; one will be selected randomly (or by cheating)
	 * Currently super simple (returns exactly one element) to emulate the old twine event, but may easily be expanded if more backgrounds are written
	 * @param {string} relative
	 * @returns {string[]}
	 */
	_getRelativeBackgrounds(relative) {
		let bgs = [];
		const pushWeight = (value, weight=1) => bgs.push(...Array(weight).fill(value));

		if (relative === "daughter") {
			pushWeight("prostitute");
		} else if (relative === "son") {
			pushWeight("shemale prostitute");
		} else if (relative === "mother") {
			pushWeight("bed MILF");
		} else if (relative === "father") {
			pushWeight("gelded servant");
		} else if (relative === "older sister" || relative === "older brother") {
			pushWeight("sex toy");
		} else if (relative === "younger sister") {
			pushWeight("flat toy");
		} else if (relative === "younger brother") {
			pushWeight("bimbo toy");
		} else if (relative === "twin") {
			pushWeight("twin");
		}
		return bgs;
	}

	execute(node) {
		const [eventSlave] = this.actors.map(a => getSlave(a));
		const {He, he, his} = getPronouns(eventSlave);
		let newSlave;

		V.nextLink = "RIE Eligibility Check";

		let artDiv = document.createElement("div"); // named container so we can replace it later
		App.Events.drawEventArt(artDiv, eventSlave);
		node.appendChild(artDiv);

		// re-choose the relative (a valid one was assigned during her casting, but the last slave to go through casting might not have been the one selected)
		this._chooseTargetRelative(eventSlave);
		// pick a random background for the selected relative
		this.params.background = this._getRelativeBackgrounds(this.params.relative).random();

		let that = this; // fuck javascript's half-assed classes
		let cost = 0; // will be filled out later

		let cheatDiv = App.UI.DOM.makeElement("div", (V.debugMode > 0 && V.debugModeEventSelection > 0) ? cheatModeSelectors() : '');
		node.appendChild(cheatDiv);

		let eventTextDiv = App.UI.DOM.makeElement("div", eventText());
		node.appendChild(eventTextDiv);

		/** produce the event text and response links. might be regenerated by changing slave selection in cheat mode
		 * @returns {DocumentFragment}
		 */
		function eventText() {
			let frag = document.createDocumentFragment();

			newSlave = makeSlave();
			cost = slaveCost(newSlave);
			const {He: He2, him: him2, his: his2, he: he2, daughter: daughter2, sister: sister2} = getPronouns(newSlave);

			const {title: Master} = getEnunciation(eventSlave);

			let t = [];
			t.push(App.UI.DOM.slaveDescriptionDialog(eventSlave));
			t.push(`requests an interview with you. ${He}'s a devoted slave, and you grant it, and are happy you did when you see the troubled expression on ${his} face. ${He} explains`);
			if (!canTalk(eventSlave)) {
				t.push("with desperate gestures");
			}
			t.push(`that`);
			switch (that.params.relative) {
				case "daughter":
				case "son":
					t.push(`${he} had a ${daughter2}, who was sent to the slave orphanages. ${He}'s heard a rumor through other slaves that ${his} ${daughter2} will go up for sale soon.`);
					break;
				case "mother":
				case "father":
					t.push(`${his} ${that.params.relative} might be getting sold soon. ${He2} has been a slave for some time. ${He}'s heard a rumor through other slaves that ${his} ${that.params.relative} will go up for sale soon.`);
					break;
				case "older sister":
				case "older brother":
					t.push(`${his} older ${sister2} is being sold. ${He2} was likely to be enslaved the last ${eventSlave.slaveName} knew of ${him2}, and now ${he}'s heard a rumor through other slaves that ${his} big ${sister2} is going to be sold to a new owner.`);
					break;
				case "younger sister":
				case "younger brother":
					t.push(`${his} younger ${sister2} is being sold. ${He2} was likely to be enslaved the last ${eventSlave.slaveName} knew of ${him2}, and now ${he}'s heard a rumor through other slaves that ${his} little ${sister2} is going to be sold to a new owner.`);
					break;
				case "twin":
					t.push(`${he} has a twin ${sister2}, who was still free the last ${eventSlave.slaveName} knew of ${him2}. ${He}'s heard a rumor through other slaves that ${his} twin has finally been enslaved, and will soon go up for sale.`);
					break;
				default:
					throw Error(`Unknown relative type: ${that.params.relative}`);
			}

			if (!canTalk(eventSlave)) {
				t.push(`${He} urgently gestures for permission to write. It's unusual, but ${he} seems quite serious, so you grant it. ${He} writes,`);
			}
			t.push(Spoken(eventSlave, `"You've been so good to me, ${Master}. I'm sure ${he2} looks like I did when you bought me. Please, ${Master}, will you buy ${newSlave.slaveName} like you bought me? I'm afraid ${he2}'ll go to a cruel master."`));
			t.push(`${He} bites ${his} lip.`);
			t.push(Spoken(eventSlave, `"And, ${Master}, I'm sure ${he2}'d learn to love`));

			if (eventSlave.fetish === "cumslut") {
				t.push(Spoken(eventSlave, `the taste of your cum`));
			} else if (eventSlave.fetish === "submissive") {
				t.push(Spoken(eventSlave, `submission`));
			} else if (eventSlave.fetish === "humiliation") {
				t.push(Spoken(eventSlave, `being treated like a dirty slut`));
			} else if (eventSlave.fetish === "buttslut") {
				t.push(Spoken(eventSlave, `the feeling of your cock in ${his2} butt`));
			} else if (eventSlave.fetish === "sadist") {
				t.push(Spoken(eventSlave, `hurting your other slaves`));
			} else if (eventSlave.fetish === "pregnancy" && newSlave.genes !== "XY") {
				t.push(Spoken(eventSlave, `being pregnant`));
			} else if (eventSlave.fetish === "masochist") {
				t.push(Spoken(eventSlave, `being beaten`));
			} else if (eventSlave.fetish === "dom") {
				t.push(Spoken(eventSlave, `fucking your other slaves`));
			} else if (eventSlave.energy > 95) {
				t.push(Spoken(eventSlave, `being a good nympho slut`));
			} else if (eventSlave.addict > 2) {
				t.push(Spoken(eventSlave, `being a druggie whore`));
			} else if (eventSlave.counter.birthsTotal > 3 && newSlave.genes !== "XY") {
				t.push(Spoken(eventSlave, `bearing children`));
			} else if (eventSlave.bellyPreg >= 50 && eventSlave.pregKnown === 1 && newSlave.genes !== "XY") {
				t.push(Spoken(eventSlave, `swelling with life`));
			} else if (eventSlave.anus > 2) {
				t.push(Spoken(eventSlave, `getting ${his2} butt stretched out`));
			} else if (eventSlave.boobsImplant > 500) {
				t.push(Spoken(eventSlave, `getting turned into a bimbo slut`));
			} else if (V.PC.dick > 0 ) {
				t.push(Spoken(eventSlave, `the feeling of your cock in ${him2}`));
			} else {
				t.push(Spoken(eventSlave, `the taste of your pussy`));
			}
			t.push(Spoken(eventSlave, `as much as I do.`));

			if (eventSlave.fetish === "cumslut") {
				t.push(Spoken(eventSlave, `We could blow you at the same time, ${Master}! And share cum!"`));
			} else if (eventSlave.fetish === "submissive") {
				t.push(Spoken(eventSlave, `You could use us together, ${Master}!"`));
			} else if (eventSlave.fetish === "humiliation") {
				t.push(Spoken(eventSlave, `You could make us fuck each other in public, ${Master}!"`));
			} else if (eventSlave.fetish === "buttslut") {
				t.push(Spoken(eventSlave, `You could fuck our butts right next to each other, ${Master}!"`));
			} else if (eventSlave.fetish === "pregnancy" && newSlave.genes !== "XY") {
				t.push(Spoken(eventSlave, `You could knock us up next to each other, ${Master}!"`));
			} else if (eventSlave.fetish === "sadist") {
				t.push(Spoken(eventSlave, `I'm sure ${he2}'d love to help me, ${Master}!"`));
			} else if (eventSlave.fetish === "masochist") {
				t.push(Spoken(eventSlave, `You could whip us both, ${Master}!"`));
			} else if (eventSlave.fetish === "dom") {
				t.push(Spoken(eventSlave, `I'm sure ${he2}'d love to help me use other slaves, ${Master}!"`));
			} else if (eventSlave.energy > 95) {
				t.push(Spoken(eventSlave, `I'm sure ${he2}'d love to have threesomes, ${Master}!"`));
			} else if (eventSlave.counter.birthsTotal > 3 && newSlave.genes !== "XY") {
				if (V.PC.dick !== 0) {
					t.push(Spoken(eventSlave, `We could compete over who carried more of your children, ${Master}!"`));
				} else {
					t.push(Spoken(eventSlave, `We could compete over who carried more children for you, ${Master}!"`));
				}
			} else if (eventSlave.bellyPreg >= 50 && eventSlave.pregKnown === 1 && newSlave.genes !== "XY") {
				t.push(Spoken(eventSlave, `You could compare how big our bellies are next to each other, ${Master}!"`));
			} else {
				t.push(Spoken(eventSlave, `You could fuck us together, ${Master}!"`));
			}

			t.push(`${He} waits anxiously for your decision.`);
			App.Events.addParagraph(frag, t);

			t = [];
			t.push(`You look up the ${that.params.relative}. ${He2} costs ${cashFormat(cost)}, a bargain, but you won't be able to inspect ${him2} beyond ${his2} likely resemblance to ${eventSlave.slaveName}.`);
			t.push(that._getBackgroundDescription(newSlave, that.params.background));
			App.Events.addParagraph(frag, t);

			App.Events.addResponses(frag, [
				new App.Events.Result(`Buy ${him2}`, buySlave),
			]);

			return frag;
		}

		/** fill in the relationship/background selectors for cheat mode
		 * @returns {DocumentFragment}
		 */
		function cheatModeSelectors() {
			const refreshCallback = (effect) => { effect(); $(cheatDiv).empty().append(cheatModeSelectors); $(eventTextDiv).empty().append(eventText); };

			let relativeTypeLinks = _.uniq(that._getTargetRelativeChoices(getSlave(that.actors[0]))).map((choice) =>
				App.UI.DOM.link(choice, refreshCallback, [() => { that.params.relative = choice; that.params.background = that._getRelativeBackgrounds(choice).random(); }])
			);
			let backgroundTypeLinks = _.uniq(that._getRelativeBackgrounds(that.params.relative)).map((choice) =>
				App.UI.DOM.link(choice, refreshCallback, [() => { that.params.background = choice; }])
			);

			let frag = document.createDocumentFragment();
			$(frag).append(
				`Relative Type: <strong>${that.params.relative}</strong> `, App.UI.DOM.generateLinksStrip(relativeTypeLinks),
				"<br>",
				`Background: <strong>${that.params.background}</strong> `, App.UI.DOM.generateLinksStrip(backgroundTypeLinks)
			);
			return frag;
		}

		/** make the target relative slave
		 * @returns {App.Entity.SlaveState}
		 */
		function makeSlave() {
			/** @param {App.Entity.SlaveState} slave */
			function clearMods(slave) {
				slave.ageImplant = 0;
				slave.boobsImplant = 0;
				slave.boobsImplantType = "none";
				slave.buttImplant = 0;
				slave.buttImplantType = "none";
				if (slave.race !== "catgirl") {
					slave.earImplant = 0;
				}
				slave.faceImplant = 0;
				slave.hipsImplant = 0;
				slave.lipsImplant = 0;
				slave.shouldersImplant = 0;
				slave.voiceImplant = 0;
				slave.areolaePiercing = 0;
				slave.anusPiercing = 0;
				slave.clitPiercing = 0;
				slave.corsetPiercing = 0;
				slave.dickPiercing = 0;
				slave.earPiercing = 0;
				slave.eyebrowPiercing = 0;
				slave.lipsPiercing = 0;
				slave.navelPiercing = 0;
				slave.nipplesPiercing = 0;
				slave.nosePiercing = 0;
				slave.tonguePiercing = 0;
				slave.vaginaPiercing = 0;
				slave.anusTat = 0;
				slave.armsTat = 0;
				slave.backTat = 0;
				slave.bellyTat = 0;
				slave.boobsTat = 0;
				slave.buttTat = 0;
				slave.dickTat = 0;
				slave.lipsTat = 0;
				slave.legsTat = 0;
				slave.shouldersTat = 0;
				slave.stampTat = 0;
				slave.vaginaTat = 0;
				if (slave.nipples === "fuckable") {
					slave.nipples = either("cute", "inverted", "partially inverted", "puffy");
				}
			}

			function relativeOrigin() {
				switch (that.params.relative) {
					case "mother":
					case "father":
						return "$He was recruited into your service by $his child.";
					case "son":
					case "daughter":
						return "$He was recruited into your service by $his parent.";
					case "younger brother":
					case "younger sister":
						return "$He was recruited into your service by $his older sibling.";
					case "older brother":
					case "older sister":
						return "$He was recruited into your service by $his younger sibling.";
					case "twin":
						return "$He was recruited into your service by $his twin.";
				}
				throw Error(`Unknown relative type: ${that.params.relative}`);
			}

			/** @param {App.Entity.SlaveState} slave */
			function applyBackground(slave) {
				function applyProstitute() { // assumes XX
					slave.boobsImplant = 600;
					slave.boobsImplantType = "normal";
					slave.boobs += slave.boobsImplant;
					slave.boobShape = "normal";
					slave.skill.oral += random(30, 50);
					slave.skill.vaginal += random(30, 50);
					slave.skill.anal += random(30, 50);
					slave.skill.entertainment += random(0, 20);
					slave.skill.whoring += random(30, 50);
					slave.nipplesPiercing = 1;
					slave.lipsPiercing = 1;
					slave.tonguePiercing = 1;
					slave.vaginaPiercing = 1;
					slave.earPiercing = 1;
					slave.makeup = 1;
					slave.nails = 4;
					slave.hStyle = either("luxurious", "neat", "tails", "up");
					slave.stampTat = "advertisements";
				}

				function applyShemaleWhore() { // assumes XY
					slave.vagina = random(1, 2);
					slave.boobsImplant = 600;
					slave.boobsImplantType = "normal";
					slave.boobs += slave.boobsImplant;
					slave.boobShape = "normal";
					slave.skill.oral += random(30, 50);
					slave.skill.vaginal += random(30, 50);
					slave.skill.anal += random(30, 50);
					slave.skill.entertainment += random(0, 20);
					slave.skill.whoring += random(30, 50);
					slave.lips = random(60, 90);
					slave.lipsImplant = 40;
					slave.lipsPiercing = 1;
					slave.tonguePiercing = 1;
					slave.vaginaPiercing = 1;
					slave.earPiercing = 1;
					slave.makeup = 1;
					slave.nails = 4;
					slave.hStyle = "tails";
					slave.stampTat = "advertisements";
				}

				function applyBedMILF() { // assumes XX
					slave.anus = 1;
					slave.vagina = 3;
					if (V.seePreg !== 0) {
						slave.preg = random(5, 39);
						slave.pregType = 1;
						slave.pregKnown = 1;
						slave.pregSource = 0;
						slave.pregWeek = slave.preg;
						SetBellySize(slave);
					}
					slave.weight = random(30, 135);
					slave.muscles = random(0, 15);
					slave.skill.oral = 15;
					slave.skill.vaginal = 30;
					slave.skill.anal = 15;
					slave.skill.entertainment = 10;
					slave.skill.whoring = 10;
					slave.boobs = (random(12, 20)*100);
					slave.butt = random(4, 6);
					slave.boobShape = "saggy";
					slave.lactation = 1;
					slave.lactationDuration = 2;
					slave.markings = "birthmark";
					slave.hLength = random(50, 100);
					slave.hStyle = either("bun", "luxurious", "neat", "up");
					slave.voice = 2;
					slave.counter.birthsTotal = 5;
					slave.bellySag = 4;
					slave.bellySagPreg = 4;
					slave.energy = 65;
					slave.bellyTat = "a heart";
				}

				function applyGeldedServant() { // assumes XY
					slave.anus = 2;
					slave.weight = random(70, 180);
					slave.skill.oral = 35;
					slave.skill.anal = 75;
					slave.hLength = random(10, 20);
					slave.hStyle = either("buzzcut", "neat", "trimmed");
					slave.voice = 1;
					slave.energy = 0;
					slave.balls = 0;
				}

				function applySexToy() { // either sex
					slave.tonguePiercing = 1;
					slave.makeup = 1;
					if (slave.balls < 4 && slave.balls > 0) {
						slave.balls = 4;
						slave.scrotum = slave.balls;
					}
					if (slave.dick < 5 && slave.dick > 0) {
						slave.dick = 5;
						slave.foreskin = slave.dick;
					}
					if (slave.vagina > -1) {
						slave.vagina = 2;
					}
				}

				function applyFlatToy() { // either sex
					slave.boobs = Math.min(slave.boobs, (random(1, 4)*100));
					slave.butt = random(1, 2);
					slave.hips = random(-2, 0);
					slave.shoulders = random(-2, 0);
					slave.skill.entertainment += random(0, 20);
					if (slave.vagina > -1) {
						slave.anus = 0;
						slave.vagina = 1;
					} else {
						slave.anus = 1;
					}
				}

				function applyBimboToy() { // either sex
					slave.boobsImplant = (random(20, 40)*100);
					slave.boobsImplantType = "string";
					slave.boobs += slave.boobsImplant;
					if (slave.boobsImplant / slave.boobs >= 0.90) {
						slave.boobShape = "spherical";
						slave.nipples = "flat";
					} else {
						slave.boobShape = "normal";
					}
					slave.buttImplant = random(5, 7);
					slave.buttImplantType = "string";
					slave.butt += slave.buttImplant;
					slave.lipsImplant = random(60, 80);
					slave.lips = Math.clamp(slave.lips + slave.lipsImplant, 0, 100);
					slave.nipplesPiercing = 2;
					if (slave.vagina > -1) {
						slave.vagina = 3;
					}
					slave.anus = 3;
					slave.makeup = 3;
					slave.nails = 5;
					slave.skill.anal = 70;
					slave.skill.oral = 70;
					slave.skill.whoring = 100;
					slave.energy = 100;
					slave.skill.entertainment += random(0, 20);
				}

				function applyTwin() {
					// no changes for this case
				}

				const backgroundDispatch = {
					"prostitute": applyProstitute,
					"shemale prostitute": applyShemaleWhore,
					"bed MILF": applyBedMILF,
					"gelded servant": applyGeldedServant,
					"sex toy": applySexToy,
					"flat toy": applyFlatToy,
					"bimbo toy": applyBimboToy,
					"twin": applyTwin
				};
				backgroundDispatch[that.params.background]();
			}

			/** @param {App.Entity.SlaveState} slave */
			function applyCommon(slave) {
				slave.devotion = random(25, 45);
				slave.trust = random(-15, 15);
				slave.oldDevotion = slave.devotion;
				slave.oldTrust = slave.trust;
				configureLimbs(slave, "all", 1, true);
				slave.career = "a slave";
				setHealth(slave, jsRandom(20, 40));
				slave.skill.combat = 0;
				slave.addict = 0;
				slave.chem = 0;
				slave.weekAcquired = V.week;
				randomizeAttraction(slave); // already randomized by generateRelatedSlave, but energy might have changed, so do it again
			}

			/** @param {App.Entity.SlaveState} slave - record cloned from genepool */
			function updateGPRecordAgeFromEventSlave(slave) {
				// recruitable slave is carrying cloned age data from the original recruitment (since genepool records don't age)
				// we need to update the age based on the "live" copy of the event slave, otherwise we won't get age gaps right
				const elapsedSinceRecruitment = eventSlave.actualAge - slave.actualAge;
				for (let i = 0; i < elapsedSinceRecruitment; ++i) {
					ageSlave(slave);
				}

				// copy updated birthweek (really "weeks until birthday") too, so birthdays and twins work right
				slave.birthWeek = eventSlave.birthWeek;
			}

			const origSlave = BaseSlave();
			const genepoolRec = V.genePool.find(s => s.ID === that.actors[0]);
			App.Entity.Utils.GenePoolRecordCleanup(genepoolRec);
			Object.assign(origSlave, genepoolRec);
			updateGPRecordAgeFromEventSlave(origSlave);

			const newSlave = generateRelatedSlave(origSlave, that.params.relative);
			clearMods(newSlave);
			newSlave.origin = relativeOrigin();
			applyBackground(newSlave);
			if (that.params.relative === "mother") {
				newSlave.counter.birthsTotal += V.slaves.reduce((acc, cur) => acc + (sameDad(eventSlave, cur) ? 1 : 0), 0);
			}
			applyCommon(newSlave);
			return newSlave;
		}

		/** we need to record any new parent information for existing slaves into the genepool as well as directly into the slave in question
		 * @param {App.Entity.SlaveState} slave
		 * @param {object} parentIDs
		 * @param {number} [parentIDs.mother]
		 * @param {number} [parentIDs.father]
		 */
		function setUnknownParents(slave, parentIDs = {}) {
			const gp = V.genePool.find(s => s.ID === slave.ID);

			if (parentIDs.mother && slave.mother === 0) {
				slave.mother = parentIDs.mother;
				if (gp) {
					gp.mother = parentIDs.mother;
				}
			}
			if (parentIDs.father && slave.father === 0) {
				slave.father = parentIDs.father;
				if (gp) {
					gp.father = parentIDs.father;
				}
			}
		}

		function buySlave() {
			// kill the cheat div (no going back now!)
			$(cheatDiv).empty();

			// the new slave is already set up to be related to the existing slave, but we're responsible for making sure the existing slave (and any others in our stable) gets *their* relatives set correctly
			switch (that.params.relative) {
				case "mother": {
					setUnknownParents(eventSlave, {mother: newSlave.ID} );
					for (const slave of V.slaves) {
						if (sameDad(eventSlave, slave)) {
							setUnknownParents(slave, {mother: newSlave.ID} );
						}
					}
					break;
				}
				case "father": {
					setUnknownParents(eventSlave, {father: newSlave.ID} );
					for (const slave of V.slaves) {
						if (sameMom(eventSlave, slave)) {
							setUnknownParents(slave, {father: newSlave.ID} );
						}
					}
					break;
				}
				case "older sister":
				case "younger sister":
				case "older brother":
				case "younger brother":
				case "twin": { // siblings
					if (eventSlave.father === 0 && eventSlave.mother === 0) {
						setMissingParents(eventSlave);
						setUnknownParents(newSlave, {mother: eventSlave.mother, father: eventSlave.father});
					} else if (eventSlave.father === 0) {
						setMissingParents(eventSlave);
						setUnknownParents(newSlave, {father: eventSlave.father});
						for (const slave of V.slaves) {
							if (sameMom(eventSlave, slave)) {
								setUnknownParents(slave, {father: eventSlave.father});
							}
						}
					} else if (eventSlave.mother === 0) {
						setMissingParents(eventSlave);
						setUnknownParents(newSlave, {mother: eventSlave.mother});
						for (const slave of V.slaves) {
							if (sameDad(eventSlave, slave)) {
								setUnknownParents(slave, {mother: eventSlave.mother});
							}
						}
					}
					break;
				}
				default: // nothing needed for son/daughter
			}

			cashX(forceNeg(cost), "slaveTransfer", newSlave);

			// replace slave art
			$(artDiv).empty();
			App.Events.drawEventArt(artDiv, [newSlave, eventSlave]);

			const {he: he2} = getPronouns(newSlave);

			let elements = [];
			elements.push(`You complete the legalities and biometric scanning quickly and without fuss. ${newSlave.slaveName} arrives shortly. The two slaves remember each other only dimly — they parted a long time ago — but they embrace. The devoted ${SlaveTitle(eventSlave)} explains the situation and encourages ${his} ${that.params.relative} to be a good slave to you. ${newSlave.slaveName} looks a little fearful but clearly realizes that ${he2}'s lucky to be here.`);

			elements.push(App.UI.newSlaveIntro(newSlave, eventSlave));

			return elements;
		}
	}
};