code:
// cSpell:ignore squirtgasm

App.Events.CMRESSAnnoyingCat = class CMRESSAnnoyingCat extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [];
	}

	actorPrerequisites() {
		return [
			[ // single event slave
				s => s.fetish !== Fetish.MINDBROKEN,
				hasAnyArms,
				canMove,
				s => s.race === "catgirl",
				s => s.trust > 35,
			]
		];
	}

	execute(node) {
		const [eventSlave] = this.actors.map(a => getSlave(a));
		const {
			He, he, his, him, girl
		} = getPronouns(eventSlave);
		const {title} = getEnunciation(eventSlave);
		const PC = V.PC;

		App.Events.drawEventArt(node, eventSlave);

		let t = [];
		t.push(`Although your catgirl slaves are beautiful, intelligent, and move across your penthouse with an almost supernatural grace, their feline charm and beauty comes at the expense of a number of less desirable feline traits coded deeply into their spliced DNA. One of these irritating genetic leftovers is their exceptional neediness, which, when combined with their playful nature, gives them an unfortunate tendency to attempt to get your attention through minor annoyances. Well, when they aren't terrified of you, at least.`);
		App.Events.addParagraph(node, t);

		t = [];
		t.push(`Sometimes this comes in the form of erotic teasing, offering calculated, teasing glimpses of their butts or tits to try and win your eye when they want attention. Other times, like when ${eventSlave.slaveName} loudly meows when you walk by, it's just by being a nuisance. Normally, such a little thing would be totally beneath your notice, but ${he}'s been purring annoyingly at your heels all day, flicking ${his} tail up against the base of your hips, and mrowling whenever you come close. ${He} doesn't even seem to want anything in particular, and the minor catlike annoyances have finally gotten on your nerves.`);
		App.Events.addParagraph(node, t);

		App.Events.addResponses(node, [
			canDoAnal(eventSlave)
				? new App.Events.Result(`Roughly fuck ${his} ass to shut ${him} up`, annoyedFuck, analVirginWarning())
				: new App.Events.Result(),
			new App.Events.Result(`Tell ${him} to stop being such a nuisance`, stopIt),
			new App.Events.Result(`Ignore ${him}`, ignore),
		]);

		function analVirginWarning() {
			if (eventSlave.anus === 0) {
				return `This option will take ${his} anal virginity`;
			}
		}

		function annoyedFuck() {
			t = [];
			t.push(`As ${eventSlave.slaveName} meows at you, you order the irritating cat${girl} to turn around, drop ${his} bottoms, lift ${his} tail and spread ${his} cheeks. As though to make the command's intent even more obvious, you ${PC.dick !== 0 ? "pull your cock free from your pants" : "take a strapon and slide it up your legs"} as the furball look at you in surprise for a moment. Without a word of protest, the cat${girl} simply turns, pulls ${his} bottoms just under ${his} asscheeks, and lifts up ${his} tail to show you ${his}`);
			if (eventSlave.butt > 12) {
				t.push("enormous, view-dominating furry ass.");
			} else if (eventSlave.butt > 5) {
				t.push("huge, rounded fluffy ass-globes.");
			} else if (eventSlave.butt > 2) {
				t.push("fat cat ass.");
			} else {
				t.push("slender kitten rear.");
			}
			App.Events.addParagraph(node, t);
			t = [];
			t.push(`${He} twists ${his} head to look at you as though to say something, but you don't give ${him} the chance as you grab ${him} by the hips, not so much as bothering to spit down for the slightest semblance of lube, and slam ${PC.dick !== 0 ? "your cock" : "the strapon"} into the cat${girl}'s round, furry ass, forcing yourself past the resistance of ${his} sphincter. You ruthlessly pound ${eventSlave.slaveName}'s ${eventSlave.skin} butt, holding ${him} in place around the hips as`);
			if (PC.dick === 1) {
				if (eventSlave.dick > 0) {
					t.push(`your fat nuts batter ${his} pair into submission, bruising the low-hanging targets along with ${his} asshole with each extremely gay thrust. The violent, squirting orgasm ${he} has within a minute is probably no thanks to how hard you're busting ${his} furry balls with your own as you core out ${his} rear.`);
				}
			} else {
				t.push(`${He} squeals and mrowls, writhing against you as you pound ${his} ass into submission until ${he} jerks out with an explosive, wriggling squirtgasm against the floor.`);
			}
			t.push(`Shortly after, you ${PC.dick !== 0 ? `hilt yourself in the betacat's furry butt and shoot a half-dozen thick, hot ropes of cum up ${his} colon` : "achieve a powerful, mind-fogging orgasm yourself"}, pulling yourself free and releasing the annoying cat's hips. ${eventSlave.slaveName} gasps like ${he}'s out of oxygen, fluid dripping out from ${his} brutalized asshole, and yips out a brief, happy-sounding apology for being annoying.`);
			App.Events.addParagraph(node, t);
			t = [];

			eventSlave.devotion += 2;
			seX(eventSlave, "anal", V.PC, "penetrative");
			return t;
		}

		function stopIt() {
			let t = [];
			t.push(`You grab ${eventSlave.slaveName} by the hand and tell ${him} to stop being so goddamn annoying. ${He} cocks ${his} head at you, apparently genuinely confused, and then huffs out a loud exhale.`);
			if (canTalk(eventSlave)) {
				t.push(Spoken(eventSlave, `"Uh, sorry, ${title}, I wasn't trying to be annoying or anything..." ${He} mewls,`));
			} else {
				t.push(`${He} makes a second weird, apologetic sounding noise,`);
			}
			t.push(`then scurries off when you let ${him} go with ${his} <span class="trust dec">ears flat against ${his} head.</span>`);
			eventSlave.trust -= 3;
			return t;
		}

		function ignore() {
			let t = [];
			t.push(`You completely ignore ${eventSlave.slaveName} as ${he} mrowls at you and go about your day. You're far too busy to deal with some needy cat nonsense. ${eventSlave.slaveName} gets a little louder, and then louder still throughout the day, subtly demanding your attention for no particular reason, until ${he} finally gets that you're outright ignoring ${him} and trots off somewhere to sulk angrily at you not playing into ${his} childish - or at least animalistic - antics.`);
			eventSlave.devotion -= 3;
			return t;
		}
	}
};


code:
// cSpell:ignore doggishly

