code:
App.Events.REBrothelFunction = class REBrothelFunction extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => App.Entity.facilities.brothel.employeesIDs().size > 5,
		];
	}

	execute(node) {
		const largeCash = 10000;
		const mediumCash = 2000;
		const smallCash = 1000;

		const brothelNameCaps = capFirstChar(V.brothelName);

		App.Events.addParagraph(node, [
			`${brothelNameCaps} is a reputable establishment in ${V.arcologies[0].name}, a veritable bedrock to sexual life in your arcology. As is befitting of its position, requests to rent out your brothel for one function or another come across your desk with some regularity. On this particular day, ${V.assistant.name} has laid out a number of potential clients for your perusal. Given the importance of ${brothelNameCaps} in the arcology's sex trade, it would be unwise to indulge more than one of these requests at this time.`
		]);
		App.Events.addParagraph(node, [
			`One request comes to you written on a letterhead featuring the logo of a fellow arcology owner. She describes her husband's preference for your hard working brothel whores, whom he patronizes on his regular business trips to your arcology. Such indulgences have been a distraction to her husband of late, and she has dispatched him to undertake a task in your arcology that simply cannot go poorly. With this in mind, she beseeches you to close down your brothel for a single day out of solidarity for a fellow arcology owner — and for the significant sum of ${cashFormat(largeCash)}.`
		]);
		App.Events.addParagraph(node, [
			`Another of these bids for your brothel comes in the form of a curious video call. The video comes from an infamous lothario in your arcology, a seducer of powerful and prominent women citizens. Indeed, the recording was surreptitiously recorded in the bedroom of one such influential woman, with the Casanova describing his request in hushed tones while his wealthy host minces about unknowingly in the background. He explains that he is finally ready to hang up his coat and end his days of debauchery and copious casual sex, but that he would like to do so by engaging in a full day of indulgence at ${V.brothelName}.`
		]);
		App.Events.addParagraph(node, [
			`The last of these requests comes in the form of a letter, stamped with the herald of a prominent arcology family. It seems the eldest son of the family, known to you largely as a spoiled child riding on the coattails of his parents, is about to reach the age of majority. At his behest, his parents have contacted you to reserve your brothel for a day so that their son may become a man in true Free Cities fashion — amongst a roil of writhing flesh and wanton debauchery.`
		]);

		App.Events.addResponses(node, [
			new App.Events.Result(`Acquiesce to the arcology owner's request`, arcOwner, `This will earn you ${cashFormat(largeCash)}`),
			new App.Events.Result(`Give this lady-killing rake a proper send off into retirement`, rake, `This will earn you ${cashFormat(mediumCash)}`),
			new App.Events.Result(`Welcome the boy into manhood in Free Cities fashion`, boy, `This will earn you ${cashFormat(smallCash)}`)
		]);

		function arcOwner() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`Though you close down ${brothelNameCaps} for a day, it's far from a day off for your hard-working brothel slaves. In the absence of the convenient center for the sale of sexual services that a brothel represents, you disperse them onto the streets to sell their bodies the old fashioned way. At the end of the day you receive a brief message of gratitude from your fellow arcology owner while your whores appreciate the opportunity to stretch their legs on the street for a change of pace.`);
			for (const slave of V.slaves.filter(s => s.assignment === Job.BROTHEL)) {
				slave.devotion += 4;
			}
			cashX(largeCash, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function rake() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`Though a citizen he may be, this serial seducer may have more notches on his proverbial bedpost than even your oldest slaves. Though you are not present to view his mastery of the sexual craft first-hand, the dreamy fucked-out looks of exhaustion and gratified satisfaction painting every single one of your slaves' faces at the end of the day speak volumes. Indeed, all of your brothel slaves with any room for improvement in their whoring skills learn from his skillful coupling, while even those with nothing to learn from him gain confidence from the intensity of their sexual congress.`);
			for (const slave of V.slaves.filter(s => s.assignment === Job.BROTHEL)) {
				if (slave.skill.whoring < 100) {
					slave.skill.whoring += 10;
				} else {
					slave.devotion += 4;
				}
				if (canDoVaginal(slave) && canDoAnal(slave)) {
					actX(slave, "vaginal", 3);
					actX(slave, "anal", 3);
				} else if (canDoAnal(slave)) {
					actX(slave, "anal", 5);
				} else {
					actX(slave, "oral", 10);
				}
			}
			cashX(mediumCash, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function boy() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`Though he was but a boy yesterday, none can say that this newly made man entered his manhood with anything less than a sterling display of enthusiasm and virility, though he is somewhat lacking in general technique. Nevertheless, any man able to fuck his way through an entire brothel of sex slaves and back again is clearly capable of bearing the mantle of citizenry in ${V.arcologies[0].name}. The story of a boy entering manhood in such a spectacular manner spreads rapidly and reflects well in the court of public opinion, with many citizens recalling their own passage past the age of majority. However, a lifetime of indulgence and spoiling have rendered this new citizen unable to understand the concept of being refused — not that your slaves could refuse him, in any case. His rough treatment has left your poor slave whores battered by his brutally selfish lovemaking.`);
			for (const slave of V.slaves.filter(s => s.assignment === Job.BROTHEL)) {
				healthDamage(slave, 5);
				if (canDoVaginal(slave) && canDoAnal(slave)) {
					actX(slave, "vaginal");
					actX(slave, "anal");
				} else if (canDoAnal(slave)) {
					actX(slave, "anal", 2);
				} else {
					actX(slave, "oral", 4);
				}
			}
			cashX(smallCash, "event");
			repX(2500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}
	}
};


code:
App.Events.REBusyClub = class REBusyClub extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => App.Entity.facilities.club.employeesIDs().size > 3
		];
	}

	execute(node) {
		App.Events.addParagraph(node, [`The original designers of the modern arcology did not realize how inseparable from slavery their work would become. The club at the social heart of ${V.arcologies[0].name} was not meant as a center of the more friendly kind of sexual slavery, but that is what it has become. Free whores of the highest quality work there, and they are accompanied by a flock of your slaves who have simple orders to dance, add cheer, and perform sexual favors wherever they can.`]);
		App.Events.addParagraph(node, [`Offering slaves for free sex would become unmanageable if the club where your public servants work was open to the unwashed masses, but it is not. The arcology is already selective, and only good citizens can party, dance, and fuck the night away in ${V.clubName}. The upper classes recognize your contributions to arcology culture, which you could probably parlay into an even greater benefit.`]);

		repX(500, "event");

		App.Events.addResponses(node, [
			new App.Events.Result("Sponsor a special event in the club", sponsor, `This will cost ${cashFormat(2000)}`),
			new App.Events.Result("Host a business exposition", host, `This will cost ${cashFormat(5000)}`),
		]);

		function sponsor() {
			cashX(-2000, "event");
			repX(2500, "event");
			return `The Free Cities are new, and so is their culture. There are new traditions, new expectations, and now, new holidays. One morning, the upper classes of the arcology are surprised and gratified to find that the club has been specially decorated, and all the club sluts are nude. The floor of the club is typically meant for dirty dancing and some light sex, not public penetrative intercourse. Not today; today is special. The festivities greatly improve your renown; you have set a high bar for what a wealthy arcology owner should do.`;
		}
		function host() {
			cashX(-5000, "event");
			V.arcologies[0].prosperity += 2;
			repX(2500, "event");
			return `With the world economy in a perilous state, the Free Cities are one of the few remaining areas where innovation and new business opportunities still appear. The novel markets associated with the slave trade only reinforce this trend, offering a cornucopia of opportunities for the clear-eyed investor with liquid assets. Every other week there is news of a new fortune being made from smart investments in leather, in human growth hormones, or in psychoactive drugs. You host an exposition for slave services centered on the club, with your slaves serving as greeters who are eager to ensure that all the little wants of visiting notables are thoroughly satisfied. The optimistic outlook projected by this event improves ${V.arcologies[0].name}'s business prospects and even reflects well on you personally.`;
		}
	}
};

repo_name: Ducati/fc

license: mit