App.Events.CMRESSCatLove = class CMRESSCatLove extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [];
	}

	actorPrerequisites() {
		return [
			[ // single event slave
				s => s.fetish !== Fetish.MINDBROKEN,
				hasAnyArms,
				canMove,
				s => s.race === "catgirl",
				s => s.devotion > 90,
			]
		];
	}

	execute(node) {
		const [eventSlave] = this.actors.map(a => getSlave(a));
		const {
			He, he, his, His, him, himself, girl
		} = getPronouns(eventSlave);
		const {title} = getEnunciation(eventSlave);
		const PC = V.PC;

		App.Events.drawEventArt(node, eventSlave);

		let t = [];
		t.push(`As you walk out from the office to your bedroom late in the evening, ${eventSlave.slaveName} approaches you in the halls, holding something behind ${his} back with both hands. ${His} tail swishes nervously from side to side behind ${him}. The instant you open your mouth to ask what ${he}'s holding, the quivering cat${girl} thrusts out ${his} arms in front of ${him} to show you`);
		if (eventSlave.intelligence + eventSlave.intelligenceImplant > 80) {
			t.push("a beautiful, hand-drawn picture portraying you as a godlike figure above a large collection of distinct catgirl faces.");
			App.Events.addParagraph(node, t);

			t = [];
			t.push(`${eventSlave.slaveName} ${himself} is prominently displayed at the center of the catfolk at the bottom of the image, all of whom are looking up to you with big, worshipful smiles across their faces, pointed ears perked up. The bright golden hues make it look like a religious icon, but instead of a halo you're surrounded by two complex-looking genetic tubes; the faces of Dr. Nieskowitz and some other wizened scientists hang around you like angels. It's incredibly well-made, and even inlaid with a few sparkly things that seem to be whatever ${eventSlave.slaveName} could find lying around.`);
			if (canTalk(eventSlave)) {
				t.push(
					Spoken(eventSlave, `"I, uhm, wanted to make you something nice, ${title}..."`),
					`${eventSlave.slaveName} meows out sheepishly as ${he} holds the icon out towards you.`,
					Spoken(eventSlave, `"You made all of us, and um, well, you're so good and pretty and everything..." `)
				);
			} else {
				t.push(`${He} just holds out the icon, staring at you with big ${App.Desc.eyesColor(eventSlave)} that hope you get the meaning.`);
			}
			App.Events.addParagraph(node, t);
		} else if (eventSlave.intelligence + eventSlave.intelligenceImplant > 50) {
			t.push("an elegant, small clay sculpture portraying you surrounded by a few happy catgirls.");
			App.Events.addParagraph(node, t);

			t = [];
			t.push(`${He} holds the little sculpture out to you with wobbly hands, finding it hard to balance the unwieldy thing as you examine ${his} craftscatship. The sculpture is surprisingly pretty; one of the slaves around you is obviously supposed to be ${eventSlave.slaveName}, and they're all brushing up against you lovingly with individual expressions of happiness tediously moulded onto their faces.`);
			if (canTalk(eventSlave)) {
				t.push(
					Spoken(eventSlave, `"I thought you might like a better gift, so I found some clay in the workshop and made this, ${title}."`),
					`${eventSlave.slaveName} says, struggling to hold the awkward sculpture.`,
					Spoken(eventSlave, `"You're so nice to me and I like you so much, I, um, wanted to give you something to show how much I love you..." `)
				);
			} else {
				t.push(`${He} holds the sculpture out obediently as you examine it, ears twitching atop ${his} head as ${he} eagerly awaits your judgement.`);
			}
			App.Events.addParagraph(node, t);
		} else if (eventSlave.intelligence + eventSlave.intelligenceImplant > 35) {
			t.push("a pretty drawing of the two of you cuddling one another happily.");
			App.Events.addParagraph(node, t);

			t = [];
			t.push(`${He} displays the drawing proudly. It's surprisingly well-drawn, especially considering ${his} awkward, furry hands, and ${he}'s rendered all your features flatteringly with ${eventSlave.slaveName} lovingly cradling up against your chest like an old-world girlfriend. It's obvious that ${he}'s put a lot of work into drawing this, likely in ${his} spare time after finishing the day's assignments.`);
			if (canTalk(eventSlave)) {
				t.push(
					Spoken(eventSlave, `"I hope you like it, ${title}!"`),
					`${eventSlave.slaveName} says, eagerly watching your face as you study the nice drawing.`,
					Spoken(eventSlave, `"I worked really hard on it, but it's okay, because I got to look at your face the whole time, and you're extremely pretty, ${title}..."`)
				);
			} else {
				t.push(`${He} holds the drawing out enthusiastically, obviously proud of ${his} work and silently waiting for you to decide whether you're proud of it too.`);
			}
			App.Events.addParagraph(node, t);
		} else {
			t.push("a heart cut out of red construction paper showing crude figures of you and a catgirl holding hands and smiling.");
			App.Events.addParagraph(node, t);

			t = [];
			t.push(`Upon closer inspection, the crude cat figure is clearly intended to be ${eventSlave.slaveName}, and the two of you are standing above big white text written in what looks like crayon reading "I LUV U ${V.PC.title !== 0 ? `MASTER` : `MISTRESS`}". ${eventSlave.slaveName} trembles a little as you look at the simple drawing.`);
			if (canTalk(eventSlave)) {
				t.push(
					Spoken(eventSlave, `"I'm s-sorry ${title}..."`),
					`${eventSlave.slaveName} meows weakly, still holding out ${his} heart.`,
					Spoken(eventSlave, `"I w-wanted to make you something pretty like everybody else because I love you so m-much, but I can't draw good like them, ${title}... I h-hope you like it..."`)
				);
			} else {
				t.push(`${He} holds his little paper heart out for you, staring at you with big wide ${App.Desc.eyesColor(eventSlave)} as ${his} ears flatten preemptively, apparently expecting you to hate the crude offering.`);
			}
			App.Events.addParagraph(node, t);
		}

		App.Events.addResponses(node, [
			new App.Events.Result(`Tell ${him} that ${he} can show ${his} devotion best with a heartfelt ${PC.dick !== 0 ? "blowjob" : "cunnilingus session"}`, blowjob),
			new App.Events.Result(`Take the present and let ${him} cuddle up to you`, cuddle),
			new App.Events.Result(`Hang it in your display case`, displaycase),
			new App.Events.Result(`Tear it in two, scold ${him} for wasting time making worthless trinkets, and tell ${him} to get back to work`, breakheart),
		]);

		function blowjob() {
			let t = [];
			t.push(`You take ${eventSlave.slaveName}'s present and tell ${him} that ${he} can better show you just how much ${he} cares by getting on ${his} knees and giving you ${PC.dick !== 0 ? "a blowjob" : "some pussy eating"} from the heart.`);
			if (eventSlave.sexualFlaw !== "hates oral") {
				t.push(`The cat${girl} flashes you a smile full of sharp feline fangs that makes you rethink your decision for a brief moment before ${he} squats down, pressing out ${his} ass far enough to give you a good view of those furry cheeks as ${he} works your pants down, and`);
				if (eventSlave.skill.oral >= 80) {
					if (PC.dick !== 0) {
						t.push(`gives you a magnificent, loving`);
						if (canPenetrateThroat(V.PC)) {
							t.push(`throatjob, taking your cock as far as it can bury itself in ${his} throat`);
						} else {
							t.push(`suck, teasing the entirety of your cock with ${his} tongue`);
						}
						t.push(`while working every last drop of cum out from your balls with ${his} soft, furry hands,`);
					} else {
						t.push(`eats you out skillfully and intensely, working ${his} rough cat tongue deep into your pussy until ${he} brings you to a shuddering orgasm,`);
					}
					t.push(`<span class="devotion inc">pointy ears twitching happily atop ${his} head the entire time.</span>`);
				} else if (eventSlave.skill.oral > 40) {
					if (PC.dick !== 0) {
						t.push(`gives you a skillful blowjob, carefully avoiding scratching your dick on ${his} fangs as ${he} soon`);
						if (canPenetrateThroat(V.PC)) {
							t.push(`brings you to a powerful orgasm down ${his} throat,`);
						} else {
							t.push(`fills ${his} mouth with your orgasm,`);
						}
					} else {
						t.push(`tonguefucks you hard, burying ${his} soft button nose against your clit as ${he} works out an orgasm from your pussy,`);
					}
					t.push(`<span class="devotion inc">fluffy tail waggling behind ${him} the whole time almost doggishly.</span>`);
				} else {
					t.push(`${PC.dick !== 0 ? `does ${his} best to give you a good blowjob, mostly nervously trying to avoid cutting your dick on ${his} sharp fangs until ${his} warm, amateurish mouth finally coaxes an orgasm out of you,` : `eats you out amateurishly, ${his} rough cat tongue scratching your folds slightly as ${he} twists it around to eventually bring you to orgasm,`}`);
					t.push(`<span class="devotion inc">pointy ears wiggling around on ${his} head lovingly the entire time.</span>`);
				}
				eventSlave.devotion += 2;
			} else {
				t.push(`${He} gives you a disgusted look owing to ${his} hate of oral, but nevertheless gets on ${his} knees and begrudgingly ${PC.dick !== 0 ? "gives you a powerful blowjob" : "eats you out passionately"}, wiping off ${his} mouth the second you cum.`);
				eventSlave.devotion -= 2;
			}
			seX(eventSlave, "oral", V.PC, "penetrative");
			return t;
		}

		function cuddle() {
			let t = [];
			t.push(`You gently take the handmade gift, pat ${eventSlave.slaveName} on ${his} fluffy head, and assure ${him} that it's beautiful. The cat${girl}'s entire face immediately lights up and ${he} launches ${himself} at you, wrapping ${his} furry arms around your waist in a hug so tight you have to place ${his} gift down on the ground to avoid dropping it. With the cat${girl} hugged so closely to your chest, you can hear ${him} purring like a motor against you, swishing ${his} tail around behind ${him} in the close embrace. ${He} doesn't say anything else, just lovingly purring against you until you free yourself from the devoted cat${girl}'s embrace to get back to work.`);
			eventSlave.trust += 5;
			eventSlave.devotion += 5;
			return t;
		}

		function displaycase() {
			let t = [];
			t.push(`You take ${eventSlave.slaveName} by the hand, still holding ${his} little present, and lead ${him} over to your office. As ${he} looks at you confused, you gingerly take the`);
			if (eventSlave.intelligence + eventSlave.intelligenceImplant > 80) {
				t.push(`beautiful icon from ${his} hand, open your display case with a twist of your private key, and place it inside. ${eventSlave.slaveName} takes a moment to process what's happening, then smiles wider than you've ever seen ${him} smile before and presses ${his} head against your chest.`);
				if (canTalk(eventSlave)) {
					t.push(Spoken(eventSlave, `"I'm so happy you like it, ${title}!",`));
				} else {
					t.push(`${He} purrs from the back of ${his} throat so intensely you can hear it against your heart,`);
				}
				t.push(`filled with <span class="trust inc">safety</span> and <span class="devotion inc">love from the bottom of ${his} heart.</span>`);
				addTrinket(`catgirl icon`, {name: eventSlave.slaveName, id:eventSlave.ID});
			} else if (eventSlave.intelligence + eventSlave.intelligenceImplant > 50) {
				t.push(`elegant clay sculpture from ${his} hands, open your display case with a twist of your private key, and place it inside. ${eventSlave.slaveName} takes a moment to process what's happening, then smiles wider than you've ever seen ${him} smile before and presses ${his} head against your chest, tears welling up in ${his} eyes.`);
				if (canTalk(eventSlave)) {
					t.push(
						Spoken(eventSlave, `"You're the best -- the best ${title} in the whole wide world, ${title}!"`),
						`${He} mrowls out while hugging you,`
					);
				} else {
					t.push(`${He} purrs from the back of ${his} throat so intensely you can hear it against your heart,`);
				}
				t.push(`filled with <span class="trust inc">safety</span> and <span class="devotion inc">love from the bottom of ${his} heart.</span>`);
				addTrinket(`cat clay sculpture`, {name: eventSlave.slaveName, id:eventSlave.ID});
			} else if (eventSlave.intelligence + eventSlave.intelligenceImplant > 35) {
				t.push(`pretty drawn picture from ${his} hands, open your display case with a twist of your private key, and place it inside. ${eventSlave.slaveName} takes a moment to process what's happening, then chokes out a shocked meow, opens ${his} mouth, half-meows again, and stutters. ${canTalk(eventSlave) ? `"Y-you really like it that much, ${title}?" ${He} squeaks, and then, tears forming in the corner of ${his} eyes, launches into a tight, warm hug around your waist.` : `Incapable of saying anything further, ${he} simply launches himself at you and hugs you so tight it nearly squeezes on your ribs, tears forming at the corner of ${his} eyes.`} ${He}'s filled with the kind of safety and love from the bottom of ${his} heart that only comes from genuine adoration.`);
				addTrinket(`cat drawing`, {name: eventSlave.slaveName, id:eventSlave.ID});
			} else {
				t.push(`construction paper heart from ${his} hands, open your display case with a twist of your private key, and place it inside. ${eventSlave.slaveName} looks at you, looks at the display case, looks back at you, and then suddenly breaks into tears.`);
				if (canTalk(eventSlave)) {
					t.push(
						Spoken(eventSlave, `"${title} -- I l-love you so much --"`),
						`${He} almost whimpers, before hugging ${himself} around your waist so tight it feels like ${he}'s squeezing down your ribs.`
					);
				} else {
					t.push(`${He} simply sobs for a few moments, then hugs you with so much furry warmth that you swear you can feel ${his} heart beating against yours.`);
				}
				t.push(`${He}'s filled with the kind of <span class="trust inc">safety</span> and <span class="devotion inc">love from the bottom of ${his} heart</span> that only comes from genuine adoration.`);
				addTrinket(`cat crayon`, {name: eventSlave.slaveName, id:eventSlave.ID});
			}
			eventSlave.trust += 20;
			eventSlave.devotion += 20;
			return t;
		}

		function breakheart() {
			let t = [];
			t.push(`You take the loving gift from the quivering cat${girl}'s hands, tear it in half in a single, explosive motion, and let the two ripped pieces fall to the ground. ${eventSlave.slaveName} stares at you bewildered for a second before tears start to well up at the corners of ${his} eyes. As you open your mouth to scold ${him}, ${he} starts sobbing uncontrollably, crying in loud, ugly bawls that make it completely impossible to speak. When you order ${him} to stop, ${he} turns away from you, still sobbing, and sprints out of the hallway while some of your other slaves watch with a mixture of terror and shock on their faces. One of them trots off behind the bawling cat, probably either to comfort ${him} or rape ${him} while ${he}'s vulnerable. Irritated, you set a note for yourself to harshly punish the disobedient catslave later.`);
			eventSlave.trust -= 10;
			eventSlave.devotion -= 40;
			return t;
		}
	}
};