code:
App.Events.REBusyMasterSuite = class REBusyMasterSuite extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.ConcubineID !== 0
		];
	}

	actorPrerequisites() {
		const req = [
			s => s.fuckdoll === 0,
			s => s.assignment === Job.MASTERSUITE,
			s => (
				(canDoAnal(s) && s.anus > 0) ||
				(canDoVaginal(s) && s.vagina > 0)
			),
		];

		return [ // Need at least three actors. Grab more later.
			req,
			req,
			req,
		];
	}

	execute(node) {
		const msSlaves = V.slaves.filter((s) => s.fuckdoll === 0 && s.assignment === Job.MASTERSUITE)
			.map((s) => {
				/** @type {Array<FC.SlaveActs|"none">} */
				let options = [];
				if (canDoAnal(s) && s.anus > 0) {
					options.push("anal");
				}
				if (canDoVaginal(s) && s.vagina > 0) {
					options.push("vaginal");
				}
				if (options.length === 0) {
					options.push("none");
				}
				return {slave: s, mode: options.pluck()};
			});
		const [participants, nonparticipants] = _.partition(msSlaves, s => s.mode !== "none");
		const bottomSlave = participants.first().slave;
		let r = [];

		App.Events.drawEventArt(node, [S.Concubine, ...msSlaves.map(s => s.slave)], "no clothing");

		const {
			He,
			he, his, him, himself
		} = getPronouns(S.Concubine);

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

		r.push(`You have an extended meeting with a prominent citizen planned, from the start of business in the morning until you're done. That's likely to be in the late evening, since he's probably going to get into technical business proposals, and`);
		r.push(contextualIntro(V.PC, S.Concubine, true));
		r.push(`knows it. ${He} is surprised, therefore, when a minor business emergency calls your would-be interlocutor away, canceling the meeting and sending you home hours earlier than you'd planned. ${He}`);
		if (canTalk(S.Concubine)) {
			r.push(`giggles helplessly`);
		} else {
			r.push(`signs humorously`);
		}
		r.push(`at the surprise when you walk into your suite. Apparently, ${he} decided to while away the hours until you got back by having some truly grandiose group sex with all the slaves you have in the suite.`);

		App.Events.addParagraph(node, r);
		r = [];

		r.push(`${He} had to turn to greet you as you entered, since ${he} was facing away from the entry, and the reason why is rather obvious. Up near the opposite wall, ${contextualIntro(S.Concubine, bottomSlave)} is on the floor with ${his2} face down and ${his2} ass up.`);

		App.Events.addParagraph(node, r);

		/** helper function for train...identify the hole being penetrated by the next slave
		 * @param {App.Entity.SlaveState} slave
		 * @param {FC.SlaveActs} mode
		 */
		function hole(slave, mode) {
			if (mode === "vaginal") {
				if (slave.vagina > 2) {
					return "loose pussy";
				} else if (slave.vagina > 1) {
					return "pussy";
				} else {
					return "tight pussy";
				}
			} else if (mode === "anal") {
				if (slave.anus > 2) {
					return "asspussy";
				} else if (slave.anus > 1) {
					return "asshole";
				} else {
					return "tight butt";
				}
			}
		}

		/** helper function for train...identify the tool being used by the next slave to penetrate this slave
		 * @param {App.Entity.SlaveState} slave
		 * @param {FC.SlaveActs} mode
		 * @param {App.Entity.SlaveState} nextSlave
		 */
		function penetrator(slave, mode, nextSlave) {
			let t = ``;
			if (canPenetrate(nextSlave)) {
				t += contextualIntro(slave, nextSlave) + "'s ";
				if (nextSlave.dick > 3) {
					t += "painfully big";
				} else {
					t += "hard";
				}
				t += " dick";
			} else {
				t += "a ";
				const size = (mode === "vaginal" ? slave.vagina : slave.anus);
				if (size > 2) {
					t += "huge";
				} else if (size > 1) {
					t += "big";
				} else {
					t += "moderate";
				}
				t += " strap-on worn by " + contextualIntro(slave, nextSlave);
			}
			return t;
		}

		App.Events.addParagraph(node, [
			/* build the train from all participating slaves */
			participants.reduce((acc, cur, i, arr) => {
				let r = ``;
				const {mode, slave} = cur;
				if (mode === "none") {
					throw new Error("Non-participating slave is participating"); // impossible, but needed for typechecking
				}
				const nextSlave = (i + 1 >= arr.length) ? S.Concubine : arr[i + 1].slave;

				if (i !== arr.length - 1) {
					r += `${slave.slaveName}'s ${hole(slave, mode)} is filled by ${penetrator(slave, mode, nextSlave)}, `;
					if (nextSlave.belly >= 150000) {
						r += `whose middle is so obscenely distended that ${slave.slaveName} is struggling to support it.`;
					} else if (nextSlave.belly >= 10000 || nextSlave.weight >= 160) {
						r += `whose middle is resting on ${slave.slaveName}'s ${slave.skin} back.`;
					} else if (nextSlave.boobs > 10000) {
						r += `whose tits are so unreasonably large they're resting on ${slave.slaveName}'s ${slave.skin} back.`;
					} else if (slave.butt > 4) {
						r += `well cushioned by ${slave.slaveName}'s huge ass.`;
					} else if (nextSlave.nipples === "huge") {
						r += `who is bending to rub ${getPronouns(nextSlave).his} enormous hard nipples across ${slave.slaveName}'s ${slave.skin} back.`;
					} else if (nextSlave.lips > 40) {
						r += `who is bending forward to nibble along ${slave.slaveName}'s ${slave.skin} neck.`;
					} else if (hasAnyArms(nextSlave)) {
						r += `who is reaching around to grope ${slave.slaveName}'s ${slave.skin} chest.`;
					} else {
						r += `who is propped up against ${slave.slaveName}'s ${slave.skin} butt.`;
					}
				} else {
					/* top slave */
					r += `Finally, ${slave.slaveName}'s ${hole(slave, mode)} is filled by ${penetrator(slave, mode, nextSlave)}, who has paused ${his} thrusting to issue a preemptory order to the slaves to stay where they are, before turning to greet you cheerfully.`;
				}
				seX(nextSlave, "penetrative", slave, mode, 1);
				return acc + ` ` + r;
			}, ``)
		]);
		/* and now describe what the non-participating slaves are doing */
		if (nonparticipants.length > 0) {
			App.Events.addParagraph(node, [
				`${toSentence(nonparticipants.map((s) => s.slave.slaveName))} can't participate in the train, so ${S.Concubine.slaveName} has them busy lying under the slaves who are, offering what oral stimulation they can manage.`
			]);
			for (const s of nonparticipants) {
				actX(s.slave, "oral");
			}
		}

		const top = participants.last();

		/** @type {FC.SlaveActs|"none"} */
		let concubineMode = "none";
		let concubineHole;
		if (canDoAnal(S.Concubine) && S.Concubine.anus > 0) {
			concubineMode = "anal";
			if (S.Concubine.anus > 2) {
				concubineHole = "loose anus";
			} else if (S.Concubine.anus > 1) {
				concubineHole = "asshole";
			} else {
				concubineHole = "tight little asshole";
			}
		} else if (canDoVaginal(S.Concubine) && S.Concubine.vagina > 0) {
			concubineMode = "vaginal";
			if (S.Concubine.vagina > 2) {
				concubineHole = "loose pussy";
			} else if (S.Concubine.vagina > 1) {
				concubineHole = "pussy";
			} else {
				concubineHole = "tight little pussy";
			}
		}

		const responses = [];
		if (concubineMode !== "none") {
			responses.push(new App.Events.Result("Slide in behind the concubine for some action", behindConcubine));
		}
		responses.push(new App.Events.Result("Slide in up at the head of the bed for some oral", bedHead));
		App.Events.addResponses(node, responses);

		function behindConcubine() {
			const frag = document.createDocumentFragment();
			const r = [];
			r.push(`${S.Concubine.slaveName} anticipates you, and is already sliding ${himself} partway out of ${top.slave.slaveName} and cocking ${his} hips to spread ${his}`);
			if (S.Concubine.butt > 15) {
				r.push(`immeasurable`);
			} else if (S.Concubine.butt > 10) {
				r.push(`expansive`);
			} else if (S.Concubine.butt > 7) {
				r.push(`enormous`);
			} else if (S.Concubine.butt > 5) {
				r.push(`huge`);
			} else if (S.Concubine.butt > 2) {
				r.push(`healthy`);
			} else {
				r.push(`trim`);
			}
			r.push(`buttocks as wide as ${he} can without disentangling ${himself} from the sex train. Up on the bed ${he}'s at just the right height, and ${he} winks ${his} ${concubineHole}`);
			if (canTalk(S.Concubine)) {
				r.push(`invitingly, laughing at the sheer decadence of it.`);
			} else {
				r.push(`invitingly.`);
			}

			if (V.PC.dick === 0) {
				r.push(`You pull on a strap-on and push it`);
			} else {
				r.push(`You push yourself`);
			}
			r.push(`home with some force, your concubine's extreme state of arousal leaving ${his} ass very relaxed and welcoming; the thrust shoves ${him} forward to hilt ${himself} in ${top.slave.slaveName}, and so on down the line, producing more giggling, some squealing, and much scrabbling for balance. It takes a while to find the rhythm, and while you wait for the inevitable tangles to be fixed you decide to challenge yourself. You reach around and`);
			if (S.Concubine.boobs > 10000) {
				r.push(`sink your hands into ${S.Concubine.slaveName}'s massive boobs,`);
			} else if (S.Concubine.boobs > 1000) {
				r.push(`heft ${S.Concubine.slaveName}'s heavy boobs,`);
			} else if (S.Concubine.boobs > 300) {
				r.push(`tease ${S.Concubine.slaveName}'s healthy breasts,`);
			} else {
				r.push(`massage ${S.Concubine.slaveName}'s flat chest,`);
			}
			r.push(`nibbling ${his} ${S.Concubine.skin} neck, and generally torturing ${him} with stimulation until ${he} climaxes to ${his} beloved ${getWrittenTitle(S.Concubine)}. When ${he} does, you extract yourself and pull ${him} unceremoniously off ${top.slave.slaveName}, replacing ${him} in ${top.slave.slaveName}'s`);

			if (top.mode === "anal") {
				r.push(`butt.`);
			} else {
				r.push(`pussy.`);
			}
			r.push(`You work your way down the line, orgasm by orgasm, delaying your own climax until the exhausted ${bottomSlave.slaveName} manages yet another orgasm by heroic efforts, and you're done. As you roll off ${him2}, panting, there is scattered applause and much congratulation from your harem of trusting slaves.`);
			S.Concubine.trust += 5;
			if (concubineMode !== "none") {
				seX(V.PC, "penetrative", S.Concubine, concubineMode);
			}
			for (const s of msSlaves) {
				s.slave.trust += 1;
				if (s.mode !== "none") {
					seX(V.PC, "penetrative", s.slave, s.mode);
				}
			}
			if (canImpreg(bottomSlave, V.PC)) {
				knockMeUp(bottomSlave, 10, 1, V.PC.ID);
			}

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

		function bedHead() {
			const frag = document.createDocumentFragment();
			const r = [];
			r.push(`${bottomSlave.slaveName}'s ${App.Desc.eyesColor(bottomSlave)} widen when you push ${him2} upright for a moment and slide in under ${him2}, but ${he2} wraps ${his2}`);
			if (bottomSlave.lips > 95) {
				r.push(`facepussy`);
			} else if (bottomSlave.lips > 70) {
				r.push(`dick-sucking lips`);
			} else if (bottomSlave.lips > 20) {
				r.push(`pretty lips`);
			} else {
				r.push(`lips`);
			}
			r.push(`around your`);
			if (V.PC.dick === 0) {
				r.push(`clit`);
			} else {
				r.push(`cock`);
				if (V.PC.vagina !== -1) {
					r.push(`and starts stroking your pussy`);
				}
			}
			r.push(`eagerly enough, even as ${msSlaves[1].slave.slaveName} goes back to fucking ${him2}. The sex train is fairly gentle, since anything too fast would disintegrate the gymnastic arrangement, but ${bottomSlave.slaveName} is still getting enough stimulation that ${he2} whimpers quietly into your`);
			if (V.PC.vagina !== -1) {
				r.push(`pussy,`);
			} else {
				r.push(`dick,`);
			}
			r.push(`a nice feeling. The blowjob is`);
			if (bottomSlave.skill.oral >= 100) {
				r.push(`masterful, despite the distraction,`);
			} else if (bottomSlave.skill.oral > 10) {
				r.push(`serviceable, despite the distraction,`);
			} else {
				r.push(`only mediocre, but serviceable enough,`);
			}
			r.push(`so you let ${him2} work for a while before gently shoving ${him2} off the side of the bed and telling ${him2} to get to the back of the line. The slaves all shuffle forward awkwardly, and inadvertently block your view so that you hear rather than see ${bottomSlave.slaveName} start groping your concubine ${S.Concubine.slaveName}'s`);
			if (S.Concubine.butt > 15) {
				r.push(`immeasurable`);
			} else if (S.Concubine.butt > 10) {
				r.push(`expansive`);
			} else if (S.Concubine.butt > 7) {
				r.push(`enormous`);
			} else if (S.Concubine.butt > 5) {
				r.push(`huge`);
			} else if (S.Concubine.butt > 2) {
				r.push(`healthy`);
			} else {
				r.push(`trim`);
			}
			r.push(`ass down near the foot of the bed. You climax, on occasion, but are enjoying yourself so immensely that you let the slaves continue the rotation until you're entirely spent, and they're entirely exhausted. You reach for a tablet to get some work done, in the center of a pile of sweaty, tired slaves, all of whom are resting with at least one body part in contact with their beloved ${properMaster()}.`);
			S.Concubine.devotion += 5;
			seX(V.PC, "penetrative", S.Concubine, "oral");
			for (const s of msSlaves) {
				s.slave.devotion += 1;
				seX(V.PC, "penetrative", s.slave, "oral", 2);
			}

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


code:
App.Events.REBusyServantsQuarters = class REBusyServantsQuarters extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => App.Entity.facilities.servantsQuarters.employeesIDs().size > 3
		];
	}

	execute(node) {
		App.Events.addParagraph(node, [`Your penthouse is very well staffed with servants. The trend in modern buildings is to design around automatic cleaning systems. Dusting, mopping, and polishing are no longer really necessary when machines that do them more cheaply and thoroughly than any human are readily available. Keeping slaves to clean is an ostentation, and visitors to your quarters are often surprised and gratified to see a sex slave working away in the old way.`]);
		App.Events.addParagraph(node, [`The busy servants' quarters are a reservoir of slaves that can be used for almost any whim that occurs to you.`]);

		repX(500, "event");

		App.Events.addResponses(node, [
			new App.Events.Result("Share the servants' quarters with your more favored slaves", share),
		]);

		function share() {
			for (const slave of V.slaves) {
				if (slave.assignment !== Job.QUARTER) {
					slave.devotion += 4;
					if (canPenetrate(slave)) {
						actX(slave, "penetrative", 2);
						if (canDoVaginal(slave)) {
							actX(slave, "vaginal", 1);
						} else {
							actX(slave, "penetrative", 1);
						}
					} else if (canDoVaginal(slave)) {
						actX(slave, "vaginal", 2);
						actX(slave, "penetrative", 1);
					} else {
						actX(slave, "penetrative", 3);
					}
				} else {
					slave.devotion -= 5;
					if (canDoVaginal(slave) && slave.vagina > 0) {
						actX(slave, "vaginal");
					} else if (canDoAnal(slave) && slave.anus > 0) {
						actX(slave, "anal");
					}
					actX(slave, "oral", 5);
				}
			}
			return `The poor slaves in the servants' quarters are lower than almost any others, and they know it. Unfortunately for them, they're about to spend a long weekend knowing it unusually well. Sleeping time is usually nearly inviolate; you are the only person in the penthouse who is permitted to wake a sleeping slave for any but emergency reasons. Not now. You haunt the servants' quarters, using and abusing at will, and encourage your better slaves to follow your example. They quickly take the opportunity to be better than someone for once, and compete with each other in sexual harassment of the servants. They appreciate having targets for their frustrations.`;
		}
	}
};


code:
App.Events.RECelebrityAddictionDebt = class RECelebrityAddictionDebt extends App.Events.BaseEvent {
	eventPrerequisites() {
		return []; // always return valid
	}

	execute(node) {
		const slave = newCelebrityAddict();
		const {him, his, he} = getPronouns(slave);

		slave.prestigeDesc = `$He used to be ${slave.actualAge < 16 ? "a child actress" : "an actress"}, starring in several recent blockbuster films that many millions loved to watch on whatever screens they could get their hands on.`;
		slave.origin = `$He was a famous ${slave.actualAge < 16 ? "child " : ""}actress until $his drug habits pushed $him so far into debt that $his agent sold $him to you at auction.`;

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

		node.append(eventText());

		function eventText() {
			let t = new SpacedTextAccumulator();

			t.push(`A life of excess is dangerous, especially if there's no one around who can really tell you no. With all the money and power at your fingertips, not a day goes by where you're not tempted into excess.`);
			t.push(`You're reminded of this fact when your personal assistant informs you of a high profile slave auction.`);
			t.push(slave.slaveName);
			t.push(`used to be a famous movie`);
			if (V.diversePronouns && slave.pronoun === App.Data.Pronouns.Kind.male) {
				t.push(`actor.`);
			} else {
				t.push(`actress.`);
			}
			t.push(`That was, until ${his} aphrodisiac habit got the better of ${him}. Hopelessly addicted and drowning in debt, ${his} life is being offered up at auction to anyone who wants it. Your personal assistant estimates the auction to end somewhere between ¤30,000 and ¤50,000. Needless to say, it would be very prestigious to own ${him}.`);

			t.toParagraph();

			const choices = [];
			if (V.cash < 15000) {
				choices.push(new App.Events.Result(null, null, `Unfortunately you don't have the funds to remain competitive in this particular auction.`));
			} else {
				choices.push(new App.Events.Result(`Attend the Auction`, attendAuction));
			}
			App.Events.addResponses(t.container(), choices);

			return t.container();
		}

		function newCelebrityAddict() {
			const slave = GenerateNewSlave(undefined, {
				minAge: 10,
				maxAge: 30,
				ageOverridesPedoMode: true,
				disableDisability: 1
			});

			slave.career = slave.actualAge < 16 ? "a child actress" : "an actress";
			slave.prestige = 2;

			slave.devotion = random(-80, -60);
			slave.trust = random(-60, -50);

			// famous non-porn actor/actress should have a conventional build, and would be able to get breast reductions, even with macro/gigantomastia
			if (slave.genes === "XY") {
				slave.boobs = Math.clamp(slave.boobs, 100, 200);
			} else if (slave.actualAge < 13) {
				slave.boobs = Math.clamp(slave.boobs, 100, 300);
			} else if (slave.actualAge < 16) {
				slave.boobs = Math.clamp(slave.boobs, 100, 500);
			} else {
				slave.boobs = Math.clamp(slave.boobs, 100, 2000);
			}

			slave.health.condition = random(-75, -30);
			slave.health.longDamage = 20;
			slave.weight = random(-40, 20);

			// slave has unusually high odds of pFace, with a very high .face score and possibility of plastic surgery otherwise
			slave.geneticQuirks.pFace = either(0, 0, 0, 1, 1, 2);
			if (slave.geneticQuirks.pFace > 0) {
				slave.face = 100;
			} else {
				slave.face = random(25, 100);
			}
			// only apply plastic surgery when it would have an effect, and never to child actors
			if (slave.actualAge >= 16 && slave.face <= 80) {
				const plasticSurgeries = random(0, Math.floor((100 - slave.face) / 20));
				if (plasticSurgeries > 0) {
					slave.face = Math.min(slave.face + (20 * plasticSurgeries), 100);
					slave.faceImplant = either(5, 10, 15, 20) * plasticSurgeries;
				}
			}

			if (slave.visualAge < 16) {
				slave.faceShape = "cute";
			}

			slave.lips = random(0, 70);

			if (slave.teeth === "crooked" || slave.teeth === "gapped") {
				slave.teeth = "normal";
			}

			if (slave.vagina > -1) {
				if (slave.actualAge > 14) {
					slave.vagina = random(3);
				} else {
					slave.vagina = 0;
				}
			}
			slave.anus = slave.actualAge > 14 ? 3 : 0;

			if (slave.vagina > 0) {
				slave.skill.vaginal = random(31, 70);
			}
			slave.skill.oral = random(31, 70);
			if (slave.dick > 0) {
				slave.skill.penetrative = jsRandom(31, 70);
			}
			if (slave.anus !== 0) {
				slave.skill.anal = random(31, 70);
			}
			slave.skill.entertainment = 75;
			slave.skill.combat = 0;
			slave.skill.entertainer = 175;
			slave.addict = 20;
			slave.intelligence = random(-50, 80);
			slave.intelligenceImplant = Math.clamp(((slave.actualAge > 16) + (slave.actualAge > 24) + (slave.intelligence > 0) + (slave.intelligence > 50) + random(-2, 1)), 0, 2) * 15;
			slave.energy = 100;
			slave.behavioralFlaw = either("arrogant", "bitchy");

			if (slave.pubertyXX > 0 && slave.vagina > 0 && random(0, 100) >= 20) {
				slave.preg = random(1, 35);
				slave.pregWeek = slave.preg;
				slave.pregType = either(1, 1, 1, 1, 1, 2, 2, 3);
				slave.pregSource = either(-4, -2, 0);
				SetBellySize(slave);
			}

			slave.slaveCost = random(30000, 50000);

			// Lowers actual cost of slave depending on how good the PC is at trading
			slave.slaveCost -= V.PC.skill.trading * 100;

			return slave;
		}

		function attendAuction() {
			const t = new SpacedTextAccumulator();
			if (V.cash < slave.slaveCost) {
				t.push(`You work your cash as far as it will go, but despite your best efforts, you are outbid. The slave goes home with one of ${his} many fans, and you go home empty-handed.`);
			} else {
				cashX(-slave.slaveCost, "slaveTransfer", slave);

				t.push(`It's a rough auction; a number of rabid fans stretch their wallets as thin as they will go, but in the end, yours stretches further. You return to your penthouse and eagerly await the delivery of your prize.`);
				t.push(`When ${he} arrives at your penthouse, ${he}'s shoved stark naked into your office by a manager who's clearly got better things to do. It's obvious that ${his} health is failing rapidly; up this close, you can clearly see the effects of addiction eating away at ${him}. Medical attention should be more than enough to keep ${him} alive with a little effort, though. Unsurprisingly, instead of asking you for help, ${he} demands the strongest aphrodisiac you have, not quite aware of how different ${his} new situation is from ${his} old one. It's going to take a lot of work to turn the addiction-riddled mess in front of you into even a halfway decent sex slave.`);

				t.toParagraph();

				t.push(App.UI.newSlaveIntro(slave));
			}
			t.toParagraph();
			return t.container();
		}
	}
};