repo_name: Nithhogg/fc

license: mit


code:
App.Events.RESosBombing = class RESosBombing extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.seeCats !== 0,
			() => V.projectN.status > 4
		];
	}

	execute(node) {
		let r = [];
		const impRaid = () => raidOutcome("Imperial Knights");
		const romanRaid = () => raidOutcome("Roman");
		const mercenaries = () => raidOutcome("Mercenaries");
		const standard = () => raidOutcome("Standard");
		const bombPlotHappened = either(1, 2, 3, 4) === 1;
		App.UI.StoryCaption.encyclopedia = "The Sons of Sekhmet";

		r.push(`While working at your desk, your security team sends you an urgently-marked bulletin. The security update enclosed is fairly simple; the security staff think they've got a "reasonable lead" on a potential terrorist operation by the Sons of Sekhmet to bomb a few essential locations in the arcology, sometime in the next few days.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`Although they're not positive, they're requesting a few thousand credits in additional funding for the resources they'll need to properly investigate the potential cell and launch a raid. Although a public operation would no doubt look bad in the public eye if it failed to produce results, not to mention the money you'd spend, ignoring the potential of a bombing campaign could be absolutely disastrous - and cost you many times more that whatever you'd spend shutting down Sekhmeti cells. Ultimately, though, the decision on whether to give the raid the go-ahead or not is up to you.`);
		App.Events.addParagraph(node, r);
		r = [];

		const choices = [];
		if (V.arcologies[0].FSNeoImperialistLaw1 === 1) {
			choices.push(new App.Events.Result(`Authorize the raid, but give your Imperial Knights authority over it`, impRaid));
		}
		if (V.arcologies[0].FSRomanRevivalistLaw === 1) {
			choices.push(new App.Events.Result(`Authorize the raid, but delegate it to your armed citizens instead of the security team`, romanRaid));
		}
		if (V.mercenaries === 5) {
			choices.push(new App.Events.Result(`Authorize the raid, but transfer authority to your ${V.mercenariesTitle}`, mercenaries));
		}
		choices.push(new App.Events.Result(`Authorize the raid with standard drones and guard officers`, standard));
		choices.push(new App.Events.Result(`Refuse authorization`, refuse));
		App.Events.addResponses(node, choices);

		function refuse() {
			const frag = new DocumentFragment();
			let r = [];
			if (bombPlotHappened) {
				r.push(`You tell the security team to stop chasing ghosts and focus on real issues in the arcology. Two days later, while you're working in your office, a distant booming sound rumbles out from outside the penthouse. Turning to look out the window, you see a column of smoke coming up from the marketplace, and the distant glow of a raging flame. A few seconds later, another muffled boom rings out, this time from the direction of the plaza, and then a third, and a fourth. Sounds of gunshots in the distance ring out shortly afterwards. From here, there's nothing you can do but watch as the series of explosions devastates the arcology's hard-built prosperity - and its citizens. This time wasn't just a fluke, it seems. You don't even need to turn on the TV to imagine what the media is already saying about your failure to stop this attack before it happened. It's not going to be good.`);
				V.arcologies[0].prosperity -= 5;
				cashX(-24000, "event");
				repX(-5000, "event");
			} else {
				r.push(`You tell the security team to stop chasing ghosts and focus on real issues in the arcology. A few days later, someone from the team bashfully sends you an "update" bulletin notifying you that it was a false alarm after all and they'd just gotten worked up over some intimidating posts on social media.`);
			}
			App.Events.addParagraph(frag, r);
			return frag;
		}

		/**
		 * @param {string} operationalCommand
		 * @returns {DocumentFragment}
		 */
		function raidOutcome(operationalCommand) {
			const frag = new DocumentFragment();
			const r = ["You authorize the raid"];
			switch (operationalCommand) {
				case "Imperial Knights":
					r.push("but bring in your Knights to captain the effort.");
					break;
				case "Roman":
					r.push("but transfer authority for its execution over to a group of loyal, free citizens, who are all too eager to defend the Republic.");
					break;
				case "Mercenaries":
					r.push(`but head up the effort with your better-trained ${V.mercenariesTitle}.`);
					break;
				case "Standard":
					r.push("with no further comments.");
			}

			r.push("Early in the morning the next day,");
			switch (operationalCommand) {
				case "Imperial Knights":
					if (bombPlotHappened) {
						r.push(`the heavily-armed Knights burst into an old warehouse in the lower sectors, interrupting a group of Sekhmeti terrorists building a series of improvised bombs on a bunch of turned-over crates. As the bombmakers scramble for their weapons, your Knights absolutely slaughter the group, blasting the scene to pieces with heavy firepower and shrugging off the helpless potshots the terrorists make with their ultra-heavy Imperial Plate. Although the overzealous Knights don't leave you anything left to enslave, the media are on the scene within minutes, and the interviews with smiling, unscathed Knights in their elegant coats of armor in front of the scene of an utterly destroyed terrorist cell is a good look for your arcology.`);
					} else {
						r.push(`the heavily-armed Knights burst into a small apartment in the lower sectors, nearly giving the old woman in the living room a heart attack. Multiple men in ultra-heavy Imperial Plate all but burst through the walls of the apartment to tackle a single scrawny teenager in his room before they realize that this place probably isn't a radical Sons of Sekhmet cell. Even though this raid ended up being wasted money, your Knights eloquently apologize to the edgy teenager they nearly crushed, and your arcology loves the romanticized Knights enough that there's no lasting reputation damage from the unfortunate raid.`);
					}
					break;
				case "Roman":
					if (bombPlotHappened) {
						r.push(`a group of Praetorians in full gear burst into a small apartment in the lower sectors, interrupting a small group of Sekhmeti terrorists building a series of improvised bombs in the barren living room. Before the bombmakers can even grab their guns, the well-disciplined citizens gun them down in an explosive hail of fire, killing the whole cluster indiscriminately. Although the zealous citizenry don't leave anything left for you to enslave, a group of proud, well-trained free citizens voluntarily defending the arcology from a terrorist plot - and doing so without so much as a scratch - is a good look.`);
					} else {
						r.push(`a group of Praetorians in full gear burst into a dilapidated warehouse in the lower sectors, shocking the small group of transport workers carrying crates around for some secondhand shipment. Although the citizens nearly fire on the rough-looking warehouse hands, they realize that this isn't a group of Sekhmeti radicals before they do and apologize for the insurrection. Although this raid ultimately turned out to be wasted money, the free citizens conducting it and their disciplined Roman nature prevents any lasting reputation damage.`);
					}
					break;
				case "Mercenaries":
					if (bombPlotHappened) {
						r.push(`the deadly mercenaries kick down the door of a small office building in the lower sectors, interrupting a group of Sekhmeti terrorists in the middle of constructing a series of improvised bombs in the converted office space. The ${V.mercenariesTitle} blow the entire group to pieces with high-power weaponry, absolutely annihilating the careful plot with overwhelming force and indiscriminate destruction before they can fire off a single shot. Although the rough mercenaries don't leave anything left for you to enslave, the well-trained mercs emerging from the smoldering ruin of what used to be a terrorist field HQ is a good look for the security of your arcology.`);
					} else {
						r.push(`the deadly mercenaries burst into the back of a small shop in the lower sectors, nearly giving the lower-class workers heart attacks with the sudden appearance of their scarred - over faces in full battle gear. Although they tackle two of the poor workers to the ground, it doesn't take the ${V.mercenariesTitle} long to realize that this isn't a radical Sons of Sekhmet terrorist cell, and they leave before the media can show up to report on it. Even though this raid turned out to be wasted money, your mercenaries conduct themselves well enough that there's no lasting reputation damage.`);
					}
					break;
				case "Standard":
					if (bombPlotHappened) {
						r.push(`a group of security officers burst into the back of a small shop in the lower sectors, interrupting a group of Sekhmeti terrorists in the middle of constructing a series of improvised bombs, having removed all the machinery from the back of the shop to make space. The drones fire their tasers at the Sons, but they're better-armed and trained than to get so easily disabled, and your officers and the bombmakers get drawn into a prolonged firefight over the next ten minutes that draws arcology media to the scene like a candle. Although a few of the officers involved limp out with bullet wounds and slashes, they manage to completely eradicate the terrorist cell, and brave officers coming out from the destroyed Sekhmeti HQ is a good look, even if they didn't manage to leave you any of the terrorists alive to enslave.`);
					} else {
						r.push(`a group of security officers kick down the door of a small office building in the lower sectors, practically giving the workers inside heart attacks. One of the drones misinterprets a panicked worker dropping a file as an aggressive action and tases him, much to the chagrin of the rest of the officer team. Arcology media is on the scene in minutes, and on top of being a waste of money, you've also got a PR nightmare on your hands as the tased worker complains on live media about the "unfair paranoia" of the arcology and how much his taser burns hurt. What a shit-show.`);
					}
			}

			if (operationalCommand !== "Standard" && bombPlotHappened) {
				repX(2500, "event");
			} else {
				repX((bombPlotHappened ? 1500 : -500), "event");
			}

			cashX(-5000, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}
	}
};


code:
// cSpell:ignore damk, Sakhmat, Abna

App.Events.RESosSniper = class RESosSniper extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.seeCats !== 0,
			() => V.projectN.status > 4
		];
	}

	execute(node) {
		let r = new SpacedTextAccumulator(node);
		let gameover = false;

		App.UI.StoryCaption.encyclopedia = "The Sons of Sekhmet";

		if (S.Bodyguard) {
			App.Events.drawEventArt(node, S.Bodyguard);
		}
		const {
			He,
			he, his,
		} = getPronouns(S.Bodyguard ? S.Bodyguard : {pronoun: App.Data.Pronouns.Kind.neutral});

		const slave = GenerateNewSlave(null, {minAge: 18, maxAge: 32, disableDisability: 1});
		generateSalonModifications(slave);
		slave.face = random(50, 100);
		slave.origin = "$He was an elite sniper of the Sons of Sekhmet, nearly successful in assassinating you with a long-range shot from across the arcology before being captured by your Imperial Knights in a tense shootout.";
		slave.intelligenceImplant = 30;
		slave.career = "a sniper";
		slave.skill.combat = 70;
		slave.devotion = -100;
		slave.trust = random(-20, 10);
		slave.weight = random(-20, 30);
		slave.muscles = random(20, 80);
		slave.waist = random(10, 80);
		eyeSurgery(slave, "both", "normal");
		slave.shouldersTat = either("flowers", "tribal patterns", "asian art");
		slave.custom.tattoo = "$He has the orange sun of the Sons of Sekhmet tattooed on $his neck, marking $him as a high-ranking operative.";

		r.push(`It's a particularly nice day out and you've decided to visit some of the more prominent citizens of your arcology, the kind of people you might call 'friends' if genuine friendship wasn't a quick way to get stabbed in the back in the Free Cities. As you're having a pleasant conversation with one of these notables on the raised porch of his luxurious apartment, ${V.assistant.name} pings you with an urgent message: DUCK.`);
		r.toParagraph();

		if (V.PC.skill.warfare >= 60) {
			r.push(`You don't even think about it. Combat reflexes kicking in, you dive onto the ground as something whizzes past your head close enough to shave off a lock of hair, slamming into the ground next to you with enough force to shatter the wood. Before you consciously realize what's going on, your body understands that you're being shot at,`);
			if (S.Bodyguard) {
				r.push(`${S.Bodyguard.slaveName} helping you up and shielding you with ${his} body as you're hustled into the citizen's apartment with the citizen himself.`);
			} else {
				r.push(`leaping up and springing towards the citizen's apartment with the frightened man himself.`);
			}
			r.push(`Two more shots slam into the wood around you as you all but leap into the citizen's apartment, one more bullet splintering the wood of the door as you close it shut behind you.`);
		} else if (!S.Bodyguard || S.Bodyguard.intelligence + S.Bodyguard.intelligenceImplant <= 60) {
			r.push(`You blink once at the strange message. That's the extent of time it takes for the .50 caliber bullet travelling through the air from halfway across the arcology to impact the front of your head and exit through the back, splattering your brains into a fine gray goop across the suit of the citizen you were speaking with seconds ago. On the bright side, your death is instantaneous, unexpected, and totally painless, given that your head is essentially ripped off your body with the force of the sniper round.`);
			gameover = true;
		} else {
			r.push(`You blink once at the message in confusion before ${S.Bodyguard.slaveName} tackles you, ${his} shoulder bursting out with an explosion of red as ${he} catches a bullet clearly meant for you. ${He} cries out in pain, but it doesn't look like the hit was lethal; even injured and bleeding, ${he} shields you as you hustle into the open apartment along with the spooked citizen, more shots impacting around you as you wildly scramble into cover. A final bullet splinters the wood of the door as you close it shut behind you.`);
			cashX(-1000, "event", S.Bodyguard);
			healthDamage(S.Bodyguard, 60);
		}
		r.toParagraph();

		if (gameover) {
			r.push(`The next day the Sons of Sekhmet release a propaganda video featuring graphic footage of your death as a "victory against the decadent anarcho-tyrannies of the New World". The other silver lining to all this is that you aren't there to see the violence and strife that immediately erupts between your arcology's forces and the Sekhmeti cells nearby in the wake of your death.`);
			r.toParagraph();
			App.Events.LocalGameOver(node);
		} else {
			r.push(`As you pant in the wake of the sudden attack, ${V.assistant.name} notifies you that they've traced the origin of the shots to somewhere in Sector Three. Having missed the killing shot, the sniper is undoubtedly packing up and moving to leave right now. You'll have to get a search party moving immediately if you want any hope of tracking them down.`);
			r.toParagraph();

			const choices = [];
			if (V.arcologies[0].FSNeoImperialistLaw1 === 1) {
				choices.push(new App.Events.Result(`Lock down the sector and notify your Imperial Knights to lead citizens out in searching for the shooter`, impResponse));
			}
			if (V.arcologies[0].FSRomanRevivalistLaw === 1) {
				choices.push(new App.Events.Result(`Lock down the sector and notify your Praetorians to lead the citizens out in searching for the shooter`, romanResponse));
			}
			if (V.mercenaries === 5) {
				choices.push(new App.Events.Result(`Lock down the sector and notify your ${V.mercenariesTitle} to send in hunter-killer teams`, mercResponse));
			}
			choices.push(new App.Events.Result(`Just lock down the sector and send out search parties for the shooter`, lockdown));

			App.Events.addResponses(node, choices);
		}

		function impResponse() {
			let r = new SpacedTextAccumulator();
			let sniperEscape;
			if (either(1, 2, 3) === 1) {
				sniperEscape = 1;
				r.push(`After a few hours of searching, your brightly-painted Knights return empty-handed, cursing that it was like no one was ever there.`);
			} else if (random(1, 2) === 1) {
				sniperEscape = 2;
				r.push(`After maybe thirty minutes, you hear loud gunfire coming from the sector where your Knights are searching. About five minutes later, a Knight in bright red armor brings you a body slung over his shoulder and thumps it in the ground in front of you, riddled in bullet holes and marked with the logo of the Sons of Sekhmet. "We got the bastard, m'lord." The Knight drawls. With his other hand, he tosses a broken sniper rifle next to the corpse.`);
			} else {
				sniperEscape = 3;
				r.push(`After maybe thirty minutes, you hear loud gunfire coming from the sector where your Knights are searching. About five minutes later, a Knight in bright red armor brings you a captive bound heavily with iron shackles, covered in body armor bearing the logo of the Sons of Sekhmet. In his other hand, he tosses a broken sniper rifle on the ground in front of you.`);
			}
			r.toParagraph();
			if (sniperEscape === 1) {
				r.push(`The assassination attempt and subsequent escape has scared many of your citizens, even after you pay for the damage the sniper bullets caused to the wealthy elite's property. A few days later, a trader passing by the arcology hands you an envelope, saying that he was told to pass it onto you. Inside is a single slip of paper, totally blank except for a single line of text: "See you soon." The envelope is emblazoned with the logo of an orange sun.`);
				V.arcologies[0].prosperity -= 1;
				repX(-2000, "event");
			} else if (sniperEscape === 2) {
				r.push(`Surviving the assassination attempt and killing the assassin earns you admiration of the citizenry, who see you as strong for punishing the assassin, particularly after you pay for the damage the sniper bullets caused to the wealthy elite's property. The next day, the Sons of Sekhmet release a 'news' update featuring their balaclava-wearing figurehead in front of his professional desk.`);
				r.toParagraph();
				r.push(`"Today a servant of Sekhmet was martyred while making an attempt on the life of a hedonistic new-world plutocrat. This was not the first attempt we have made, and it will not be the last. Next time, we will inscribe his name on the bullet that finishes the job. Abna Sakhmat damk-" You turn off the report. That's about all you need to see.`);
				V.arcologies[0].prosperity += 1;
				repX(2000, "event");
			} else if (sniperEscape === 3) {
				r.push(`Surviving the assassination attempt and capturing the assassin earns you admiration of the citizenry, who see you as strong for punishing the assassin, particularly after you pay for the damage the sniper bullets caused to the wealthy elite's property. The next day, the Sons of Sekhmet release a 'news' update featuring their balaclava-wearing figurehead in front of his professional desk.`);
				r.toParagraph();
				r.push(`"Today a servant of Sekhmet was martyred while making an attempt on the life of a hedonistic new-world plutocrat. The enemy has captured one of ours - in time we will free them, or perhaps they will awake to find a dagger in their back. Soon, they will understand the grave mistake of taking a Son into their ranks, even as a slave. Abna Sakhmat damk-" You turn off the report. That's about all you need to see.`);
				V.arcologies[0].prosperity += 1;
				repX(2000, "event");
				newSlave(slave);
			}
			r.toParagraph();
			return r.container();
		}

		function romanResponse() {
			let r = new SpacedTextAccumulator();
			let sniperEscape;
			if (either(1, 2, 3) === 1) {
				sniperEscape = 1;
				r.push(`After a few hours of searching, your armed Praetorian citizens return empty-handed, cursing that it was like no one was ever there.`);
			} else if (random(1, 2) === 1) {
				sniperEscape = 2;
				r.push(`After maybe thirty minutes, you hear loud gunfire coming from the sector where your citizens are searching. About five minutes later, a group of rough-looking Hastati citizens bring you a body slung over his shoulder and thumps it in the ground in front of you, riddled in bullet holes and marked with the logo of the Sons of Sekhmet. "We got the filth." The Hastati carrying the body enunciates. With his other hand, he tosses a broken sniper rifle next to the corpse.`);
			} else {
				sniperEscape = 3;
				r.push(`After maybe thirty minutes, you hear loud gunfire coming from the sector where your citizens are searching. About five minutes later, a group of rough-looking Hastati citizens bring you a captive bound heavily with iron shackles, covered in body armor bearing the logo of the Sons of Sekhmet. In his other hand, he tosses a broken sniper rifle on the ground in front of you.`);
			}
			r.toParagraph();
			if (sniperEscape === 1) {
				r.push(`The assassination attempt and subsequent escape has scared many of your citizens, even after you pay for the damage the sniper bullets caused to the wealthy elite's property. A few days later, a trader passing by the arcology hands you an envelope, saying that he was told to pass it onto you. Inside is a single slip of paper, totally blank except for a single line of text: "See you soon." The envelope is emblazoned with the logo of an orange sun.`);
				V.arcologies[0].prosperity -= 1;
				repX(-2000, "event");
			} else if (sniperEscape === 2) {
				r.push(`Surviving the assassination attempt and killing the assassin earns you admiration of the citizenry, who see you as strong for punishing the assassin, particularly after you pay for the damage the sniper bullets caused to the wealthy elite's property. The next day, the Sons of Sekhmet release a 'news' update featuring their balaclava-wearing figurehead in front of his professional desk.`);
				r.toParagraph();
				r.push(`"Today a servant of Sekhmet was martyred while making an attempt on the life of a hedonistic new-world plutocrat. This was not the first attempt we have made, and it will not be the last. Next time, we will inscribe his name on the bullet that finishes the job. Abna Sakhmat damk-" You turn off the report. That's about all you need to see.`);
				V.arcologies[0].prosperity += 1;
				repX(2000, "event");
			} else if (sniperEscape === 3) {
				r.push(`Surviving the assassination attempt and capturing the assassin earns you admiration of the citizenry, who see you as strong for punishing the assassin, particularly after you pay for the damage the sniper bullets caused to the wealthy elite's property. The next day, the Sons of Sekhmet release a 'news' update featuring their balaclava-wearing figurehead in front of his professional desk.`);
				r.toParagraph();
				r.push(`"Today a servant of Sekhmet was martyred while making an attempt on the life of a hedonistic new-world plutocrat. The enemy has captured one of ours - in time we will free them, or perhaps they will awake to find a dagger in their back. Soon, they will understand the grave mistake of taking a Son into their ranks, even as a slave. Abna Sakhmat damk-" You turn off the report. That's about all you need to see.`);
				V.arcologies[0].prosperity += 1;
				repX(2000, "event");
				newSlave(slave);
			}
			r.toParagraph();
			return r.container();
		}

		function mercResponse() {
			let r = new SpacedTextAccumulator();
			let sniperEscape;
			if (either(1, 2, 3) === 1) {
				sniperEscape = 1;
				r.push(`After a few hours of searching, your ${V.mercenariesTitle} return empty-handed, cursing that it was like no one was ever there.`);
			} else if (random(1, 2) === 1) {
				sniperEscape = 2;
				r.push(`After maybe thirty minutes, you hear loud gunfire coming from the sector where your ${V.mercenariesTitle} are searching. About five minutes later, a small squad of heavily-armored mercenaries bring you a body, dragging it in the ground in front of you, riddled in bullet holes and marked with the logo of the Sons of Sekhmet. "We got the fucker." The sergeant of the mercenary squad grumbles. With his other hand, he tosses a broken sniper rifle next to the corpse.`);
			} else {
				sniperEscape = 3;
				r.push(`After maybe thirty minutes, you hear loud gunfire coming from the sector where your ${V.mercenariesTitle} are searching. About five minutes later, a small squad of heavily-armored mercenaries bring you a captive bound heavily with iron shackles, covered in body armor bearing the logo of the Sons of Sekhmet. One of the tosses a broken sniper rifle on the ground in front of you.`);
			}
			r.toParagraph();
			if (sniperEscape === 1) {
				r.push(`The assassination attempt and subsequent escape has scared many of your citizens, even after you pay for the damage the sniper bullets caused to the wealthy elite's property. A few days later, a trader passing by the arcology hands you an envelope, saying that he was told to pass it onto you. Inside is a single slip of paper, totally blank except for a single line of text: "See you soon." The envelope is emblazoned with the logo of an orange sun.`);
				V.arcologies[0].prosperity -= 1;
				repX(-2000, "event");
			} else if (sniperEscape === 2) {
				r.push(`Surviving the assassination attempt and killing the assassin earns you admiration of the citizenry, who see you as strong for punishing the assassin, particularly after you pay for the damage the sniper bullets caused to the wealthy elite's property. The next day, the Sons of Sekhmet release a 'news' update featuring their balaclava-wearing figurehead in front of his professional desk.`);
				r.toParagraph();
				r.push(`"Today a servant of Sekhmet was martyred while making an attempt on the life of a hedonistic new-world plutocrat. This was not the first attempt we have made, and it will not be the last. Next time, we will inscribe his name on the bullet that finishes the job. Abna Sakhmat damk-" You turn off the report. That's about all you need to see.`);
				V.arcologies[0].prosperity += 1;
				repX(2000, "event");
			} else if (sniperEscape === 3) {
				r.push(`Surviving the assassination attempt and capturing the assassin earns you admiration of the citizenry, who see you as strong for punishing the assassin, particularly after you pay for the damage the sniper bullets caused to the wealthy elite's property. The next day, the Sons of Sekhmet release a 'news' update featuring their balaclava-wearing figurehead in front of his professional desk.`);
				r.toParagraph();
				r.push(`"Today a servant of Sekhmet was martyred while making an attempt on the life of a hedonistic new-world plutocrat. The enemy has captured one of ours - in time we will free them, or perhaps they will awake to find a dagger in their back. Soon, they will understand the grave mistake of taking a Son into their ranks, even as a slave. Abna Sakhmat damk-" You turn off the report. That's about all you need to see.`);
				V.arcologies[0].prosperity += 1;
				repX(2000, "event");
				newSlave(slave);
			}
			r.toParagraph();
			return r.container();
		}

		function lockdown() {
			let r = [];
			r.push(`After a few hours of searching, your guards return empty-handed, cursing that it was like no one was ever there. The assassination attempt and subsequent escape has scared many of your citizens, even after you pay for the damage the sniper bullets caused to the wealthy elite's property. A few days later, a trader passing by the arcology hands you an envelope, saying that he was told to pass it onto you. Inside is a single slip of paper, totally blank except for a single line of text: "See you soon." The envelope is emblazoned with the logo of an orange sun.`);
			V.arcologies[0].prosperity -= 1;
			repX(-2000, "event");
			return r;
		}
	}
};