code:
// cSpell:ignore Shahryar

App.Events.RECitizenHookup = class RECitizenHookup extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.policies.regularParties === 1,
		];
	}

	execute(node) {
		let r = [];
		let repopHookupPregnant;

		const FSArray = FutureSocieties.activeFSes(V.arcologies[0]);
		const FS = (FSArray.length > 0) ? FSArray.random() : "none";

		r.push(`At night, the best living areas in the arcology offer a constant mélange of selective entertainments. There's a perpetual social scrum of who is to be invited to what going on, and you occupy a preeminent place atop it, mostly aloof from the struggles of your citizens for recognition and influence. You're invited to almost everything, since everyone who lives here knows the value of being in favor with the owner of the arcology. Invitations to your parties, of course, are some of the most valuable social currency in the arcology and one of ${V.assistant.name}'s most important duties is to help you manage them without wasting your valuable time. It's not actually necessary for you to attend your own parties, since almost everyone will be glad to be seen in the entertainment area of the penthouse whether or not the`);
		r.push(`${V.PC.title === 1 ? 'proprietor' : 'proprietress'} is actually present.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`But tonight, you've put in an appearance. Your citizens are drinking your`);
		if (FutureSocieties.isActive('FSPastoralist')) {
			r.push(`milk`);
		} else if (FutureSocieties.isActive('FSRestart')) {
			r.push(`finest alcohol`);
		} else {
			r.push(`alcohol`);
		}
		r.push(`and eating your food, though of course they helped pay for it through their rent. They're performing a complex dance of social dominance, and it all radiates around you, with complex unspoken rules of collective approval governing which citizens cycle past you for a word, and for how long. During a low point in the ebb and flow,`);
		switch (FS) {
			case "FSSubjugationist":
			case "FSSupremacist":
				r.push(`a pretty, racially pure young woman`);
				break;
			case "FSGenderRadicalist":
				r.push(`a beautiful young futa`);
				break;
			case "FSGenderFundamentalist":
				r.push(`a good-looking young lady`);
				break;
			case "FSRepopulationFocus":
				if (V.arcologies[0].FSRepopulationFocusLaw === 1 && (random(1, 10) > 3)) {
					repopHookupPregnant = 1;
					r.push(`a heavily pregnant young lady`);
				} else {
					repopHookupPregnant = 0;
					r.push(`a pretty, fertile young woman with wide, child-bearing hips`);
				}
				break;
			case "FSRestart":
				r.push(`a stunningly gorgeous woman`);
				break;
			case "FSPaternalist":
				r.push(`a pretty, cheerful young woman`);
				break;
			case "FSDegradationist":
				r.push(`a confident girl`);
				break;
			case "FSBodyPurist":
				r.push(`a clean-looking young woman`);
				break;
			case "FSTransformationFetishist":
				r.push(`a nicely augmented girl`);
				break;
			case "FSYouthPreferentialist":
				if (V.minimumSlaveAge < 13) {
					r.push(`an adorable little loli`);
				} else if (V.minimumSlaveAge < 18) {
					r.push(`a pretty teenage girl`);
				} else {
					r.push(`a nice looking girl`);
				}
				break;
			case "FSMaturityPreferentialist":
				r.push(`an attractive, mature woman`);
				break;
			case "FSSlimnessEnthusiast":
				r.push(`a slim young thing`);
				break;
			case "FSAssetExpansionist":
				r.push(`a curvaceous young woman`);
				break;
			case "FSPastoralist":
				r.push(`a hot little lady`);
				break;
			case "FSPhysicalIdealist":
				r.push(`a hot little amazon`);
				break;
			case "FSHedonisticDecadence":
				r.push(`a plump little cutey`);
				break;
			case "FSChattelReligionist":
				r.push(`a pretty, devout-looking young woman`);
				break;
			case "FSRomanRevivalist":
				r.push(`a proper young Roman lady`);
				break;
			case "FSNeoImperialist":
				r.push(`a gorgeous young Imperial Knight with flowing blonde hair and a scarred face`);
				break;
			case "FSAztecRevivalist":
				r.push(`a natural Aztec beauty`);
				break;
			case "FSEgyptianRevivalist":
				r.push(`a pretty, sun-kissed lady`);
				break;
			case "FSEdoRevivalist":
				r.push(`a proper Edo lady`);
				break;
			case "FSArabianRevivalist":
				r.push(`a pretty Arabian princess`);
				break;
			case "FSChineseRevivalist":
				r.push(`a pretty Chinese lady`);
				break;
			case "FSIntellectualDependency":
				r.push(`a cute party girl`);
				break;
			case "FSSlaveProfessionalism":
				r.push(`an elegant woman`);
				break;
			case "FSPetiteAdmiration":
				r.push(`a delightfully short young lady`);
				break;
			case "FSStatuesqueGlorification":
				r.push(`a towering figure`);
				break;
			default:
				r.push(`a pretty young woman`);
		}
		r.push(`sidles up to you. She begins to introduce herself, but one of the advantages of your connection to the arcology is that you always know who everyone is, and you greet her by name, which people have never learned not to be impressed by. She gushes about some of your recent`);
		if (FS !== "none") {
			r.push(FutureSocieties.displayAdj(FS));
		}
		r.push(`actions, displaying an unusual grasp of what you've been planning. Despite her sincere interest, she's obviously got something else on her mind.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`She's yours for the taking, if you want her, and if her praise and proximity weren't enough to make that clear, she manages to`);
		switch (FS) {
			case "FSSubjugationist":
			case "FSSupremacist":
				r.push(`give you an excellent view straight down her ethnically superior cleavage, straining against the top of her fashionable dress.`);
				break;
			case "FSGenderRadicalist":
				r.push(`simultaneously give you an excellent view straight down her cleavage, and bring the material of her sheer dress tight across her legs in a way that outlines her dick.`);
				break;
			case "FSGenderFundamentalist":
				r.push(`press her flirting as far she can decorously take it, batting her eyes at you coquettishly.`);
				break;
			case "FSRepopulationFocus":
				if (repopHookupPregnant === 1) {
					r.push(`lean back just far enough that her full term, triplets rounded middle splits the front of her overly tight dress.`);
				} else {
					r.push(`press her hips up against your own, before leaning in and whispering`);
					if (V.arcologies[0].FSRepopulationFocusLaw === 1) {
						r.push(`"My womb is ready to do its duty."`);
					} else {
						r.push(`"I'm ripe for breeding right now."`);
					}
				}
				break;
			case "FSRestart":
				r.push(`give you an excellent view straight down her perfect cleavage, straining against the top of her name-brand dress.`);
				break;
			case "FSPaternalist":
				r.push(`brush her breasts against your arm, presuming on the egalitarian nature of your Paternalist society to flirt a little aggressively.`);
				break;
			case "FSDegradationist":
				r.push(`raise one shoulder far enough that her breast on that side pulls its nipple just clear of her tight leather dress, revealing a spiked piercing.`);
				break;
			case "FSBodyPurist":
				r.push(`arch her back with such warm propinquity that her natural breasts almost spill out of her tight little dress, and actually reveal the upper edges of their areolae.`);
				break;
			case "FSTransformationFetishist":
				r.push(`pop her huge fake boobs entirely out of her tight little evening dress without even using her hands.`);
				break;
			case "FSYouthPreferentialist":
				r.push(`perfectly balance her youthful, innocent appeal with the proper decorum between you and a citizen.`);
				break;
			case "FSMaturityPreferentialist":
				r.push(`perfectly balance her matronly, sensual appeal with the proper decorum between you and a citizen.`);
				break;
			case "FSSlimnessEnthusiast":
				r.push(`turn from side to side as she flirts with you in a way that shows off the coquettish forum under her tight dress to great effect.`);
				break;
			case "FSAssetExpansionist":
				r.push(`arch her back with such warm propinquity that her huge breasts spill out of her tight little dress, springing clear to offer themselves glorious and nude.`);
				break;
			case "FSPastoralist":
				r.push(`let you know that she's almost entirely milk-fed, while giving you quite an eyeful of her straining cleavage.`);
				break;
			case "FSPhysicalIdealist":
				r.push(`get a pretty good flex going without being obvious about it, outlining her abs against the sheer midsection of her tight dress.`);
				break;
			case "FSHedonisticDecadence":
				r.push(`lean her chubby body back far enough to pop the buttons off her top and allow her ample breasts and armful of a belly to hang free.`);
				break;
			case "FSChattelReligionist":
				r.push(`assume just a hint of a Chattel Religionist devotional pose used to request penetration. It's heavy flirting, of a modern religious sort.`);
				break;
			case "FSRomanRevivalist":
				r.push(`hint that her pudicitia, that is her purity, would be if anything enhanced by sexual commerce with someone as powerful as you.`);
				break;
			case "FSNeoImperialist":
				r.push(`hint that as a Knight under your banner, to serve you in *any* way would be among the greatest of honors.`);
				break;
			case "FSAztecRevivalist":
				r.push(`hint that her devotion, which is the most important thing, cannot be besmirched by tasting your divine power.`);
				break;
			case "FSEgyptianRevivalist":
				r.push(`hint that she would like nothing better than to bask in the pharaonic light in the arcology, very close to its source, while loosening her linen dress a little.`);
				break;
			case "FSEdoRevivalist":
				r.push(`allude to the refined pleasures, while assuming a slightly less dignified posture in her gorgeous kimono.`);
				break;
			case "FSArabianRevivalist":
				r.push(`reference young Scheherazade and mighty Shahryar in a way that suggests she's quite willing to play the former.`);
				break;
			case "FSChineseRevivalist":
				r.push(`allude to the divinity that resides with the powerful, implying that she'd very much like to come closer to it.`);
				break;
			case "FSIntellectualDependency":
				r.push(`hint that she forgot to put on panties and that she needs that dripping sound checked out.`);
				break;
			case "FSSlaveProfessionalism":
				r.push(`bring you fully erect with a single, masterful stroke of her fingers.`);
				break;
			case "FSPetiteAdmiration":
				r.push(`give the bulge in your pants a quick kiss.`);
				break;
			case "FSStatuesqueGlorification":
				r.push(`affectionately rest her breasts on your head.`);
				break;
			default:
				r.push(`flirt with you quite hard without crossing any lines between a citizen and an arcology owner.`);
		}
		r.push(`She's clearly attracted to you; even the most consummate actress would have difficulty fooling you, and her breath is a little quick, her pupils are a bit dilated, and she's blushing cutely. But she's no fool, either. A casual liaison with ${PCTitle()} would be a tremendous social boost for her.`);
		App.Events.addParagraph(node, r);

		const choices = [
			new App.Events.Result(`Keep aloof without offending her`, aloof),
			new App.Events.Result(`To them that hath, it shall be given`, give)
		];
		if (FS !== "none") {
			choices.push(new App.Events.Result(`Emphasize her societal style with exhibitionism`, exhibitionism));
		}
		App.Events.addResponses(node, choices);

		function aloof() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You thank her for her praise, weighting the words in just the right way to communicate that you consider her flirtations worthy compliments, and nothing more. She understands immediately, communicating acceptance and pleasure at her own daring with nothing more than a thankful look in your eyes. This is how you approach matters like this. You are the ruler of this place and it behooves you to maintain a balance atop all your citizens without showing any susceptibility to solicitation. A little incident like this has little effect on its own, but your habit of maintaining proper reserve creates a reputation for judiciousness that businesspeople consider attractive for arcology investment.`);
			V.arcologies[0].prosperity += 3;
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function give() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You're not exactly starved for casual sex, but you've never thought there was any such thing as too much of a good thing. You place a`);
			if (V.PC.title === 1) {
				r.push(`masculine`);
			} else {
				r.push(`feminine`);
			}
			r.push(`hand against the small of her back, feeling the warmth of her through the material of her evening wear. You hear a slight gasp from her as she realizes that her gambit has succeeded with more immediate effect than she expected. She shivers with anticipation as you steer her back through a side door, making a discreet exit towards your private suite.`);
			if (S.Concubine) {
				const {
					he, his
				} = getPronouns(S.Concubine);
				if (S.Concubine.intelligence+S.Concubine.intelligenceImplant > 50) {
					r.push(`${S.Concubine.slaveName} is there, of course, and ${he} instantly`);
					if (canSee(S.Concubine)) {
						r.push(`sees`);
					} else {
						r.push(`realizes`);
					}
					r.push(`that ${his} continued presence for a ménage à trois is wanted by both you and your guest.`);
				} else if (S.Concubine.intelligence+S.Concubine.intelligenceImplant < -50) {
					r.push(`${S.Concubine.slaveName} is there, of course, absentmindedly doing whatever it is ${he} does when you are not around, and unsurprisingly fails to`);
					if (canSee(S.Concubine)) {
						r.push(`see`);
					} else {
						r.push(`realize`);
					}
					r.push(`that ${his} presence might not be wanted.`);
				} else if (S.Concubine.fetish === Fetish.MINDBROKEN) {
					r.push(`${S.Concubine.slaveName} is there, of course, completely indifferent to you or your guest's presence.`);
				}
			}
			r.push(`Your guest restrains her eager praise now that you're in private, but her wide-eyed appreciation of your domain is compliment enough. Once in your suite, she strips, revealing`);
			switch (FS) {
				case "FSSubjugationist":
				case "FSSupremacist":
					r.push(`her fresh, pure body.`);
					break;
				case "FSGenderRadicalist":
					r.push(`perky young breasts, a pretty pussy, and a stiff dick above it.`);
					break;
				case "FSGenderFundamentalist":
					r.push(`perky young breasts and an elegantly coiffed strip of hair that perfectly highlights her demure pussy.`);
					break;
				case "FSRepopulationFocus":
					if (repopHookupPregnant === 1) {
						if (random(1, 10) > 7) {
							r.push(`an experienced body, comfortable with the burdens of pregnancy.`);
						} else {
							r.push(`an inexperienced body undergoing its very first pregnancy.`);
						}
						r.push(`She's taken good care of herself; not a single stretch mark can be seen across her proportionally giant belly.`);
					} else {
						if (V.arcologies[0].FSRepopulationFocusLaw === 1) {
							r.push(`an experienced body, ready and eager to grow fecund once more.`);
						} else {
							r.push(`an inexperienced body, but one with potential for becoming quite fecund.`);
						}
					}
					break;
				case "FSRestart":
					r.push(`a near flawless body; the only distinguishable mark on it: a small tattoo of a prestigious school.`);
					break;
				case "FSPaternalist":
					r.push(`a nice young body, with all the little attractions and flaws of a free girl's.`);
					break;
				case "FSDegradationist":
					r.push(`a taut body covered in dominant tattoos and spiky piercings.`);
					break;
				case "FSBodyPurist":
					r.push(`a delectably curvaceous young body unmarred by any trace of surgical intervention.`);
					break;
				case "FSTransformationFetishist":
					r.push(`a massive fake bubble butt to go with her fake boobs.`);
					break;
				case "FSYouthPreferentialist":
					r.push(`that her whole body looks fresh, untouched, and quite young.`);
					break;
				case "FSMaturityPreferentialist":
					r.push(`a big pair of motherly tits, generous hips, a broad ass, and total self confidence.`);
					break;
				case "FSSlimnessEnthusiast":
					r.push(`perky little breasts, a smooth waist, trim hips, and a cute little ass.`);
					break;
				case "FSAssetExpansionist":
					r.push(`an inhumanly enormous ass to match her similarly improbable boobs.`);
					break;
				case "FSPastoralist":
					r.push(`amply milk-fed assets.`);
					break;
				case "FSPhysicalIdealist":
					r.push(`the dimples that form on the sides of her cute buttocks when she flexes.`);
					break;
				case "FSHedonisticDecadence":
					r.push(`well-fed and delightfully jiggly assets.`);
					break;
				case "FSChattelReligionist":
					r.push(`a fresh and ready body, adorned here and there with sensual devotional jewelry.`);
					break;
				case "FSRomanRevivalist":
					r.push(`a graceful, milk-pale vision of classical beauty.`);
					break;
				case "FSNeoImperialist":
					r.push(`a statuesque body, corded with fit musculature made for practical service.`);
					break;
				case "FSAztecRevivalist":
					r.push(`a strong, tight, bronze body.`);
					break;
				case "FSEgyptianRevivalist":
					r.push(`a perfect expanse of smooth, warm, tanned skin.`);
					break;
				case "FSEdoRevivalist":
					r.push(`a graceful form so perfectly pale that her face requires almost no whitening at all.`);
					break;
				case "FSArabianRevivalist":
					r.push(`a nubile young body perfectly formed for a Sultan's bed.`);
					break;
				case "FSChineseRevivalist":
					r.push(`a pretty young body that would not look out of place in an Imperial bed.`);
					break;
				case "FSIntellectualDependency":
					r.push(`a young body practically begging you for dick.`);
					break;
				case "FSSlaveProfessionalism":
					r.push(`an elegant, mature body that knows its way around the bedroom.`);
					break;
				case "FSPetiteAdmiration":
					r.push(`an adorably petite figure.`);
					break;
				case "FSStatuesqueGlorification":
					r.push(`that you have to crane your neck back to take in her full stature.`);
					break;
				default:
					r.push(`a hot young body.`);
			}
			r.push(`Citizens like her often appreciate a good hard fuck, since regular submission to a pounding from sex slaves would be a scandal. There's little opprobrium waiting for you if it's known you had her, though, and she's deliciously eager as you press her down onto the bed${(V.PC.dick === 0) ? " and pull on your usual harness" : ""}. She ruts herself hard back against you as you thrust into her, moaning, and after a short while she begs for it even harder, so you flip her over and mount her like a bitch, making her scream.`);
			if (S.Concubine) {
				const {
					his, him
				} = getPronouns(S.Concubine);
				r.push(`The view of your conquest's rutting back is nice, of course, but after enjoying it for a few moments you pull ${S.Concubine.slaveName} in`);
				if (S.Concubine.intelligence+S.Concubine.intelligenceImplant > 50) {
					r.push(`and kiss your favorite deeply, playing with ${him} as you fuck.`);
				} else if (S.Concubine.intelligence+S.Concubine.intelligenceImplant < -50) {
					r.push(`and kiss your favorite idiot deeply, keeping ${him} from feeling left out as you fuck.`);
				} else if (S.Concubine.fetish === Fetish.MINDBROKEN) {
					r.push(`and play with ${his} body as you fuck.`);
				}
			}
			r.push(`When your guest is finally spent, she showers, dresses, and leaves discreetly, offering you a proper thank you. This is the kind of thing that builds a lasting reputation in the Free Cities.`);
			repX(5000, "event");
			if (FS === "FSRepopulationFocus" && V.PC.dick !== 0 && repopHookupPregnant === 0 && (random(1, 100) > 40)) {
				addTrinket(`a tasteful morning-after message, with attached positive pregnancy test, from a pretty citizen you bred`);
			} else if (FS !== "none") {
				addTrinket(`a tasteful morning-after message from a pretty ${FutureSocieties.displayAdj(FS)} citizen`);
			} else {
				addTrinket("a tasteful morning-after message from a pretty citizen");
			}
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function exhibitionism() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You turn to face her straight on, and something about the look in your eye fills her with mixed apprehension and anticipation. You agree with her banter and praise her for being so forward-thinking, before transitioning to more direct praise of her style and then her body. You're speaking in a tone that cuts through the room, and by the time you kiss your willing conquest, there's not a person in the room who isn't paying attention. They all understand the message: this gathering is turning into something else, now. Those few who aren't willing to fuck in public withdraw, and everyone who didn't come with a sexual partner sends urgent messages to have appropriate slaves brought from their apartments. You make out with her for a while, letting everyone make arrangements, and then pull her clothes off, making sure her`);
			if (!["none", "FSNull"].includes(FS)) {
				V.arcologies[0][FS] += 5;
			}
			switch (FS) {
				case "FSSubjugationist":
				case "FSSupremacist":
					r.push(`superior body`);
					break;
				case "FSGenderRadicalist":
					r.push(`tits and stiff dick`);
					break;
				case "FSGenderFundamentalist":
					r.push(`femininity`);
					break;
				case "FSRepopulationFocus":
					if (repopHookupPregnant === 1) {
						r.push(`fecund body`);
					} else {
						r.push(`ready-to-be-bred body`);
					}
					break;
				case "FSRestart":
					r.push(`perfect body`);
					break;
				case "FSPaternalist":
					r.push(`appealing body`);
					break;
				case "FSDegradationist":
					r.push(`dominant form`);
					break;
				case "FSBodyPurist":
					r.push(`natural body`);
					break;
				case "FSTransformationFetishist":
					r.push(`fake butt`);
					break;
				case "FSYouthPreferentialist":
					r.push(`young body`);
					break;
				case "FSMaturityPreferentialist":
					r.push(`mature body`);
					break;
				case "FSSlimnessEnthusiast":
					r.push(`slender body`);
					break;
				case "FSAssetExpansionist":
					r.push(`curvaceous form`);
					break;
				case "FSPastoralist":
					r.push(`milk-fed plushness`);
					break;
				case "FSPhysicalIdealist":
					r.push(`muscular body`);
					break;
				case "FSHedonisticDecadence":
					r.push(`plump body`);
					break;
				case "FSChattelReligionist":
					r.push(`divine sexuality`);
					break;
				case "FSRomanRevivalist":
					r.push(`elegant form`);
					break;
				case "FSNeoImperialist":
					r.push(`chiseled body`);
					break;
				case "FSAztecRevivalist":
					r.push(`well-built form`);
					break;
				case "FSEgyptianRevivalist":
					r.push(`beautiful tanned body`);
					break;
				case "FSArabianRevivalist":
				case "FSChineseRevivalist":
				case "FSEdoRevivalist":
					r.push(`graceful form`);
					break;
				case "FSIntellectualDependency":
					r.push(`extreme horniness`);
					break;
				case "FSSlaveProfessionalism":
					r.push(`experienced body`);
					break;
				case "FSPetiteAdmiration":
					r.push(`tiny form`);
					break;
				case "FSStatuesqueGlorification":
					r.push(`towering form`);
					break;
				default:
					r.push(`hot young body`);
			}
			r.push(`is obvious to everyone. The message is clear, and your guest of honor is the center of attention as you take her there in view of the arcology's leading citizens. Naturally, the story percolates, making it clear that there's nothing you won't do to further acceptance of ${FS !== "none" ? FutureSocieties.displayAdj(FS) : "societal"} principles.`);

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


code:
App.Events.REDevotedTwins = class REDevotedTwins extends App.Events.BaseEvent {
	eventPrerequisites() {
		// Conditional example
		return [
			() => V.seeIncest === 1
		];
	}

	actorPrerequisites() {
		return [
			[
				s => s.fetish !== Fetish.MINDBROKEN,
				s => s.sisters > 0,
				s => s.devotion > 50,
				canWalk,
				hasAnyArms
			],
			[
				s => s.fetish !== Fetish.MINDBROKEN,
				s => areSisters(s, getSlave(this.actors[0])) === 1,
				s => s.rivalTarget !== this.actors[0],
				s => s.devotion > 50,
				canWalk,
				hasAnyArms,
				isSlaveAvailable
			]
		];
	}

	execute(node) {
		const [alphaTwin, betaTwin] = this.actors.map(a => getSlave(a));

		App.Events.drawEventArt(node, [alphaTwin, betaTwin]);

		let t = [];

		t.push(
			App.UI.DOM.slaveDescriptionDialog(alphaTwin),
			`and`,
			App.UI.DOM.slaveDescriptionDialog(betaTwin),
			`are such good and devoted slaves that they happily do everything together. They sleep ${hasBothArms(alphaTwin) && hasBothArms(betaTwin) ? "in each other's arms" : 'together'}, bathe together, work together whenever they can, and fuck together. For a while they masturbated together until they became so habituated to sexual slavery that they stopped seeing much distinction between masturbation and sex with one another. At the moment, they're getting ready for their day, chatting quietly and helping each other.`,
		);

		App.Events.addParagraph(node, t);

		App.Events.addResponses(node, [
			new App.Events.Result(`Take them out for the morning`, morningWalk),
			new App.Events.Result(`Use them side by side`, threesome)
		]);

		function morningWalk() {
			t = [];
			t.push(`You head out of your penthouse with a pretty sex slave under each arm. They're attentive companions, doing everything they can to mirror each other as they show off their bodies to onlookers.`);
			if (V.weatherToday.severity <= 2) {
				t.push(`It's a bright, sunny day, so you walk them up and down a busy glassed-in galleria.`);
			} else {
				t.push(`It's a particularly nasty day, so you stick to walking them up and down the crowded interior malls.`);
			}
			t.push(`They clearly expect you to fuck them in public, but for once you just enjoy a couple of hours with them. They start disappointed that you aren't going to use them, but they quickly get over it and enjoy preening under your arms. They have both become more trusting of you, and your reputation has increased considerably.`);

			for (const slave of [alphaTwin, betaTwin]) {
				slave.trust += 4;
				repX(2500, "event", slave);
			}
			return t;
		}

		function threesome() {
			const alphaVaginal = canDoVaginal(alphaTwin) && alphaTwin.vagina > 0;
			const alphaAnal = canDoAnal(alphaTwin) && alphaTwin.anus > 0;
			const betaVaginal = canDoVaginal(betaTwin) && betaTwin.vagina > 0;
			const betaAnal = canDoAnal(betaTwin) && betaTwin.anus > 0;
			t = [];
			t.push(`Slave twins inevitably get used to threesomes with their sibling, and ${alphaTwin.slaveName} and ${betaTwin.slaveName} are no exception. They greet you with every appearance of arousal and begin a carefully balanced routine — foreplay with you, of course, but whatever parts of them aren't working on you work on the other slave. They stroke you while making out, stroke each other while`);
			if (V.PC.dick > 0) {
				t.push(`sucking you to rock hardness,`);
			} else {
				t.push(`building your arousal,`);
			}
			if (canDoVaginal(alphaTwin) && canDoVaginal(betaTwin)) {
				t.push(`and finger each other's holes`);
			} else if (alphaTwin.dick > 0 && alphaTwin.chastityPenis === 0 && betaTwin.dick > 0 && betaTwin.chastityPenis === 0) {
				t.push(`and fondle each other's dicks`);
			} else {
				t.push(`and fondle each other`);
			}
			t.push(`while`);
			if (V.PC.dick > 0) {
				if (alphaTwin.boobs > 300 && betaTwin.boobs > 300 && (alphaTwin.boobs <= betaTwin.boobs + 800 && alphaTwin.boobs >= betaTwin.boobs - 800) || (alphaTwin.boobs > 10000 && betaTwin.boobs > 10000)) {
					t.push(`rubbing four breasts up and down your dick.`);
				} else if (alphaTwin.belly > 5000 && betaTwin.belly > 5000) {
					t.push(`rubbing two bulging bellies up and down your dick.`);
				} else if (alphaTwin.weight > 95 && betaTwin.weight > 95) {
					t.push(`rubbing your dick between two soft bellies.`);
				} else {
					t.push(`running two tongues up and down your dick.`);
				}
				t.push(`Since you only have one cock, the symmetry ends when you start fucking them.`);
				if ((alphaVaginal || alphaAnal) && (betaVaginal || betaAnal)) {
					t.push(`As you switch from hole to hole, whichever twin isn't getting fucked at the moment uses their mouth and hands to stimulate your balls and their twin's fuckhole as you pound it. When you finally cum in ${betaTwin.slaveName}, ${alphaTwin.slaveName} sucks it out and they kiss deeply to share your ejaculate.`);
					if (alphaVaginal) {
						actX(alphaTwin, "vaginal");
					}
					if (alphaAnal) {
						actX(alphaTwin, "anal");
					}
					if (betaVaginal) {
						actX(betaTwin, "vaginal");
					}
					if (betaAnal) {
						actX(betaTwin, "anal");
					}
					actX(V.PC, "penetrative");
				} else {
					t.push(`As you switch from throat to throat, whichever twin isn't getting facefucked at the moment uses their hands to stimulate your balls and their twin's body. When you finally cum in ${betaTwin.slaveName}'s mouth, they turn and deeply kiss to share your ejaculate.`);
					actX(alphaTwin, "oral");
					actX(betaTwin, "oral");
					actX(V.PC, "penetrative");
				}
			} else {
				t.push(`crowding their faces against your pussy. You reach down and seize a nipple in each hand, pulling them upward so they can suck your nipples instead; they use manual stimulation to keep you going while they do. With one straddling each of your thighs, grinding shamelessly, you can reach around and molest their butts with your own hands.`);
				seX(alphaTwin, "oral", V.PC, "vaginal");
				seX(betaTwin, "oral", V.PC, "vaginal");
			}
			t.push(`<span class="devotion inc">They have both become more devoted to you.</span>`);

			alphaTwin.devotion += 4;
			betaTwin.devotion += 4;

			return t;
		}
	}
};


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

	actorPrerequisites() {
		const devoteeRequirements = [
			s => s.devotion > 50,
			canWalk,
			isSlaveAvailable
		];
		return [ // total of four actors, identical requirements for each
			devoteeRequirements,
			devoteeRequirements,
			devoteeRequirements,
			devoteeRequirements
		];
	}

	execute(node) {
		let devotees = this.actors.map(a => getSlave(a)); // for this event, they're fine as an array

		App.Events.drawEventArt(node, devotees);

		const slaveList = devotees.map(s => s.slaveName).reduce((res, ch, i, arr) => res + (i === arr.length - 1 ? ' and ' : ', ') + ch);

		let t = [];
		t.push(`You have a mature, well-trained household of slaves. ${slaveList} are all devoted to you. There are all manner of ways you could display this coterie of loyal sex slaves to show off your wealth and power.`);
		App.Events.addParagraph(node, t);

		App.Events.addResponses(node, [
			new App.Events.Result("See an operetta with four attendants", opera),
			new App.Events.Result("Visit a casino in good company", casino),
		]);

		function opera() {
			let t = [];
			t.push(`You reserve a box at an upcoming operetta; classical Italian music is enjoying a renaissance these days. The doormen at the fashionable opera house promptly widen the velvet ropes so that you and your party may proceed unimpeded. Their quick thinking is necessary, since there are five of you walking sedately up the steps: you in the middle, impeccable in`);
			if (V.PC.title === 1) {
				t.push(`gentleman's evening wear, complete with gloves and cane;`);
			} else {
				t.push(`a fine and noble lady's tuxedo;`);
			}
			t.push(`and ${slaveList}, all dressed in the gorgeous fashion of the seventeenth century, all plunging necklines, piled hair, and ruffled petticoats. The splendid master of ceremonies clears his throat and announces in a sonorous voice, "${PCTitle()}." The ostentation turns every head and catches every eye.`);
			for (const s of devotees) {
				repX(600, "event", s);
			}
			return t;
		}

		function casino() {
			let t = [];
			t.push(`The croupiers, bouncers and regulars down at the nearest casino hardly know what to think when you appear with a chit full of cash and twice as many partners as you have arms. You live the night big, starting at the poker table with so many tits and asses on display behind you that, baby, you make a killing. ${slaveList} quickly catch the rhythm of the place: slaves can get away with a little more in the smoky, whiskey soaked, money tinted atmosphere, and they enjoy themselves immensely. They flirt, flash, giggle, kiss each other, and generally destroy the concentration of everyone within twenty ${V.showInches === 2 ? "yards" : "meters"} — except you. Ring-a-ding-ding.`);
			const inc = random(30, 100)*30;
			for (const s of devotees) {
				cashX(inc, "event", s);
				s.devotion += 4;
			}
			return t;
		}
	}
};