code:
App.Events.SEProjectNBubbles = class SEProjectNBubbles extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.projectN.status === 3,
			() =>	(V.projectN.wellFunded === 1 && App.Events.effectiveWeek() >= V.projectN.phase2 + 4) ||
					(V.projectN.wellFunded !== 1 && App.Events.effectiveWeek() >= V.projectN.phase2 + 6)
		];
	}

	execute(node) {
		V.projectN.status = 4;
		V.projectN.phase3 = App.Events.effectiveWeek();

		App.Events.addParagraph(node, [`You check in on the genelab, and are pleased to see that project N is making a great deal of progress. What was once an indistinguishable fleshy mass in a tube of mysterious green liquid looks now more like a small, unconscious humanoid body, pink-fleshed and nude, with a set of pointy triangular ears atop its bald head that vaguely resemble a cat. Doctor Nieskowitz steps up to you as you examine the growing body, actually smiling for once.`]);
		App.Events.addParagraph(node, [`"Ah, I see you've seen our latest progress. I'm quite proud of the team's work so far, you know – five months ago I would have said this kind of genetic splicing was simply impossible. But there's no better scientific feeling than proving yourself wrong, eh? Anyway, we've started to refer to the subject as 'Bubbles', on account of the–" The doctor is interrupted by a slight thrashing movement from the unconscious body, which produces a short span of bubbling within the tube's liquid. "...well, that. But anyway, since you're funding the project and she'll be your property once we finish, I thought it best to ask you your opinion on the matter of a real name before we proceed any further."`]);

		App.Events.addResponses(node, [
			new App.Events.Result(`Bubbles is a good name`, bubbles),
			new App.Events.Result(`I had something else in mind`, rename)
		]);

		function bubbles() {
			return `You tell Nieskowitz that you like the name the scientists have chosen. He nods a couple times, jots something down in a notepad, and then returns to his work on subject delta - or, rather, on Bubbles.`;
		}

		function rename() {
			const frag = new DocumentFragment();
			App.Events.addParagraph(frag, [
				`You tell the waiting bioengineers that you'll be formally naming the growing catgirl `,
				App.UI.DOM.makeTextBox(V.subjectDeltaName, (v) => V.subjectDeltaName = v),
				`Nieskowitz nods, jots something down in a notepad, and then lets you know that he'll update you on the situation as it develops.`
			]);
			return frag;
		}
	}
};


code:
App.Events.SEProjectNInitialized = class SEProjectNInitialized extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.projectN.status === 1
		];
	}

	execute(node) {
		V.projectN.status = 2;
		V.projectN.phase1 = App.Events.effectiveWeek();

		App.Events.addParagraph(node, [`After giving the order to your personal assistant to begin preparations for your transhumanist genetic engineering project, you spend much of the next week getting in contact with the most renowned geneticists and biologists of the old world. Many of these gray-bearded intellectuals scoff as you initially explain your goal of making a 'catgirl', but change their tune almost immediately when you mention the paycheck attached. By the end of the week, you've acquired an impressive team of high-profile minds en route to the arcology, many of them already setting up workstations and tables full of imported chemicals within your laboratory.`]);
		App.Events.addParagraph(node, [`The first few days within the lab are spent organizing the new staff's structure; under your supervision, they create a formal research team headed by the ancient Doctor Nieskowitz, dubbed "Project N" both for the research head and as a dry joke by the ever-sardonic science team for their cat-focused intentions. As things begin to formalize into the process of initial research, you realize you've got a decision to make before you've even started the project itself - are you going to keep Project N a secret from the rest of your arcology, or immediately bring it out into the public eye?`]);

		const choices = [];
		choices.push(new App.Events.Result(`Announce Project N to the public`, announce));
		choices.push(new App.Events.Result(`Keep Project N quiet`, quiet));
		App.Events.addResponses(node, choices);

		function announce() {
			let r = [];
			r.push(`You hold a press release the next day with a number of prominent journalists in the arcology noting the research team that you've gathered for project N, and its intention to create the world's first fully natural catgirl. Even though you've got absolutely no results to show and the project is still in its fully theoretical stage, the attending journalists react to the news with obvious excitement and you spend the next few hours answering conceptual questions that run on arcology media for the next couple of days, which helps promote your public image. When you return to the lab, Dr. Nieskowitz is clearly irritated, telling you that the media attention is almost guaranteed to slow down progress in these early stages.`);
			if (FutureSocieties.isActive('FSBodyPurist')) {
				r.push(`This announcement absolutely <span class="red">horrifies</span> the body purists in your arcology.`);
			}
			repX(2000, "event");
			V.projectN.public = 1;
			V.bodyPuristRiot = 1;
			if (FutureSocieties.isActive('FSBodyPurist')) {
				repX(-4000, "event");
			}
			return r;
		}

		function quiet() {
			return `You opt to keep Project N on the down-low for now, probably the safer choice. Lack of media attention will surely make your scientists <span class="green"> work faster</span> undisturbed, too.`;
		}
	}
};