code:
App.Events.REDrunkenTourist = class REDrunkenTourist extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.arcologies[0].prosperity >= 100,
			() => V.rep > random(1, 30000) || (V.debugMode > 0 && V.debugModeEventSelection > 0)
		];
	}

	execute(node) {
		const tourist = GenerateNewSlave("XX", {
			minAge: 21, maxAge: 29, race: "nonslave", disableDisability: 1
		});
		tourist.origin = "$He came to your arcology as a tourist and found $himself enslaved.";
		tourist.devotion = random(-70, -55);
		tourist.trust = random(-45, -25);
		setHealth(tourist, jsRandom(10, 20), undefined, undefined, undefined, 5);
		tourist.vagina++;
		tourist.hips = 2;
		tourist.butt = random(4, 6);
		tourist.boobs = 100 * random(10, 18);
		tourist.natural.boobs = tourist.boobs;
		tourist.weight = random(60, 140);
		tourist.behavioralQuirk = "none";
		tourist.sexualQuirk = "none";
		tourist.canRecruit = 0;
		App.Events.drawEventArt(node, tourist, "nice business attire");
		App.Events.addParagraph(node, [
			"While on a midnight stroll through the arcology, you notice a young woman stumbling along one of the pathways, looking lost.",
			"From her clothing to her demeanor you can tell she is a tourist, and an extremely drunk one at that.",
			"Upon seeing you, she stumbles up to you as quickly as she can manage, almost falling over in the process.",
			"She clearly doesn't recognize you as the owner of the arcology, as she makes no attempt at showing deference. "
		]);
		App.Events.addParagraph(node, [`"Excuse *hic* me... I'm lost. I don't know how to get back to my hotel... can you help me? These streets are so confusing..."`]);
		App.Events.addParagraph(node, ["She's going to be in for quite the hangover."]);

		const choices = [];
		choices.push(new App.Events.Result(`Escort her to her hotel`, escort));
		if (V.cash > 20000) {
			choices.push(new App.Events.Result(`Enslave her`, enslave, `This will require an unprofitable ${cashFormat(20000)}, since she is wealthy and obfuscating her fate will require considerable spending`));
		} else {
			choices.push(new App.Events.Result(null, null, `You cannot afford the ${cashFormat(20000)} enslaving her would require, since she is wealthy and obfuscating her fate would necessitate considerable spending`));
		}
		choices.push(new App.Events.Result(`Ignore her`, ignore));
		App.Events.addResponses(node, choices);

		function escort() {
			const frag = new DocumentFragment();
			App.Events.addParagraph(frag, [
				"You escort the drunken woman back to her hotel, and she asks you how long you've lived in the arcology.",
				"When you tell her you own the arcology, she thanks you profusely for taking the time to lead her back to her suite and presses herself up against you, trying her best to be sexy despite her impaired state.",
				`She promises to <span class="reputation inc">spread a good word about you,</span> and lets you know that you can come up to her room any time.`
			]);
			repX(500, "event");
			return frag;
		}

		function enslave() {
			const frag = new DocumentFragment();
			App.Events.refreshEventArt(tourist, "no clothing");
			App.Events.addParagraph(frag, [
				"Under the pretense of leading her back to her hotel, you bring her to the penthouse and have her scanned and tagged.",
				"She's so inebriated she thinks it's just a routine security scan, and ends up passing out before you can explain the situation to her fully.",
				"You have a slave carry her off in the meantime so you can initiate her when she wakes.",
				App.UI.newSlaveIntro(tourist)
			]);
			cashX(-20000, "event", tourist);
			return frag;
		}

		function ignore() {
			const frag = new DocumentFragment();
			App.Events.addParagraph(frag, [
				"You ignore the woman and move on with your night.",
				"You don't have time to involve yourself in such trivial matters.",
				"Dumbfounded, she stumbles onward in search of her hotel room."
			]);
			return frag;
		}
	}
};