code:
App.Events.SEProjectNMoMoney = class SEProjectNMoMoney extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.projectN.status === 2,
			() => (V.projectN.public === 0 && App.Events.effectiveWeek() >= V.projectN.phase1 + 3) ||
				(V.projectN.public === 1 && App.Events.effectiveWeek() >= V.projectN.phase1 + 5)
		];
	}

	execute(node) {
		V.projectN.status = 0;
		V.projectN.phase2 = App.Events.effectiveWeek();

		App.Events.addParagraph(node, [`After a few weeks of theoretical designs and planning, the project N bioengineers finally have a set of results ready to present to you. Doctor Nieskowitz, heading up the team, presents you with a neat clipboard full of technical information as you enter the lab, telling you that he's got both good news and bad news.`]);
		App.Events.addParagraph(node, [`The balding man launches into the good news first. "We've got our first sample prepared, and we've begun physical work manipulating the growing genetic structure of the subject." Nieskowitz gestures behind him to one of the genetic tubes, a vat filled with thick green liquid, where a fist-sized cluster of pink flesh-like material floats in the center. "We call her subject Delta."`]);
		App.Events.addParagraph(node, [`"Unfortunately, it's not all rainbows and sunshine." Nieskowitz continues. "As it turns out, this work isn't going to be cheap. The initial cash injection let us get set up with our materials and provides the team a nice little paycheck, but we're going to need a lot more equipment to make this dream of yours a reality. We'll need top-line genetic sequencers, automated manipulation tools for precision physical work, a lot of new sterilization staff, complete AI integration with the equipment for constant monitoring..."`]);

		const askPrice = 220000;
		const adequatePrice = 125000;
		const barePrice = 50000;
		const choices = [];
		if (V.cash >= askPrice) {
			choices.push(new App.Events.Result(`Give Nieskowitz however much he wants`, unlimited, `equivalent to ${cashFormat(askPrice)}.`));
		}
		if (V.cash >= adequatePrice) {
			choices.push(new App.Events.Result(`Provide Project N with adequate funding`, adequate, `equivalent to ${cashFormat(adequatePrice)}.`));
		}
		if (V.cash >= barePrice) {
			choices.push(new App.Events.Result(`Give Project N the bare minimum to limp on`, bare, `equivalent to ${cashFormat(barePrice)}.`));
		}
		choices.push(new App.Events.Result(`Discontinue Project N`, cancel));
		App.Events.addResponses(node, choices);

		function unlimited() {
			cashX(-askPrice, "personalBusiness");
			V.projectN.status = 3;
			V.projectN.wellFunded = 1;
			return `You inform Nieskowitz that project N will have as much money as it needs. As the doctor starts rattling off necessities and upgrades to the genelab, the eventual list proves hugely expensive, but the good doctor assures you that the money spent - over double your initial investment - will make sure project N runs smoothly and rapidly.`;
		}

		function adequate() {
			cashX(-adequatePrice, "personalBusiness");
			V.projectN.status = 3;
			return `You agree to spend, the amount of money Nieskowitz requests, but set a strict budgetary limit for them to follow. The doctor seems pleased, and doesn't contest this ruling as he starts to prepare the expensive upgrades and redesigns that'll be needed to keep the project going at a steady rate.`;
		}

		function bare() {
			cashX(-barePrice, "personalBusiness");
			V.projectN.status = 3;
			V.projectN.poorlyFunded = 1;
			return `You give Nieskowitz the bare minimum budget needed to keep project N operational. The doctor seems obviously displeased and makes no effort to hide his frustration with your limited budget, noting that your stinginess will almost inevitably have consequences to the sensitive nature of their work. Time will tell if he's correct.`;
		}

		function cancel() {
			V.projectN.status = 0;
			return `You casually hand back the clipboard to Nieskowitz and tell him that you didn't plan on spending a cent more on project N - and still don't. As the frustrated biologists start to pack up their things, Nieskowitz tells you that if you "get your head out of your ass" they'll be available to resume work on the project, provided you have the money to fund it this time.`;
		}
	}
};


code:
App.Events.SEProjectNSaboteur = class SEProjectNSaboteur extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.projectN.status === 4,
			() => (V.projectN.poorlyFunded !== 1) && (App.Events.effectiveWeek() >= V.projectN.phase3 + 4) ||
				((V.projectN.public === 1) && (V.projectN.poorlyFunded === 1) && (App.Events.effectiveWeek() >= V.projectN.phase3 + 6))
		];
	}

	execute(node) {
		App.UI.StoryCaption.encyclopedia = "The Sons of Sekhmet";
		V.projectN.status = 9;
		V.projectN.phase4 = App.Events.effectiveWeek();

		App.Events.addParagraph(node, [`You're awoken in the middle of the night by your virtual assistant, informing you that there's a security breach in the genetics lab. It seems like a small team of well-trained saboteurs is currently in the process of planting an explosive on the project N equipment, detected via the AI's routine scanning of the entire arcology's camera system and noticing errors in the genetics lab consistent with outside interference.`]);
		App.Events.addParagraph(node, [`You're not going to be able to get down there in time yourself, but you'll need to respond quickly, or else whoever sent these armed radicals will blow the lab, destroying all your work on project N and potentially killing a number of the nearby scientists, too. Over the cameras, as your assistant brings them back online, you can see one of them hastily spraying the symbol of a rising sun on the outside of the genelab, along with a short phrase in red paint - "THE SONS OF SEKHMET HAVE YOUR BLOOD".`]);

		const choices = [];
		if (V.projectN.wellFunded === 1) {
			choices.push(new App.Events.Result(`Activate the lab's integrated security`, security));
		}
		if (V.mercenaries === 5) {
			choices.push(new App.Events.Result(`Send for your ${V.mercenariesTitle} to bring in a rapid-response bomb defusal team`, mercenaries));
		}
		choices.push(new App.Events.Result(`Desperately try to make it to the lab yourself in time`, yourself));
		App.Events.addResponses(node, choices);

		function security() {
			V.projectN.status = 5;
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You briefly thank your lucky stars that you invested enough in project N to provide for integrated security, then call for the lab's drones to activate. Over the cameras, you smugly watch from your comfortable bed as the security drones tear two of the mysterious saboteurs to shreds, then pin down and apprehend the third. Seems like all they managed to get you today was a brand new slave.`);
			repX(1500, "event");
			const slave = GenerateNewSlave(null, {minAge: 16, maxAge: 32, disableDisability: 1});
			generateSalonModifications(slave);
			slave.origin = "$He is an enslaved Son of Sekhmet, one of many idealistic rebel groups violently opposed to you.";
			slave.devotion = random(-90, -70);
			slave.trust = random(-20, 30);
			slave.weight = random(-20, 30);
			slave.muscles = random(20, 80);
			slave.waist = random(10, 80);
			r.push(App.UI.newSlaveIntro(slave));
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function mercenaries() {
			V.projectN.status = 5;
			return `You immediately call for your ${V.mercenariesTitle} to send a bomb defusal team to the lab, and be ready to fight with the saboteurs on arrival. In the few minutes it takes for them to assemble a QRF and send it rocketing up to your laboratory, the saboteurs have already planted their bomb and vanished out the genelab's doors, disappearing into the dead of night. The mercenary team arrives shortly afterwards, bursts through the doors, and disables the ticking bomb with less than a minute left on the clock. Panting and sweating with nerves rather than fatigue, one of them flashes you a thumbs-up over the security cameras. Crisis narrowly averted.`;
		}

		function yourself() {
			V.projectN.status = 9;
			return `As you sprint towards the lab, an ear-shatteringly loud explosion freezes you in your tracks. Pieces of rubble and glass rain down to your sides for a few seconds, as you watch flames engulf the majority of your genetics laboratory, bright reds and oranges staining your retinas. Most of the project N scientists slept in rooms attached to the lab itself - you don't even need to read your AI report to know that Nieskowitz and the core team are dead already. It'd shock you more if they hadn't died with the project they worked so hard to build.`;
		}
	}
};


code:
App.Events.SEProjectNTechRelease = class SEProjectNTechRelease extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.projectN.status >= 6,
			() => V.projectN.status !== 9,
			() => V.projectN.decisionMade !== 1,
			() => App.Events.effectiveWeek() >= V.projectN.phase4 + 5
		];
	}

	execute(node) {
		App.Events.addParagraph(node, [`Project N is complete. You've successfully engineered the world's first natural catgirl, ${V.subjectDeltaName}, whose face you occasionally see splayed out on some media report excitedly detailing "new scientific innovations". Despite the unwanted attention from radicals and terrorists the project generated, seeing your face displayed in the news as a patron of progress certainly helps to make it feel as though it was all worth it in the end.`]);
		App.Events.addParagraph(node, [`But even though the project's been finished, you still have one last decision to make. Media attention in the wake of ${V.subjectDeltaName}'s release has generated significant public interest in the technologies and documentation used in project N, and as the sole proprietor of the tech, you've received generous offers from other arcology owners interested in creating their own catgirls along with public petitions to release all documents for public use. If you don't release the project N tech now, it's possible that a competitor might figure out how to engineer their own catgirls in the future, so if you want to capitalize on the short-lived media craze for either public face or money, it'd be best to make a decision on the matter immediately.`]);

		const choices = [];
		choices.push(new App.Events.Result(`Release the Project N documentation and technology for free`, free));
		choices.push(new App.Events.Result(`Patent the Project N technologies and sell them selectively to other wealthy elites`, patent));
		choices.push(new App.Events.Result(`Hoard the Project N technologies to yourself to create a monopoly on catgirl production`, secret, `(WARNING: This decision will PERMANENTLY DISABLE any natural generation of catgirls outside the ones you create yourself.)`));
		App.Events.addResponses(node, choices);

		function free() {
			repX(3000, "event");
			V.projectN.decisionMade = 1;
			V.projectN.techReleased = 1;
			return `You opt to release the project N technologies for free public use, a decision you announce in a brief media conference the next day. The unexpectedly generous decision is met with praise by the general public, although, of course, the only people who have the capital to actually apply the tech will be other exclusive plutocrats. You're sure that at least some nerd in his basement is going to use your open-source code to try and grow a catgirl in his basement, though. Godspeed.`;
		}

		function patent() {
			cashX(80000, "project N tech sale");
			V.projectN.decisionMade = 1;
			V.projectN.techReleased = 1;
			return `You create a patent on the project N technologies and sell them to a select few arcology owners, mostly friends of yours. Although mildly disappointing to some who hoped for an open-source release, this is more or less business as usual in the free cities, and you get to line your own pockets while other elites prepare their own labs to corner the emerging demand for catgirl slaves alongside you. The rich get richer. Just another day in paradise.`;
		}

		function secret() {
			V.projectN.decisionMade = 1;
			repX(-1500, "event");
			return `You opt to leave the other elites completely out of it and refuse to sell or release the project N technologies at all. This decision is seen as open greed by both the general public and other wealthy elites, who make a point of bashing you over the choice on major news networks. Although you've ruffled some feathers by choosing to corner the market yourself, you now have a total monopoly on catgirl production, and as long as you can keep Nieskowitz and the other scientists churning out catgirls, you could make an absolute killing as their sole proprietor...`;
		}
	}
};


code:
App.Events.recRunawayCat = class recRunawayCat extends App.Events.BaseEvent {
	constructor(actors, params) {
		super(actors, params);
	}

	eventPrerequisites() {
		return [
			() => V.seeCats !== 0,
			() => V.projectN.techReleased !== 0,
			() => ((V.rep/400) > random(1, 100) || V.cheatMode === 1)
		];
	}

	get eventName() {
		return "Runaway Cat";
	}

	execute(node) {
		const slave = makeSlave();
		const {He, he, his, him, girl} = getPronouns(slave);
		let r = [];

		r.push(`Coming to your desk in the morning, you see that your assistant has noted that you have a 'pressing' piece of business to attend to. With a wave of your hand, you bring up the notification to see that a runaway slave has apparently been waiting outside your penthouse for the entire night. What's more, ${he}'s owned by a prominent rival arcology owner within the cluster - and ${he}'s a cat${girl}, to boot. Apparently, according to the short, hand-scrawled letter that ${V.assistant.name} has digitized into the notification, ${his} former master regularly beat ${him} both out of frustration and for pleasure, and ${he}'s approached you hoping for a better life in the slavery that's defined ${his} existence.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`The exclusive and novel nature of cat${girl}s makes ${him} an exceptionally valuable slave, and the genetic modification that created ${him} has ensured that the feline face you look over in the automated overview is particularly attractive, but taking ${him} under your wing away from another wealthy plutocrat would cause a whole score of problems. Deciding it'd be best not to make more enemies than you have to, you call up the rival on your personal phone, who answers after only a few seconds. After you explain the situation, the abusive oligarch chuckles, admits that he hadn't even noticed the cat${girl} leaving, and says he'll formally sell ${him} over to you for "just" twenty thousand credits. Otherwise, he'll give you a little cash to show his appreciation for sending the runaway back home.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(App.UI.DOM.makeElement("span", `The other oligarch's offer is a pretty heavy ${cashFormat(20000)}, although his cat${girl} slave is pretty, young, and seems fairly well-trained. ${He}'s still got a few scars from regular abuse, though, both mental and physical, and despite ${his} offer of self-enslavement seems exceptionally skittish and scared around you.`, "note"));

		App.Events.addParagraph(node, r);
		const contractCost = 20000;
		const cost = slaveCost(slave) - contractCost;
		const responses = [];
		if (V.cash >= contractCost) {
			responses.push(new App.Events.Result(`Enslave ${him}`, enslave));
		} else {
			responses.push(new App.Events.Result(null, null, `You lack the necessary funds to enslave ${him}`));
		}
		responses.push(new App.Events.Result(`Return ${him} to ${his} owner`, sell, `This will bring in ${cashFormat(cost)}`));

		node.append(App.Desc.longSlave(slave, {market: "generic"}));

		App.Events.addResponses(node, responses);

		function enslave() {
			const el = new DocumentFragment();
			let r = [];
			cashX(forceNeg(contractCost), "slaveTransfer", slave);
			r.push(`You agree to the other plutocrat's offer and after a quick transfer of credits between your private lines, he casually congratulates you on your new slave, makes a joke about sloppy seconds, and hangs up. You call down for a guard outside to bring the skittish new cat${girl} up to your office so you can get your fresh new slave better introduced into your harem.`);
			r.push(App.UI.newSlaveIntro(slave));
			App.Events.addNode(el, r);
			return el;
		}

		function sell() {
			const el = new DocumentFragment();
			let r = [];
			cashX(cost, "slaveTransfer");
			r.push(`You shrug to yourself and tell the other oligarch you'll send ${him} back over. The rival plutocrat tells you that he'll send you offer a little 'gift' to show his appreciation as you hang up and order some of the arcology guards to take the nervous cat${girl} outside away. A few days later, the abusive oligarch makes good on his promise and you find a generous sum of money, about the estimate worth of the cat${girl}, deposited into your account. Easiest money you've ever made.`);
			App.Events.addNode(el, r);
			return el;
		}

		function makeSlave() {
			const slave = GenerateNewSlave(null, {minAge: 16, maxAge: 22, race: "catgirl"});
			slave.face = random(25, 75);
			slave.origin = "$He was bioengineered by a rival arcology owner. After being mistreated, $he escaped and came to you for protection.";
			slave.slaveName = App.Data.misc.catSlaveNames.random();
			slave.birthName = slave.slaveName;
			slave.weight = 10;
			slave.muscles = 0;
			slave.waist = 10;
			slave.slaveSurname = "";
			slave.birthSurname = "";
			slave.career = "an orphan";
			slave.intelligenceImplant = 0;
			slave.teeth = "fangs";
			slave.devotion = random(-25, -10);
			slave.trust = random(-25, -10);
			slave.earShape = "none";
			slave.earT = "cat";
			slave.earTColor = slave.hColor;
			slave.earTNatural = 1;
			slave.tailShape = "cat";
			slave.tailColor = slave.hColor;
			slave.eye.left.pupil = "catlike";
			slave.eye.right.pupil = "catlike";
			slave.accent = 2;
			slave.canRecruit = 0;
			App.Medicine.Modification.addScar(slave, "back", "whip");
			slave.behavioralFlaw = "odd";
			return slave;
		}
	}
};


code:
App.Events.SEVatCatBoy = class SEVatCatBoy extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.projectN.status === 8,
			() => V.growingNewCat === 0,
		];
	}

	execute(node) {
		const slave = growCatgirl("XY", {minAge: 16, maxAge: 16});
		slave.origin = "$He is a vat-grown catboy created by Dr. Nieskowitz and the science team in your genelab.";

		App.Events.addParagraph(node, [
			`With their latest genemodding project complete, Dr. Nieskowitz proudly presents to you a healthy, unconscious catboy, floating suspended in the tube of thick green liquid you use to grow them. "Looks like he came out just fine." The aging doctor says with an authoritative gesture. "Another successful project. ${slave.slaveName} is going to make a lovely addition to your little collection."`
		]);

		App.Events.addResponses(node, [new App.Events.Result(`Bring your new slave back home`, home)]);

		function home() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`There's no obnoxious media attention this time getting in the way of you and your brand new, confusedly meowing catboy. It's just you, the rising sun over your arcology, and a fresh new cat to lead up to the penthouse.`);
			V.projectN.status = 6;
			r.push(App.UI.newSlaveIntro(slave));
			App.Events.addParagraph(frag, r);
			return frag;
		}
	}
};


code:
App.Events.SEVatCatGirl = class SEVatCatGirl extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.projectN.status === 7,
			() => V.growingNewCat === 0,
		];
	}

	execute(node) {
		const slave = growCatgirl("XX", {minAge: 16, maxAge: 16});
		slave.origin = "$He is a vat-grown catgirl created by Dr. Nieskowitz and the science team in your genelab.";

		App.Events.addParagraph(node, [`With their latest genemodding project complete, Dr. Nieskowitz proudly presents to you a healthy, unconscious catgirl, floating suspended in the tube of thick green liquid you use to grow them. "Looks like she came out just fine." The aging doctor says with an authoritative gesture. "Another successful project. ${slave.slaveName} is going to make a lovely addition to your little collection."`]);

		App.Events.addResponses(node, [new App.Events.Result(`Bring your new slave back home`, home)]);

		function home() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`There's no obnoxious media attention this time getting in the way of you and your brand new, confusedly meowing catgirl. It's just you, the rising sun over your arcology, and a fresh new cat to lead up to the penthouse.`);
			V.projectN.status = 6;
			r.push(App.UI.newSlaveIntro(slave));
			App.Events.addParagraph(frag, r);
			return frag;
		}
	}
};


code:
/**
 * Generates a new vat-grown catgirl that was grown in this arcology.
 * @returns {FC.SlaveState}
 * @param {"XY"|"XX"|""} [sex] null or omit to use default rules
 * @param {object} [Obj]
 */
globalThis.growCatgirl = function(sex, {
	minAge,
	maxAge,
} = {}) {
	const slave = GenerateNewSlave(sex, {
		minAge, maxAge, nationality: "Stateless", disableDisability: 1, race: "catgirl"
	});
	slave.face = random(55, 95);
	slave.faceShape = "feline";
	slave.slaveName = App.Data.misc.catSlaveNames.random();
	slave.birthName = slave.slaveName;
	slave.career = "an orphan";
	slave.intelligenceImplant = 0;
	slave.devotion = 20;
	slave.trust = 30;
	slave.earShape = "none";
	slave.teeth = "fangs";
	slave.earT = "cat";
	slave.earTColor = slave.hColor;
	slave.earTNatural = 1;
	slave.tailShape = "cat";
	slave.tailColor = slave.hColor;
	slave.eye.left.pupil = "catlike";
	slave.eye.right.pupil = "catlike";
	slave.weight = 10;
	slave.muscles = 0;
	slave.waist = 10;
	slave.vagina = Math.min(slave.vagina, 0);
	slave.anus = 0;
	slave.accent = 4;
	slave.canRecruit = 0;
	slave.skill = new App.Entity.SlaveSkillsState();
	slave.piercing = new App.Entity.completePiercingState();

	const revivalistNationality = getRevivalistNationality();
	if (typeof revivalistNationality === 'string') {
		slave.nationality = revivalistNationality;
	}

	// they're genetically engineered and very expensive, so go ahead and make their genes conform a bit better to local expectations...
	const arc = V.arcologies[0];
	if (FutureSocieties.isActive('FSStatuesqueGlorification', arc)) {
		slave.natural.height = Math.min(slave.natural.height + 10, 274);
		slave.height = Height.forAge(slave.natural.height, slave);
	} else if (FutureSocieties.isActive('FSPetiteAdmiration', arc)) {
		slave.natural.height = Math.max(slave.natural.height - 10, 85);
		slave.height = Height.forAge(slave.natural.height, slave);
	}
	if (FutureSocieties.isActive('FSIntellectualDependency', arc)) {
		slave.intelligence = Math.max(slave.intelligence - 15, -100);
	} else if (FutureSocieties.isActive('FSSlaveProfessionalism', arc)) {
		slave.intelligence = Math.min(slave.intelligence + 15, 100);
	}
	if (FutureSocieties.isActive('FSAssetExpansionist', arc)) {
		slave.natural.boobs += 500;
		slave.boobs += 500;
	} else if (FutureSocieties.isActive('FSSlimnessEnthusiast', arc)) {
		if (slave.natural.boobs > 500) {
			slave.natural.boobs = 200;
			slave.boobs = 200;
		}
	}

	return slave;
};


code:
/**
 *
 * @param {FC.SlaveState} slave
 * @returns {DocumentFragment}
 */
App.Interact.fPet = function(slave) {
	const node = new DocumentFragment();
	let r = [];

	const {
		He, His,
		he, his, him, himself, girl
	} = getPronouns(slave);

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

	r.push(`You tell ${slave.slaveName} to`);
	if (!hasAnyLegs(slave)) {
		r.push(`have another slave set ${him} up onto your desk.`);
	} else if (tooBigBreasts(slave)) {
		r.push(`have another slave help ${him} heft ${his} tits so ${he} can be near you.`);
	} else if (tooBigBelly(slave)) {
		r.push(`have another slave help ${him} heft ${his} belly so ${he} can be near you.`);
	} else if (tooBigButt(slave)) {
		r.push(`have another slave help ${him} heft ${his} ass cheeks so ${he} can be near you.`);
	} else if (tooBigDick(slave)) {
		r.push(`have another slave help ${him} heft ${his} cock so ${he} can be near you.`);
	} else if (tooBigBalls(slave)) {
		r.push(`have another slave help ${him} heft ${his} balls so ${he} can be near you.`);
	} else if (tooFatSlave(slave)) {
		r.push(`have another slave help ${him} up so ${he} can be near you.`);
	} else {
		r.push(`move closer towards you.`);
	}

	r.push(`Once ${he}'s at an acceptable petting range, you bring the overgrown cat into your embrace and gingerly run a hand from the top of ${his} head down ${his} spine, coursing through the soft fur in a massage-like petting motion.`);

	if (slave.fetish === Fetish.MINDBROKEN) {
		r.push(`${He} accepts the petting robotically, barely even comprehending what you're doing. The pleasant scritch of your fingers against ${his} back produces some sort of guttural purring sound, but that conveys the extent of the mindbroken cat's response.`);
	} else if (slave.devotion > 75) {
		r.push(`The cat${girl} loudly purrs and eagerly rubs up against you, arching ${his} back to give you a full range over the silky fur. ${His} tail flicks back and forth happily as you pet ${him}, flicking up to tease against your chin as you pet the purring kitten. When you finally retract your hand, ${slave.slaveName} bats ${his} eyelashes at you, still purring a little.`);
		if (!hasAnyArms(slave) && !canTalk(slave)) {
			r.push(`${His}`);
			if (canSee(slave)) {
				r.push(`eyes glimmer`);
			} else {
				r.push(`expression stares`);
			}
			r.push(`at you contentedly.`);
		} else if (!canTalk(slave)) {
			r.push(`${He} signs a little thank-you for the pets.`);
		} else {
			r.push(`${He} mrowls,`);
			r.push(Spoken(slave, `"Why'd you stop, ${Master}? Can I suck you off so you keep going?"`));
		}
	} else if (slave.devotion > 50) {
		r.push(`The cat${girl} presents ${his} back to you eagerly for petting, purring softly as you stroke your hand up and down ${his} soft fur. It's easy to let your hand practically get lost in the silky material, especially since the eager cat does all ${he} can to keep your hand running up and down ${his} spine in tender petting motions. When you finally retract your hand, ${slave.slaveName} bats ${his} eyelashes at you, still purring a little.`);
		if (!hasAnyArms(slave) && !canTalk(slave)) {
			r.push(`${His}`);
			if (canSee(slave)) {
				r.push(`eyes glimmer`);
			} else {
				r.push(`expression stares`);
			}
			r.push(`at you contentedly.`);
		} else if (!canTalk(slave)) {
			r.push(`${He} signs that ${he} loves you.`);
		} else {
			r.push(`${He} mrowls,`);

			r.push(Spoken(slave, `"That felt great, ${Master}. Can you pet me more often?"`));
		}
	} else if (slave.devotion > 20) {
		r.push(`The cat${girl} puts up a little façade of resistance, but just about immediately melts into your hands, giving you a full range of motion to pet and rub at ${his} silky fur. ${He} lets you pet along the full length of ${his} spine, rubbing under ${his} chin and exploring the curves of ${his} ass and breasts in a way that's, for once, entirely nonsexual. After about a minute, ${he} starts to purr at your petting, rumbling against your chest, and ${he} flutters ${his} eyelashes wistfully when you finally remove your hand.`);
		if (!hasAnyArms(slave) && !canTalk(slave)) {
			r.push(`${His}`);
			if (canSee(slave)) {
				r.push(`eyes glint`);
			} else {
				r.push(`expression stares`);
			}
			r.push(`at you with a smug aura.`);
		} else if (!canTalk(slave)) {
			r.push(`${He} signs a little thank-you for the pets.`);
		} else {
			r.push(`${He} mrowls,`);
			r.push(Spoken(slave, `"Thanks, ${Master}. That was nice."`));
		}
	} else if (slave.devotion < -20 && slave.trust >= 20) {
		r.push(`${He} glowers at you as you start to pet ${him}, clearly doing ${his} best to express nonverbal dissatisfaction with you. Despite that, ${he} can't help but to shiver somewhat as you gingerly pet the fluffy cat, rumbling with a deep purr that betrays ${his} distaste for you. ${He} glares up at you the entire time, even as ${he} purrs, ${his} tail swishing about in the air as you pet the furry thing vigorously. When you finally retract your hand, ${he} acts like ${he} didn't enjoy it.`);
		if (!hasAnyArms(slave) && !canTalk(slave)) {
			r.push(`${His}`);
			if (canSee(slave)) {
				r.push(`eyes glower`);
			} else {
				r.push(`expression glowers`);
			}
			r.push(`at you.`);
		} else if (!canTalk(slave)) {
			r.push(`${He} makes a rude sign gesture.`);
		} else {
			r.push(`${He} mrowls,`);
			r.push(Spoken(slave, `"I'm a person, not some kind of dumb animal."`));
		}
	} else if (slave.devotion >= -20 && slave.trust >= -20) {
		r.push(`${He} flinches back when you raise your hand towards ${him}, expecting to be hit. The tender petting that occurs obviously shocks ${him}, and for the first minute it looks like ${he}'s expecting you to change your mind at any moment and hit ${him} anyway. When you don't, only then does the scared cat${girl} allow ${himself} to get pet properly, slightly arching ${his} back to give you a range of motion against the silky fur as you stroke and play with your bioengineered cat${girl}. When you finally retract your hand, ${he} bats ${his} eyelashes at you, confused.`);
		if (!hasAnyArms(slave) && !canTalk(slave)) {
			r.push(`${He} just stares at you, blinking a few times.`);
		} else if (!canTalk(slave)) {
			r.push(`${He} makes a confused sign gesture.`);
		} else {
			r.push(`${He} mrowls,`);
			r.push(Spoken(slave, `"I-Is that it, ${Master}..?"`));
		}
	} else if (slave.trust < -20) {
		r.push(`${He} flinches back when you raise your hand towards ${him}, expecting to be hit. The tender petting that occurs obviously shocks ${him}, and for the first minute it looks like ${he}'s expecting you to change your mind at any moment and hit ${him} anyway. When you don't, only then does the scared cat${girl} allow ${himself} to get pet properly, slightly arching ${his} back to give you a range of motion against the silky fur as you stroke and play with your bioengineered cat${girl}. When you finally retract your hand, ${he} bats ${his} eyelashes at you, confused.`);
		if (!hasAnyArms(slave) && !canTalk(slave)) {
			r.push(`${He} just stares at you, blinking a few times.`);
		} else if (!canTalk(slave)) {
			r.push(`${He} makes a confused sign gesture.`);
		} else {
			r.push(`${He} mrowls,`);
			r.push(Spoken(slave, `"I-Is that it, ${Master}..?"`));
		}
	} else {
		r.push(`The cat${girl} puts up a little façade of resistance, but doesn't really fight back against your petting, giving you a full range of motion to pet and rub at ${his} silky fur. ${He} lets you pet along the full length of ${his} spine, rubbing under ${his} chin and exploring the curves of ${his} ass and breasts in a way that's, for once, entirely nonsexual. Despite ${himself}, ${he} can't help but to purr a little by the time you finally remove ${his} hands.`);
		if (!hasAnyArms(slave) && !canTalk(slave)) {
			r.push(`${His}`);
			if (canSee(slave)) {
				r.push(`eyes glint`);
			} else {
				r.push(`expression stares`);
			}
			r.push(`at you uncertainly.`);
		} else if (!canTalk(slave)) {
			r.push(`${He} makes a huffy mrowling noise.`);
		} else {
			r.push(`${He} mrowls,`);
			r.push(Spoken(slave, `"Thanks, I guess..."`));
		}
	}
	App.Events.addParagraph(node, r);
	return node;
};