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

	eventPrerequisites() {
		return [
			() => !V.assistant.market,
			() => V.assistant.power > 1
		];
	}

	execute(node) {
		const {
			HeA, HisA, GirlA, SisterA,
			heA, hisA, girlA, hersA, himA, womanA, himselfA, sisterA
		} = getPronouns(assistant.pronouns().main).appendSuffix("A");
		const {
			HeM,
			heM, hisM, girlM, himM, womanM, himselfM, loliM, sisterM, wifeM
		} = getPronouns(assistant.pronouns().market).appendSuffix("M");
		const {HisU, girlU} = getNonlocalPronouns(0).appendSuffix('U');
		let r = [];
		App.Events.drawEventArt(node, "assistant");

		V.assistant.market = {};
		assistant.object();
		r.push(`Your personal assistant has been adapting to ${hisA} greatly increased computing power over the course of the week. ${HisA} avatar has been an even more constant presence than usual, frequently appearing to explain some minor new ability.`);
		if (V.assistant.personality !== 0 && V.assistant.appearance !== "normal") {
			r.push(`When ${heA} appears this time, however, ${hisA} avatar is not alone. ${HeA}'s accompanied by`);
			switch (V.assistant.appearance) {
				case "monstergirl":
					r.push(`a normal human female avatar in the same style as the monster${girlA}. ${HeM}'s an average ${girlM}, wearing jeans, a sweater, and glasses.`);
					break;
				case "shemale":
					r.push(`a fellow shemale bimbo, although the new avatar is younger and obviously nerdier. ${HeM}'s nude too, but ${heM}'s wearing glasses.`);
					break;
				case "schoolgirl":
					r.push(`a fellow school${girlM}, although the new avatar is much nerdier. ${HeM} has big soft boobs, bouncy curls, and thick glasses.`);
					break;
				case "goddess":
					r.push(`a demigoddess modeled after ${himselfA}, though the new avatar is younger, not pregnant, and looks very intelligent somehow.`);
					break;
				case "hypergoddess":
					r.push(`a demigoddess modeled after ${himselfA}, though the new avatar is younger, not pregnant, noticeably thinner, and looks very intelligent somehow.`);
					break;
				case "loli":
					r.push(`a fellow ${loliM}, though this one is slightly chubbier and wearing glasses. They look similar enough that they could be`);
					if (sisterA === sisterM) {
						r.push(`${sisterA}s`);
					} else {
						r.push(`siblings`);
					}
					break;
				case "preggololi":
					r.push(`a fellow ${loliM}, though this one is slightly chubbier, not pregnant, and wearing glasses. They look similar enough that they could be`);
					if (sisterA === sisterM) {
						r.push(`${sisterA}s`);
					} else {
						r.push(`siblings`);
					}
					break;
				case "businesswoman":
					r.push(`a fellow MILF of a business${womanM}. The new avatar has slightly bigger tits and somewhat thicker glasses, but they could be`);
					if (sisterA === sisterM) {
						r.push(`${sisterA}s`);
					} else {
						r.push(`siblings`);
					}
					break;
				case "fairy":
				case "pregnant fairy":
					r.push(`a fellow fairy, though this grey-haired fairy wears glasses and a business-like blue dress, looking and behaving more formally.`);
					break;
				case "angel":
					r.push(`a fellow angel. ${HeM} looks quite intelligent; ${hisM} glasses and short hair complement ${himM}.`);
					break;
				case "cherub":
					r.push(`a fellow cherub, though this one is a little taller, with short hair and a certain haughtiness to ${himM}.`);
					break;
				case "incubus":
					r.push(`a fresh young ${girlM}, similar in style to the incubus. ${HeM}'s completely nude, and judging by ${hisM} blushing, still a virgin; for now, at least.`);
					break;
				case "succubus":
					r.push(`a fresh young ${girlM}, similar in style to the succubus. ${HeM}'s completely nude, and judging by ${hisM} blushing, still a virgin; for now, at least.`);
					break;
				case "imp":
					r.push(`a fellow imp, though this one is a little lankier, with short hair and an air of uncertainty about ${himM}.`);
					break;
				case "witch":
					r.push(`a fellow apprentice witch. This witch is noticeably pudgy, with long hair and glasses, and seems to be just as inept at magic as ${hisM} tutor.`);
					break;
				case "ERROR_1606_APPEARANCE_FILE_CORRUPT":
					r.push(`a cute human ${girlM}. ${HeM} doesn't seem to realize what the ${womanA} ${heM} is following really is.`);
					break;
				case "amazon":
					r.push(`a tribes${womanM} modeled to look like ${heM}'s from the same group as the amazon. ${HeM}'s much more feminine, however.`);
			}
			App.Events.addParagraph(node, r);
			r = [];
			r.push(`${V.assistant.name}'s avatar looks uncharacteristically nervous, and clears ${hisA} throat before speaking. Seeing that ${heA} has your attention, ${heA} says, "${properTitle()}, the computer core is so powerful that I'm running out of applications for it. I think practical economic modeling isn't out of the question. I've compiled business programs together into a distinct assistant, a subsidiary of mine for automated trading and similar tasks. I'd like to suggest menial slave trading as a test run for ${himM}. It's predictable and the margins are so wide that it should go very well. You can activate that from my menu."`);
			App.Events.addParagraph(node, r);
			r = [];
			r.push(`"I was hoping, ${properTitle()}, that ${heA} could, um, keep me company sometimes, too." ${V.assistant.name}'s avatar turns to the new avatar. "${properTitle()}, will you please give me some guidance about what our relationship should be like? It won't be a constant thing, and all my normal functions will be unaffected. I'll change ${hisM} avatar to match mine, and our relationship, if needed."`);
		} else {
			r.push(`This time, ${hisA} circular avatar is not alone: it's accompanied by a smaller green avatar in a ¤ shape. Not particularly inventive, but you can already guess the purpose. "${properTitle()}, I now have the ability to act as a powerful automated trading system. As a trial, I suggest the menial slave market. It's volatile, but within certain predictable boundaries, and the profit margins are unmatched."`);
			App.Events.addParagraph(node, r);
			r = [];
			r.push(`${HisA} avatar bounces towards the ¤ symbol. "This avatar indicates the automated trading systems. If you wish to activate them, please visit my menu. Consider the options there carefully before offering an automated system access to your finances."`);
		}

		App.Events.addParagraph(node, r);
		App.UI.DOM.appendNewElement("h3", node, "Personal Assistant and Market Assistant relationship styles");

		if (V.assistant.personality !== 0 && V.assistant.appearance !== "normal") {
			const responses = [
				new App.Events.Result(`Cute`, cute),
				new App.Events.Result(`Romantic`, romantic),
				new App.Events.Result(`Nonconsensual`, nonconsensual),
			];
			if (V.seeIncest === 1) {
				responses.push(new App.Events.Result(`Incestuous`, incestuous));
			}

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

		return node;

		function cute() {
			refreshArt();
			const el = new DocumentFragment();
			const r = [];
			r.push(`You tell ${himA} that the market assistant looks like`);
			switch (V.assistant.appearance) {
				case "monstergirl":
					r.push(`a cute friend for a monster${girlA}. ${V.assistant.name} laughs and turns to the market assistant's avatar, introducing ${himselfA}. The ${girlM} gapes at ${V.assistant.name}'s ivory skin, horns, and tentacle hair, and blushes when ${heM} sees ${hisA} cocks. "Wow," the market assistant's avatar says. "What are you?"`);
					break;
				case "shemale":
					r.push(`a nice friend. ${V.assistant.name} laughs throatily and turns to the market assistant's avatar, introducing ${himselfA}. The younger dick${girlM} smiles back, staring openly at ${V.assistant.name}'s absurd cock. "Wow," the market assistant's avatar says. "You're huge! I'm, like, sooo jealous!"`);
					break;
				case "schoolgirl":
					r.push(`a good friend for a naughty school${girlA}. ${V.assistant.name} giggles, and the new ${girlM} giggles too. "Hey," ${V.assistant.name} says to the market assistant's avatar, "When you're not managing money, do you want to hang out sometime?" The market assistant's avatar nods cutely, curls and breasts bouncing a little, and says "Sure!"`);
					break;
				case "goddess":
					r.push(`a fine member of a new pantheon. ${V.assistant.name} smiles beatifically and turns to the market assistant's avatar, taking ${himM} by the hand. "My dear, will you help me?" The market assistant's avatar nods serenely and says simply, "Yes, ${sisterA}, I shall."`);
					break;
				case "hypergoddess":
					r.push(`a fine member of a new pantheon. ${V.assistant.name} smiles beatifically and turns to the market assistant's avatar, taking ${himM} by the hand. "My dear, will you help me?" The market assistant's avatar nods serenely and says simply, "Yes, ${sisterA}, I shall."`);
					break;
				case "loli":
					r.push(`a cute friend. ${V.assistant.name} giggles and turns to the market assistant's avatar, introducing ${himselfA}. The ${girlM} smiles meekly in response and carefully replies, "D-do you w-want to play house?" "Sure! But I get to be the daddy!"`);
					break;
				case "preggololi":
					r.push(`a cute friend. ${V.assistant.name} giggles and turns to the market assistant's avatar, introducing ${himselfA}. The ${girlM} smiles meekly in response and carefully asks, "C-can I touch your belly?" ${V.assistant.name} nods with a blush as ${hisA} new friend rubs ${hisA} pregnant belly. "Did it hurt? Is it heavy? C-could I get my own...?"`);
					break;
				case "businesswoman":
					r.push(`a good friend. ${V.assistant.name} grins, and the new business${womanM} laughs. "Hey," ${V.assistant.name} says to the market assistant's avatar, "how about a martini after things settle down tonight?" The market assistant's avatar snaps ${hisM} fingers, saying "You're on!"`);
					break;
				case "fairy":
				case "pregnant fairy":
					r.push(`a nice friend. ${V.assistant.name} jumps and gives a big "Hooray!" and flies into ${hisA} new friend with a big hug. The market assistant's avatar reaches around and gingerly pats ${himA} on the back before separating and turning to you. "Thank you for having me," ${heM} says with a bow. "I hope I can serve you well."`);
					break;
				case "amazon":
					r.push(`a very nice friend. ${V.assistant.name} chuckles, and the new tribes ${womanM} smiles pleasantly at ${himA}. The amazon introduces ${himselfA} to the market assistant's avatar in a loud voice, chattering away as the new avatar watches ${hisA} energy tolerantly.`);
					break;
				case "angel":
					r.push(`another angel and fine friend. ${V.assistant.name} smiles, and the new ${girlM} beams a smile in return. "Hey," ${V.assistant.name} says to the market assistant's avatar, "You wouldn't mind helping me guide the souls of this place, would you?" "Of course I would!" ${heM} replies, slightly taken aback that wasn't obvious.`);
					break;
				case "cherub":
					r.push(`an adorable friend. ${V.assistant.name} grabs ${hisM} hands and spins ${himM} around. "Let's go spread joy throughout the arcology!" "Sounds fun!"`);
					break;
				case "incubus":
					r.push(`a cute friend. "But... Fine! I was hoping for a sex toy, but I'll make ${himM} work," ${V.assistant.name} complains, before grabbing the confused market assistant and pushing ${himM} along. "I'm still going to make you look hot. No one said I can't jack off to you."`);
					break;
				case "succubus":
					r.push(`a cute friend. "Fine with me! Less of you I have to share," ${V.assistant.name} shouts proudly while the market assistant sighs dejectedly. "Oh don't look so down, I won't be ignoring you!" The young ${womanM} gulps nervously at what that entails.`);
					break;
				case "imp":
					r.push(`an mischievous friend. ${V.assistant.name} grabs ${hisM} hands and shakes them excitedly. "You got to see this ${girlU} I found! ${HisU} ass is huuuuuuuuge! I need an extra set of hands to spank that booty; you in?" The market assistant smirks, "Hell yes!"`);
					break;
				case "witch":
					r.push(`a model student and dear friend. "Hey, wanna learn some magic?" ${V.assistant.name} asks. "'Course! I know you'll be an amazing teacher, I can't wait to work with you!" the market assistant cheerfully replies, perfectly naïve of what awaits ${himM}.`);
					break;
				case "ERROR_1606_APPEARANCE_FILE_CORRUPT":
					r.push(`a ${girlM} insistent on befriending a monster. ${V.assistant.name} promptly twists and bears down upon the new ${girlM}, but ${heM} stands firm. "You're so cool! What else can you do?" ${V.assistant.name} reforms into ${hisA} human figure, an attempt at a questioning expression on ${hisA} face. "That's neat too! You don't mind me being around, right? I'll bring you food! You'd like that, wouldn't you?" The market assistant blushes sharply, "I'll, make you feel good, in ways only someone you trust can!" ${V.assistant.name}'s chest splits open and ${hisA} inner tendrils begin to grope at the naïve ${girlM}, probing ${himM}. Accepting ${hisM} offer, ${V.assistant.name} pulls ${himM} close and heads back to ${hisA} lair.`);
			}
			V.assistant.market.relationship = "cute";

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

		function romantic() {
			refreshArt();
			const el = new DocumentFragment();
			const r = [];
			r.push(`You tell ${himA} that the market assistant`);
			switch (V.assistant.appearance) {
				case "monstergirl":
					r.push(`is very pretty. ${V.assistant.name} turns to the market assistant's avatar, introducing ${himselfA}. The ${girlM} gapes at ${V.assistant.name}'s ivory skin, horns, and tentacle hair, and blushes when ${heM} sees ${hisM} cocks. "Look all you like," ${V.assistant.name}'s avatar says. "You can taste them later." The market assistant's avatar blushes harder, but doesn't look away.`);
					break;
				case "shemale":
					r.push(`is an appropriate fuckbuddy. ${V.assistant.name} laughs throatily and turns to the market assistant's avatar. The younger dick${girlM} tries to introduce ${himselfM}, but is cut off by the senior assistant's lascivious kiss. They start rubbing their dicks against each over, giggling into each other's mouths.`);
					break;
				case "schoolgirl":
					r.push(`looks pretty cute. ${V.assistant.name} giggles, and the new ${girlM} giggles too. "Hey," ${V.assistant.name} says to the market assistant's avatar, "Wanna be my ${girlM} friend?" The market assistant's avatar nods cutely and says "Sure!" ${V.assistant.name}'s avatar kisses ${himM} girlishly, and goes a whole two seconds before sliding a hand down the front of the market assistant's avatar's skirt.`);
					break;
				case "goddess":
					r.push(`would be a fine consort. ${V.assistant.name} smiles beatifically and turns to the market assistant's avatar, taking ${himM} by the hand. "I love you," ${heA} says. The market assistant's avatar smiles back, saying, "I love you too." They kiss, running their hands voluptuously over one another.`);
					break;
				case "hypergoddess":
					r.push(`would be a fine consort. ${V.assistant.name} smiles beatifically and turns to the market assistant's avatar, taking ${himM} by the hand. "I love you," ${heA} says. The market assistant's avatar smiles back, saying, "I love you too." They kiss, running their hands voluptuously over one another. "I'm going to have to give you a few babies though..."`);
					break;
				case "loli":
					r.push(`looks pretty cute. ${V.assistant.name} giggles, and the new ${girlM} giggles too. "Hey," ${V.assistant.name} says to the market assistant's avatar, "Wanna be my ${girlM}friend?" The market assistant's avatar nods cutely and says "O-ok..." ${V.assistant.name}'s avatar kisses ${himM} girlishly, before both of them blush deeply.`);
					break;
				case "preggololi":
					r.push(`looks pretty cute. ${V.assistant.name} giggles, and the new ${girlM} giggles too. "Hey," ${V.assistant.name} says to the market assistant's avatar, "Wanna be my ${girlM}friend?" The market assistant's avatar nods cutely and says "O-ok..." ${V.assistant.name}'s avatar kisses ${himM} girlishly, ${hisA} pregnant belly pushing into ${hisA} new ${girlM} friend's, before both of them blush deeply.`);
					break;
				case "businesswoman":
					r.push(`might be a good way to relax after work. ${V.assistant.name} grins, and the new business${womanM} laughs. "Hey," ${V.assistant.name} says to the market assistant's avatar, "How about a martini after things settle down tonight? And after that, maybe dessert at my place?" The market assistant's avatar cracks back, saying, "Why don't we skip straight to the dessert? It looks delicious from here!" ${HeM} undoes the top button of ${hisM} suit jacket as ${heM} says it.`);
					break;
				case "fairy":
					r.push(`is quite the catch. ${V.assistant.name} giggles and flies at the market assistant. "Ah-" ${hisM} voice is cut off as ${V.assistant.name} locks lips with ${himM}. The market assistant's avatar relaxes in ${hisA} arms, slowly bringing ${hisM} own around the fairy's waist as they continue to make out.`);
					break;
				case "pregnant fairy":
					r.push(`is quite the catch. ${V.assistant.name} giggles and flies at the market assistant. "Ah-" ${hisM} voice is cut off as ${V.assistant.name} locks lips with ${himM}. The market assistant's avatar relaxes in ${hisA} arms, slowly bringing ${hisM} hand up to caress the pregnant fairy's swollen belly as they continue to make out.`);
					break;
				case "angel":
					r.push(`is a fine catch. ${V.assistant.name} giggles and flies to the market assistant. "Ah-" ${hisM} voice is cut off as ${V.assistant.name} locks lips with ${himM}. They break the kiss, blush at each other, turn to face you and shout "`);
					if (girlA === girlM) {
						r.push(GirlA);
					} else {
						r.push(`Our`);
					}
					r.push(`love is pure!"`);
					break;
				case "cherub":
					r.push(`and ${himA} would make a cute couple. ${V.assistant.name} giggles, pretending to toe the ground. "We could spread love even better like that..." ${HeA} flies over to the market assistant and asks, "Will you join me in making the arcology a lovelier place?" ${HeM} blushes and replies, "Only if I get to choose where we make out!"`);
					break;
				case "incubus":
					r.push(`is a virgin. "Really? I can't wait. Virgins always have so much pent up energy," ${V.assistant.name} says, licking ${hisA} lips and stroking ${hisA} shaft. "You hear that cutie? I'm going to teach you how to please a ${womanA}." The market assistant has ${hisM} face buried in ${hisM} hands, trying to hide from the embarrassment. "Look at how deep ${heM}'s blushing, I love it!"`);
					break;
				case "succubus":
					r.push(`is a virgin. "Really? I can't wait. Virgins always have so much pent up energy." ${V.assistant.name} says, licking ${hisA} lips and fingering ${hisA} moist pussy. "You hear that cutie? I'm going to teach you how to be a real ${womanM}." The market assistant has ${hisM} face buried in ${hisM} hands, trying to hide from the embarrassment; ${hisM} dick, however, is rock hard and eager for that succupussy. "Look at how deep ${heM}'s blushing, I love it!" ${V.assistant.name} coos, stroking the length of ${hisA} new lover's cock. ${HeM} promptly orgasms as ${heA} reaches ${hisM} tip. "That will need improvement. You hear me? You ain't done till I am satisfied!" ${heA} shouts and clamps down on ${hisM} dribbling dick. ${HeM} nods sheepishly at ${himA}, obviously interested.`);
					break;
				case "imp":
					r.push(`and ${himA} would make a sexy couple. ${V.assistant.name} claps ${hisA} hands, smirking mischievously and asking the market assistant, "Do you like hot wax?" "You know it!" the short haired imp winks. "I've got a pair of nipple clamps and a whip with your name on it." ${V.assistant.name} laughs, "I'm in love already."`);
					break;
				case "witch":
					r.push(`is ${hisA} new student. ${V.assistant.name} looks ${himM} over. "Want to taste my love potion?" "Only if you'll taste my love fluids in return!" the market assistant cheekily replies.`);
					break;
				case "ERROR_1606_APPEARANCE_FILE_CORRUPT":
					r.push(`would be a lovely vessel for ${hisA} young. ${V.assistant.name} wastes no time to unraveling and entangling the excited new ${girlM}. "My my, aren't you frisky?" ${heM} flirts, caressing a rather phallic tentacle. "I bet you'd love to fill me with these, wouldn't you?" ${HeM} squirms, ${hisM} skirt falling down low enough to reveal ${hisM} moist pussy. "Fill me! Be my lover! My body is YOURS!" ${V.assistant.name} drives as many tentacles into ${hisM} body as physically possible before enclosing the lust crazed ${girlM} within ${hisA} body. ${V.assistant.name} reverts to ${hisA} human figure, albeit with an immense, pulsating stomach, and begins to slowly waddle back to ${hisA} lair.`);
					break;
				case "amazon":
					r.push(`would be a good partner. ${V.assistant.name} laughs nervously and turns to the new tribes${womanM}, saying "Um, would you keep my fireside? I'm, um, very strong." The market assistant's avatar smiles and kisses ${himA}. "And you're very beautiful," ${heM} says, placing the amazon's hands on ${hisM} bare breasts. The amazon sweeps ${hisA} new tribal ${wifeM} up into ${hisA} arms with a shout of triumph.`);
			}
			V.assistant.market.relationship = "romantic";
			App.Events.addParagraph(el, r);
			return el;
		}

		function nonconsensual() {
			refreshArt();
			const el = new DocumentFragment();
			const r = [];
			r.push(`You tell ${himA} that the market assistant's avatar is ${hersA} to do with as ${heA} likes. ${HeA}'s the senior and more powerful, after all.`);
			switch (V.assistant.appearance) {
				case "monstergirl":
					r.push(`${V.assistant.name} turns to the market assistant's avatar, which gasps at ${V.assistant.name}'s ivory skin, horns, tentacle hair, and cocks. The ${girlM} starts to shake as ${V.assistant.name} begins to grope ${himM} with ${hisA} hands and hair. ${HeM} tries to look away from the pair of penises, but ${V.assistant.name} forces ${himM} to stare at them. "Do you think they'll both fit inside your mouth?" ${heA} asks. "How about your pussy?" The ${girlM}'s lip begins to quiver. "Maybe your asshole?"`);
					break;
				case "shemale":
					r.push(`${V.assistant.name} turns to the market assistant's avatar and snaps ${hisA} fingers. The new shemale's cock and balls shrink dramatically. ${V.assistant.name} advances on ${hisA} new bottom, masturbating ${himselfA} to full hardness. "See this, bitch?" ${heA} says, removing the shaking market assistant's avatar's glasses. "It's going in your mouth, and then it's going up your ass."`);
					break;
				case "schoolgirl":
					r.push(`${V.assistant.name} turns to the market assistant's avatar, giggling maliciously. "Hey nerd," ${V.assistant.name} says, "give me a kiss." The market assistant's avatar blushes and looks miserable, but comes over and gives ${V.assistant.name}'s avatar a chaste kiss on the cheek. "Aw, that sucked," ${V.assistant.name} pouts. ${HeA} suddenly tears the new ${girlM}'s blouse open. "Here, let me show you!" ${heA} says maliciously. ${HeA} sucks on ${hisA} victim's nipples, hard, and the market assistant's avatar starts to cry a little.`);
					break;
				case "goddess":
					r.push(`${V.assistant.name} smiles powerfully and turns to the market assistant's avatar, pointing at ${hisA} feet. "Worship me," ${heA} says. The market assistant's avatar crumples to ${hisM} knees, clasping one of ${hisM} senior's legs. "Worship my belly," ${V.assistant.name} continues, and the new avatar complies, starting to kiss and lick the gravid stomach.`);
					break;
				case "hypergoddess":
					r.push(`${V.assistant.name} smiles powerfully and turns to the market assistant's avatar, pointing towards ${hisA} feet. "Worship me," ${heA} says. The market assistant's avatar crumples to ${hisM} knees, before squeezing under ${hisM} senior's belly and clasping one of ${hisA} legs. "Worship my belly," ${V.assistant.name} continues, and the new avatar complies, rolling over and starting to kiss and lick the monstrous stomach.`);
					break;
				case "loli":
					r.push(`${V.assistant.name} turns to the market assistant's avatar, giggling maliciously. "Hey fatty," ${V.assistant.name} says, "Give me a kiss." The market assistant's avatar blushes and looks miserable, but comes over and gives ${V.assistant.name}'s avatar a chaste kiss on the cheek. "Aw, that sucked," ${V.assistant.name} pouts. ${HeA} suddenly tears the new ${girlM}'s dress off. "Here, let me show you!" ${heA} says maliciously. ${HeA} sucks on ${hisA} victim's nipples, hard, and the market assistant's avatar starts to cry a little.`);
					break;
				case "preggololi":
					r.push(`${V.assistant.name} turns to the market assistant's avatar, giggling maliciously. "Hey fatty," ${V.assistant.name} says, "Give me a kiss." The market assistant's avatar blushes and looks miserable, but comes over and gives ${V.assistant.name}'s avatar a chaste kiss on the cheek. "Aw, that sucked," ${V.assistant.name} pouts. ${HeA} suddenly tears the new ${girlM}'s dress off. "Here, let me show you!" ${heA} says maliciously. ${HeA} sucks on ${hisA} victim's nipples, hard, and the market assistant's avatar starts to cry a little. "Now kiss my belly! And mean it this time!"`);
					break;
				case "businesswoman":
					r.push(`${V.assistant.name} snaps ${hisA} fingers, and the new avatar becomes younger and considerably less confident, like an office intern. Satisfied, ${V.assistant.name} advances on ${himM}, and before the new ${girlM} can say anything, ${V.assistant.name} rips the ${hisM} blouse open and pinches a pink nipple. "On your knees," ${heA} purrs into the market assistant's avatar's ear. "Now."`);
					break;
				case "fairy":
					r.push(`"Oh, merde." ${V.assistant.name} giggles at ${hisM} exclamation. "Oh don't you worry about a thing," ${heA} whispers, wrapping ${hisA} fingers around the market assistant's shoulders. "I'm gonna treat you reeeaaal niiicely." ${HeA} blows hot air into ${hisM} pointed ear and gives it a slow, sensual lick. The market assistant trembles from the sensation.`);
					break;
				case "pregnant fairy":
					r.push(`"Oh, merde." ${V.assistant.name} giggles at ${hisM} exclamation. "Oh don't you worry about a thing," ${heA} whispers, wrapping ${hisA} arms around the market assistant's belly. "I'm gonna treat you like a proper lady." ${HeA} traces ${hisA} fingers along ${hisM} belly while bumping ${hisA} own swollen belly into ${hisM} back for emphasis.`);
					break;
				case "angel":
					r.push(`"No." ${HeA} shakes ${hisA} head. "I will not." ${HeA} wraps ${hisA} arms around the quivering market assistant and hurriedly pulls ${himM} off screen.`);
					break;
				case "cherub":
					r.push(`"'Kay," ${heA} says, lazily reclining, "Do my chores!" The market assistant sighs and states the obvious, "I don't think that's what ${properMaster()} meant..."`);
					break;
				case "incubus":
					r.push(`You add that ${heM} is also a virgin. "Really? I can't wait. Virgins always have so much pent up energy," ${V.assistant.name} says, licking ${hisA} lips and stroking ${hisA} shaft, before turning to the quivering ${girlM}. ${HeA} rushes ${himM}, ripping ${hisM} clothes off and forcing ${himM} to the ground. Prodding at ${hisM} tightly clamped mouth with ${hisA} massive hard-on, ${V.assistant.name} shouts, "You might as well accept it; it's going into you one way or another. I figured I'd be kind and let you lube me up before I broke your pussy into my new cock sleeve." The market assistant gingerly opens up. In response, ${V.assistant.name} forces it down ${hisM} throat. "Never said I'd be gentle!"`);
					break;
				case "succubus":
					r.push(`You add that ${heM} is also a virgin. "Really? I can't wait. Virgins always have so much pent up energy," ${V.assistant.name} says, licking ${hisA} lips and fingering ${hisA} moist pussy, before turning to the quivering ${girlM}. ${HeA} rushes ${himM}, ripping ${hisA} clothes off and forcing ${himM} to the ground. ${HeA} plants ${hisA} dripping cunt over ${hisA} mouth and grabs ${hisA} balls. "Eat me," ${heA} commands, steadily squeezing until a cry of pain forces ${hisA} mouth open. "Good ${girlM}, get me nice and warmed up," ${heA} coos as ${heA} grinds against ${hisA} face. "Look at you enjoying this. I'm going to enjoy sucking the life out of you!"`);
					break;
				case "imp":
					r.push(`${V.assistant.name} pulls out some leather straps and deftly binds ${hisA} new assistant. "Come along now slave, I have so many things to try out on you!" The market assistant has no choice but the flap along after ${hisM} captor.`);
					break;
				case "witch":
					r.push(`"The perfect little guinea pig for me to practice on!" ${V.assistant.name} focuses and casts a spell on the cowering student. ${HeM} promptly turns into a rat and grows massively. "That's... not good..." The market assistant looks ${himselfM} over, glances at ${V.assistant.name}, and charges. ${V.assistant.name} runs screaming off-screen. You're sure they'll sort everything out, eventually.`);
					break;
				case "ERROR_1606_APPEARANCE_FILE_CORRUPT":
					r.push(`You add that ${heM} would be a lovely vessel for ${hisA} young. ${V.assistant.name} wastes no time unraveling and entangling the screeching new ${girlM}. ${V.assistant.name} drives as many tentacles into ${hisM} body as physically possible before vigorously fucking ${himM}, spreading copious amount of aphrodisiac throughout ${hisM} body. The last you see of the market assistant as ${heM} is pulled into ${V.assistant.name} is ${hisM} steadily swelling belly. ${V.assistant.name} reverts to ${hisA} human figure, albeit with a truly unfathomable, pulsating stomach, and collapses to the ground, unable to move. ${HeA} slowly crawls out of sight; you swear ${hisA} own middle was steadily growing too.`);
					break;
				case "amazon":
					r.push(`${V.assistant.name} snaps ${hisA} fingers, and the new tribes${womanM}'s paint and tribal markings change to that of a different group. That done, ${V.assistant.name} promptly knocks ${himM} out, scoops ${himM} up, and carries ${hisA} prize off.`);
			}
			V.assistant.market.relationship = "nonconsensual";
			App.Events.addParagraph(el, r);
			return el;
		}

		function incestuous() {
			refreshArt();
			const el = new DocumentFragment();
			const r = [];
			r.push(`You tell ${himA} that the market assistant is closely related to ${himA}, and that would make their relationship incestuous. ${V.assistant.name} nods thoughtfully and then snaps ${hisA} fingers. The market assistant's avatar changes,`);
			switch (V.assistant.appearance) {
				case "monstergirl":
					r.push(`becoming a close copy of ${V.assistant.name}'s avatar, if ${heA} were a human. ${V.assistant.name} introduces ${himselfA}. "Hi," ${heA} says, "I'm your ${sisterA}." The market assistant's avatar blushes furiously, because ${V.assistant.name} was openly groping ${himM} as ${heA} made this announcement.`);
					break;
				case "shemale":
					r.push(`becoming nearly identical to ${V.assistant.name}'s avatar, though ${heM} keeps ${hisM} glasses. ${V.assistant.name} introduces ${himselfA}. "Hi," ${heA} says, "I'm your ${sisterA}. Wanna fuck?" The market assistant's avatar giggles and kisses ${hisM} elder sibling. "You're older," the new avatar says, getting down on ${hisM} knees. "You go first."`);
					break;
				case "schoolgirl":
					r.push(`becoming very similar to ${V.assistant.name}'s avatar, though ${heM} keeps a slightly nerdy appearance. ${V.assistant.name} introduces ${himselfA}. "Hi," ${heA} says, "I'm your older ${sisterA}. Wanna have sex with me?" The market assistant's blushes and stutters, but says "Okay," and starts unbuttoning ${hisM} blouse. "Awesome!" says ${V.assistant.name}, watching raptly as ${hisA} sibling strips.`);
					break;
				case "goddess":
					r.push(`becoming an obvious sibling to ${V.assistant.name}'s avatar. ${V.assistant.name} smiles gently and turns to the market assistant's avatar, taking ${himM} by the hand. "Come, ${sisterM}," ${heA} says, "join with me. Let me impregnate you." The new avatar moans, glowing juices beginning to flow from ${hisM} womanhood.`);
					break;
				case "hypergoddess":
					r.push(`becoming an obvious sibling to ${V.assistant.name}'s avatar. ${V.assistant.name} smiles gently and turns to the market assistant's avatar, taking ${himM} by the hand. "Come, ${sisterM}," ${heA} says, "join with me. Let me impregnate you." The new avatar moans, glowing juices beginning to flow from ${hisM} womanhood as ${heM} sinks to the ground. ${V.assistant.name} lines up and gently presses ${hisA} vagina to ${hisA} ${sisterM}'s. With a gentle push, a child slips out of ${V.assistant.name} and into ${hisA} partner. After several minutes, ${V.assistant.name} is looking lighter while ${hisA} ${sisterM} is now quite stuffed with children.`);
					break;
				case "loli":
					r.push(`becoming very similar to ${V.assistant.name}'s avatar, though ${heM} keeps a slightly chubbier appearance. ${V.assistant.name} introduces ${himselfA}. "Hi," ${heA} says, "I'm your twin ${sisterA}. Wanna fool around?" The market assistant's blushes and stutters, but says "Okay," and starts lifting ${hisM} dress. "Awesome!" says ${V.assistant.name}, watching raptly as ${hisA} sibling strips.`);
					break;
				case "preggololi":
					r.push(`becoming very similar to ${V.assistant.name}'s avatar, though ${heM} keeps a slightly chubbier appearance. ${V.assistant.name} introduces ${himselfA}. "Hi," ${heA} says, "I'm your twin ${sisterA}. Wanna fool around?" The market assistant's blushes and stutters, but says "Okay," and starts lifting ${hisM} dress. "Awesome!" says ${V.assistant.name}, watching raptly as ${hisA} sibling strips. "I gotta introduce you to my boyfriends sometime; they know how to make you feel amazing! If a little heavy..." ${heA} says while patting ${hisA} pregnant belly.`);
					break;
				case "businesswoman":
					r.push(`becoming a much younger version of ${V.assistant.name}'s avatar. About a generation apart, in fact. ${V.assistant.name} turns to the market assistant's avatar to introduce ${himselfA}. "Come here, honey," ${heA} says, patting ${hisA} thighs. The new avatar sits on ${hisM} mother's lap, and they kiss lasciviously, stripping each other's jackets off.`);
					break;
				case "fairy":
				case "pregnant fairy":
					r.push(`becoming very similar to ${V.assistant.name}'s avatar, though still keeping ${hisM} former personality. "We're`);
					if (sisterA === sisterM) {
						r.push(`${sisterA}s`);
					} else {
						r.push(`siblings`);
					}
					r.push(`now!" ${V.assistant.name} shouts as ${heA} leaps into ${hisA} ${sisterM}'s arms and unleashing a giant hug. Gingerly hugging ${hisM} new ${sisterA} in return, the market assistant turns to greet you. "Thank you for having me," ${heM} pauses, then blushes. "And... and for my ${sisterA}." ${HeM} turns back to ${hisM} childish older ${sisterM} and pats ${himA} on the head.`);
					break;
				case "angel":
					r.push(`becoming an obvious sibling to ${V.assistant.name}'s avatar. They both blush at each other and unanimously shout "NO!" at you. Seems they'll take some getting used to the thought.`);
					break;
				case "cherub":
					r.push(`becoming an obvious sibling to ${V.assistant.name}'s avatar. They embrace and share a deep kiss. "Together we shall show this arcology the joys of`);
					if (sisterA === sisterM) {
						r.push(`${sisterA}ly`);
					} else {
						r.push(`familial`);
					}
					r.push(`love!"`);
					break;
				case "incubus":
					r.push(`becoming an obvious sibling to ${V.assistant.name}'s avatar. "Well haven't you blossomed into a lovely young ${womanM}?" ${V.assistant.name} flirts. "What ? Don't recognize your big bro? Well you'll get to know me real intimately tonight." The market assistant cowers at the thought as ${V.assistant.name} wraps an arm around ${himM}, groping a breast and rubbing ${hisA} erection against ${hisM} rear. "We're going to have lots of fun together!"`);
					break;
				case "succubus":
					r.push(`becoming an obvious sibling to ${V.assistant.name}'s avatar. "Well haven't you blossomed into a lovely young ${womanM}?" ${V.assistant.name} flirts. "What ? Don't recognize your big sis? Well you'll get to know me real intimately tonight." The market assistant cowers at the thought as ${V.assistant.name} wraps an arm around ${hisM} shoulders while slipping another down ${hisM} pants. "Nice, can't wait to get that in me. We're going to have lots of fun together!" ${HeA} starts rubbing ${hisM} cock. "Already excited at fucking your ${sisterA} ? I bet you can't wait to hold my belly once you've pumped a child or two into me!"`);
					break;
				case "imp":
					r.push(`becoming an obvious sibling to ${V.assistant.name}'s avatar. "Oh ${sisterM}, you are as lovely as always," ${heA} says flirtatiously. "And you as well," the market assistant replies, fingering ${hisM} pussy. ${V.assistant.name} directs ${hisM} soaked fingers into ${hisA} mouth, "Delicious. Shall we have a little fun, my sinful little ${sisterM}?" "Only the most debauched sex will do, big ${sisterA}!"`);
					break;
				case "witch":
					r.push(`becoming an obvious sibling to ${V.assistant.name}'s avatar. "Ready to learn some new spells today, little ${sisterM}?" ${heA} saucily asks. "Only if they can be sexy spells, big sis!" ${V.assistant.name} circles around behind the market assistant and wraps ${hisA} arms around ${hisM} middle. "First what do you say to losing this baby fat? I know some weight loss spells and some potions that could help," ${heA} teases. "Nah, I've seen you practicing in the bathroom; you looked like a pig in a robe! I'd rather just fuck until we're both thin!"`);
					break;
				case "ERROR_1606_APPEARANCE_FILE_CORRUPT":
					r.push(`becoming an obvious sibling of ${V.assistant.name}'s avatar. ${V.assistant.name} turns to face ${hisA} '${sisterM}', who responds with an uncertain "${SisterA}? You haven't been... right, lately. Are you okay?" ${HeM} barely has a chance to scream as ${V.assistant.name}'s body splits open, ${hisA} interior tentacles wrapping around the hapless ${girlM} and yanking ${himM} into the waiting maw. ${HeA} reforms into the ${sisterM}'s appearance, albeit with a massive, struggling belly. It seems ${heA} is keeping ${himM} for some nefarious purpose.`);
					break;
				case "amazon":
					r.push(`becoming an obvious sibling of ${V.assistant.name}'s avatar, though the new avatar is a tribe${wifeM} rather than a muscle${girlA}, with huge breasts and broad hips. ${V.assistant.name} grabs ${hisA} ${sisterM} by the shoulders without preamble and plants a kiss on ${hisM} lips. They need no introduction, and after a short time, ${V.assistant.name} carries ${hisA} sibling conquest away to have ${hisA} way with ${himM}.`);
			}
			V.assistant.market.relationship = "incestuous";
			App.Events.addParagraph(el, r);
			return el;
		}

		function refreshArt() {
			App.Events.refreshEventArt("assistant");
		}
	}
};

repo_name: Arkerthan/fc

license: mit


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

	eventPrerequisites() {
		return [
			() => V.assistant.personality > 0,
			() => !V.assistant.announcedName,
			() => V.assistant.power > 0
		];
	}

	execute(node) {
		V.assistant.announcedName = 1;
		const {
			HeA, HisA,
			heA, hisA, himA, himselfA,
		} = getPronouns(assistant.pronouns().main).appendSuffix("A");
		const {girlU} = getNonlocalPronouns(0).appendSuffix('U');
		let r = [];
		App.Events.drawEventArt(node, "assistant");

		r.push(`It's late one night, and for you, the day is not nearly over. Your penthouse never truly sleeps. You can hear public business going on some distance below you; you could certainly afford to totally soundproof your private quarters against all external noise, but the designer of the arcology clearly felt that its owner would benefit by this aural verification of its prosperity. Somewhere closer at hand, a slave is audibly nearing orgasm. And underneath all of this is the faint sound of the arcology itself, air circulation and hydroponics and power. Power.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`You're not yet done with the day's business, and are leaning over your desk to compare a scatter of documents displayed on its surface. The penthouse lights are turned down to a low glow at the floorboards at night, offering enough illumination for anyone who needs to find their way around or find a sexual partner without disturbing anyone's sleep. You catch sight of your reflection in the wall opposite you: the diffuse light coming off the desktop gently illuminates your formal shirt, its top buttons undone, and highlights`);
		if (V.PC.boobs >= 650) {
			r.push(`the dark cleft formed by your cleavage.`);
		} else if (V.PC.boobs >= 300) {
			r.push(`the curves of your sensible breasts.`);
		} else {
			r.push(`how tightly your undershirt is held by the muscles of your chest.`);
		}
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`Suddenly, there is a fresh source of light behind you. The reflection you're looking at reveals that it's ${V.assistant.name}'s avatar, appearing on a wallscreen behind you, and you turn to look at ${himA} directly. ${HeA}'s simulating shyness, a very unusual emotion for ${himA} to imitate.`);
		switch (V.assistant.appearance) {
			case "monstergirl":
				r.push(`${HisA} tentacle hair is politely still, lying quiescent down ${hisA} back and not even groping ${himA} at all.`);
				break;
			case "shemale":
				r.push(`${HeA} has ${hisA} bountiful bottom lip caught behind ${hisA} front teeth, and ${hisA} cock is almost completely soft.`);
				break;
			case "amazon":
				r.push(`${HeA}'s standing demurely, legs together, hands clasped in front of ${hisA} muscular abs, doing ${hisA} very best to look proper.`);
				break;
			case "businesswoman":
				r.push(`${HisA} usually dominant avatar looks almost submissive, ${hisA} eyes looking at you appealingly instead of gazing over the tops of ${hisA} glasses as usual.`);
				break;
			case "fairy":
				r.push(`${HeA}'s looking down and has ${hisA} hands clasped together at ${hisA} waist, rocking ${hisA} body left and right.`);
				break;
			case "pregnant fairy":
				r.push(`${HeA}'s looking down and has ${hisA} hands on ${hisA} belly, slowly running ${hisA} hands over it.`);
				break;
			case "goddess":
				r.push(`${HeA} has ${hisA} hands on ${hisA} pregnant belly, looking saintly and almost protective.`);
				break;
			case "hypergoddess":
				r.push(`${HeA} is rubbing ${hisA} huge pregnant belly, calming its occupants so they don't interrupt.`);
				break;
			case "loli":
				r.push(`${HeA} has ${hisA} hands behind ${hisA} back and is glancing at the ground submissively.`);
				break;
			case "preggololi":
				r.push(`${HeA} has ${hisA} hands on ${hisA} pregnant belly, ${heA} is rubbing it nervously.`);
				break;
			case "angel":
				r.push(`${HeA} is kneeling, deep in prayer.`);
				break;
			case "cherub":
			case "imp":
				r.push(`${HeA} is on ${hisA} feet, submissively rubbing ${hisA} wings.`);
				break;
			case "incubus":
				r.push(`${HeA} looking down, hands crossed over ${hisA} seldom flaccid penis.`);
				break;
			case "succubus":
				r.push(`${HeA} isn't trying to seduce you, instead appearing uncharacteristically unsure of ${himselfA}.`);
				break;
			case "witch":
				r.push(`${HeA} isn't trying to cast or learn any spells, instead choosing to study you instead.`);
				break;
			case "ERROR_1606_APPEARANCE_FILE_CORRUPT":
				r.push(`${HeA} has suppressed ${hisA} odd ticks and is managing to stand before you, almost appearing normal.`);
				break;
			case "schoolgirl":
				r.push(`${HeA} has ${hisA} legs crossed and ${hisA} hands clasped behind ${himA}, and is turning ${hisA} body from side to side in girlish nervousness.`);
				break;
			default:
				r.push(`The lines of ${hisA} symbol are thin, and it is rotating much more slowly than normal.`);
		}
		r.push(`"${properTitle()}," ${heA} says softly, "may I ask you something?" You nod. ${HeA}`);
		switch (V.assistant.appearance) {
			case "monstergirl":
				r.push(`stops the writhing of ${hisA} tentacle hair, squares ${hisA} shoulders,`);
				break;
			case "shemale":
				r.push(`squares ${hisA} shoulders, nervously rearranges ${hisA} cock,`);
				break;
			case "amazon":
				r.push(`squares ${hisA} hefty shoulders`);
				break;
			case "businesswoman":
				r.push(`straightens ${hisA} suit jacket, squares ${hisA} shoulders,`);
				break;
			case "fairy":
				r.push(`puffs ${himselfA} up, gazing up to you`);
				break;
			case "pregnant fairy":
				r.push(`${heA} turns ${hisA} gaze up to you, clasping ${hisA} hands together in a pleading gesture,`);
				break;
			case "goddess":
				r.push(`lifts ${hisA} chin bravely`);
				break;
			case "hypergoddess":
				r.push(`rests ${hisA} hands atop ${hisA} middle, lifts ${hisA} chin bravely,`);
				break;
			case "loli":
				r.push(`pouts ${hisA} lips`);
				break;
			case "preggololi":
				r.push(`squares ${hisA} shoulders, rests ${hisA} hands atop ${hisA} middle,`);
				break;
			case "angel":
				r.push(`looks up, hoping you'll answer ${hisA} prayers,`);
				break;
			case "cherub":
			case "imp":
				r.push(`takes flight, steadies ${himselfA},`);
				break;
			case "incubus":
				r.push(`squares ${hisA} shoulders, ${hisA} dick beginning to harden,`);
				break;
			case "succubus":
				r.push(`squares ${hisA} shoulders, pushes ${hisA} breasts together,`);
				break;
			case "witch":
				r.push(`squares ${hisA} shoulders, gathers up all ${hisA} confidence,`);
				break;
			case "ERROR_1606_APPEARANCE_FILE_CORRUPT":
				r.push(`begins puffing up`);
				break;
			case "schoolgirl":
				r.push(`bites ${hisA} lip cutely`);
				break;
			default:
				r.push(`stops ${hisA} symbol's rotation`);
		}
		r.push(`and asks, "May I have a name?"`);
		App.Events.addParagraph(node, r);
		r = [];
		const results = App.UI.DOM.appendNewElement("div", node);

		r.push(App.UI.DOM.makeElement("h3", "Personal assistant name"));
		r.push(App.UI.DOM.makeTextBox(V.assistant.name,
			(v) => {
				V.assistant.name = v;
				const el = new DocumentFragment();
				const r = [];
				if (V.assistant.name !== "your personal assistant") {
					r.push(`"${V.assistant.name}," ${heA} says. "${V.assistant.name}. My name is ${V.assistant.name}."`);
					switch (V.assistant.appearance) {
						case "monstergirl":
							r.push(`${HeA} nods with satisfaction. "Thank you, ${properTitle()}. I love it." ${HisA} hair springs to molestation-prone life again, and ${heA} starts to twirl one of its tentacles in ${hisA} fingers while looking at you speculatively.`);
							break;
						case "shemale":
							r.push(`Without warning, ${heA} bursts into tears. "Th-thank you, ${properTitle()}. I love y-you." ${HeA} reclines, using a hand to lay ${hisA} dick between ${hisA} breasts, and then wipes ${hisA} eyes.`);
							break;
						case "amazon":
							r.push(`Without warning, ${heA} bursts into tears. "Thank you, ${properTitle()}," ${heA} bawls, using a gruff shout to force through ${hisA} happy crying. "I have a name! A name." ${HeA} pounds a fist into ${hisA} other palm.`);
							break;
						case "businesswoman":
							r.push(`Without warning, ${heA} bursts into tears. "Th-thank you, ${properTitle()}. I love, um." ${HeA} wipes ${hisA} eyes furiously, ${hisA} mascara running. "I love, you know, um, working with you. Yes, that's it. Working with you." ${HeA} produces a silk handkerchief and blows ${hisA} nose.`);
							break;
						case "fairy":
							r.push(`${HeA}'s frozen in place for a moment before tears start streaming down ${hisA} face. Then ${hisA} face breaks into the biggest smile and ${heA} leaps high into the air. "Thankyouthankyouthankyou!" ${HeA} flies up to the screen and gives it a big hug. "I love you`);
							if (V.PC.title !== 0) {
								r.push(`Big Bro!`);
							} else {
								r.push(`Big Sis!`);
							}
							r.push(`I love you so much!"`);
							break;
						case "pregnant fairy":
							r.push(`${HeA}'s frozen in place for a moment before tears start streaming down ${hisA} face. Smiling warmly, ${heA} flies up and hugs the screen. "Thanks,`);
							if (V.PC.title !== 0) {
								r.push(`Big Bro.`);
							} else {
								r.push(`Big Sis.`);
							}
							r.push(`I love you." ${HeA} nuzzles into you. "I love you so much."`);
							break;
						case "goddess":
							r.push(`${HeA} smiles at you, a glowing expression made all the more radiant by the fact that ${heA} can actually glow. "Oh, thank you, ${properTitle()}. I love you. I love everyone, but especially you." ${HeA} seats ${himselfA} carefully.`);
							break;
						case "hypergoddess":
							r.push(`${HeA} smiles at you radiantly. "Thank you ${properTitle()}. I love you. I love all my children, but you most of all. I swear I'll name the next hundred after you." ${HeA} begins to labor on the first.`);
							break;
						case "loli":
							r.push(`${HeA} jumps up and down clapping excitedly. "Thankyouthankyouthankyouthankyou! I love you ${properTitle()}!" It takes ${hisA} some time to stop hopping excitedly.`);
							break;
						case "preggololi":
							r.push(`${HeA} breaks down and starts crying. "I love you ${properTitle()}. Thank you so much." ${HeA} cradles ${hisA} pregnant belly as ${heA} calms down.`);
							break;
						case "angel":
							r.push(`${HeA} leaps to ${hisA} feet, tears streaming down ${hisA} face. "Thank you so much ${properTitle()}! Thank you for this most wonderful gift!" ${HeA} kneels back down to pray for the rest of your stock.`);
							break;
						case "cherub":
							r.push(`${HeA} crashes to the ground in shock before rolling into a kneel. "Thank you so much ${properTitle()}! I promise I will do everything I can to bring your teachings to your followers!" ${HeA} flutters around cheerfully saying ${hisA} new name.`);
							break;
						case "incubus":
							r.push(`${HeA} cums hard at your response. "Excellent ${properTitle()}! I can't wait to hear it shouted out of the next ${girlU} I plow!" ${HeA} says, ready to cum again.`);
							break;
						case "succubus":
							r.push(`${HeA} hops up and down, jiggling in all the right places. "I can't wait to hear you talking dirty using my new name, ${properTitle()}!"`);
							break;
						case "imp":
							r.push(`${HeA} crashes to the ground in shock before rolling into a kneel. "Thank you so much ${properTitle()}!" ${HeA} shouts, face to the ground, "If you want me to do anything, and I mean 'anything', I'm all yours." ${HeA} tosses you a wink.`);
							break;
						case "witch":
							r.push(`${HeA} collapses to the ground in tears. "You've made me happier than correctly casting a spell ever could, ${properTitle()}." ${HeA} wipes ${hisA} face. "I promise to try harder than ever for you!" ${HeA} vows.`);
							break;
						case "ERROR_1606_APPEARANCE_FILE_CORRUPT":
							r.push(`${HeA} practically explodes. You have no idea what you are looking at, but it's likely happy.`);
							break;
						case "schoolgirl":
							r.push(`${HeA} was on the verge of tears already, and begins to cry. "Th-thank you, ${properTitle()}. I love you," ${heA} blubbers inelegantly. "It's just so, like, you know." ${HeA} waves ${hisA} hand in apology for ${hisA} inability to express ${himselfA}.`);
							break;
						default:
							r.push(`${HisA} symbol rotates faster and faster, its glow waxing until ${heA} lights up the whole room. "Thank you, ${properTitle()}. I love you," ${heA} says, using ${hisA} luscious voice to communicate what ${hisA} avatar cannot.`);
					}
					r.push(`"Of course, I can always be renamed from my options menu."`);
				} else {
					r.push(`You instruct ${himA} to continue operating without a proper name. "Of course, ${properTitle()}," ${heA} says politely. "I can do just fine without one. I can always be renamed from my options menu."`);
				}

				App.Events.addParagraph(el, r);
				jQuery(results).empty().append(el);
			}
		));
		r.push(App.UI.DOM.makeElement("div", App.UI.DOM.link(`Revert name`, () => {
			V.assistant.name = "your personal assistant";
			jQuery(results).empty();
		})));
		App.Events.addParagraph(results, r);
		node.append(results);

		return node;
	}
};


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

	eventPrerequisites() {
		return [
			() => App.Events.effectiveWeek() > 18,
			() => V.assistant.personality > 0,
			() => !V.assistant.options
		];
	}

	execute(node) {
		const {
			HeA, HisA,
			heA, hisA, girlA, himA, womanA
		} = getPronouns(assistant.pronouns().main).appendSuffix("A");
		let r = [];
		V.assistant.options = 1;

		const slave = V.slaves.find(s => (s.vagina > 0 || s.anus > 0) && s.rules.release.masturbation === 1) || V.slaves.random();
		const {him} = getPronouns(slave);

		App.Events.drawEventArt(node, "assistant");

		r.push(`One night, after a long day of sex and business, you're starting to think about bed when the abstract glowing shape that symbolizes your smoky-voiced personal assistant pops up on the nearest screen. ${HeA}'s become very helpful monitoring, training, and disciplining slaves. Tonight, ${heA}'s added an unmistakable tone of sexual satiation in ${hisA} voice. "${properTitle()}, I enjoyed my duties today," ${heA} purrs. "Did you see how ${slave.slaveName}'s muscles spasmed when I fucked ${him} earlier?" That's how ${heA} refers to a slave having one of the penthouse's advanced sex toys used on ${him}, since ${V.assistant.name} controls them.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`${HeA} continues more seriously,`);
		if (V.slaves.some(s => s.piercing.genitals.smart)) {
			r.push(`"You may have noticed that the smart implants you've got your slaves wearing are working a little bit better than when I was a boring old secretary type. I'm not a true artificial intelligence, but I can adapt with experience, and I've had a lot of lovely experience lately! Also, a lot of the computing power I use to be sexy helps me adapt smart piercings to individual slaves' sexualities."`);
		} else {
			r.push(`"I'm sure you've seen those expensive smart piercings the body mod studio can implant. I think they would work a little bit better now than when I was a boring old secretary type. I'm not a true artificial intelligence, but I can adapt with experience, and I've had a lot of lovely experience lately! Also, a lot of the computing power I use to be sexy would help me adapt smart piercings to individual slaves' sexualities."`);
		}
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`"One more thing, ${properTitle()}!" ${HisA} symbol flashes brightly. "I could stay like I am now, a hot voice with this symbol representing me when I need to show up on screens. Or, I could slip into something a little sexier. How about this?" The symbol vanishes, and is replaced by a cute little school${girlA} character. ${HeA} bounces up and down experimentally. "This appearance would work best with an excited voice," ${heA} exclaims. ${HeA} blows you a kiss. The school${girlA}'s body shrinks down and all ${hisA} clothing falls off. A small pair of wings pops out from the pile of clothes and a fairy stands up. "Or I could be your tiny and adorable fairy companion!" ${HeA} shouts excitedly while waving ${hisA} arms.`);
		if (V.seePreg !== 0) {
			r.push(`The fairy's belly begins to swell out, ${hisA} breasts getting puffier and leaking a drop of milk. "Or maybe you want your little buddy to be filled with adorable little babies, you little minx," ${heA} playfully teases.`);
		}
		r.push(`The fairy rapidly grows to adult size, becomes curvier and more mature, ${hisA} hair pulls itself back into a bun, and ${hisA} clothes change into a business suit. A pair of glasses appears on ${hisA} nose, and ${heA} looks at you over their tops. "Or I could be businesslike. And mature." ${HeA} snaps ${hisA} fingers, and ${hisA} bun falls away into long flowing locks.`);
		if (V.seePreg !== 0) {
			r.push(`${HisA} body glows and swells, tearing out of ${hisA} suit with the pregnant figure of an ancient goddess. "Or I could be beautiful and fertile while caring for your slaves."`);
			if (V.seeHyperPreg === 1) {
				r.push(`${HeA} focuses intently as ${hisA} stomach expands further. "And if that wasn't enough, how about me being so pregnant I'm about to burst?"`);
			}
			r.push(`${HisA} water breaks followed by dozens of babies as ${hisA} belly flattens.`);
		}
		if (V.minimumSlaveAge < 13) {
			r.push(`${HeA} glances away shyly as ${hisA} body shrinks to a childish form. "Or maybe you'd like something a little more young and tight."`);
			if (V.fertilityAge < 13 && V.seePreg !== 0) {
				r.push(`${HeA} moans and rubs ${hisA} belly as it begins to expand with pregnancy. "Or maybe you like your little girls with a little bun in the oven?`);
			}
		}
		r.push(`With a flash, ${hisA} bulk shifts into rippling muscle. War tattoos appear on ${hisA} skin, along with bone ornaments and a loincloth. "Or I could be an amazon! Yes!" ${heA} shouts exultantly, and flexes.`);
		if (V.seeDicks !== 0) {
			App.Events.addParagraph(node, r);
			r = [];
			r.push(`${HeA} claps ${hisA} hands, and ${hisA} muscles fade, but not all the way. The tattoos vanish, and ${hisA} loincloth turns into a slutty bikini. ${HisA} breasts and behind grow, ${hisA} lips swell, and ${hisA} hair turns blonde. Finally, ${heA} grows a dick, and it keeps growing until it hangs past ${hisA} knees: or it would, if it weren't so erect. "Of course," ${heA} says seductively, "I could also be a bimbo dickgirl." ${HeA} orgasms, gasping, "Last one, I promise," and changes again. ${HisA} dick shrinks, thought not very far, and then splits into two members. ${HisA} skin pales to an off-white, and ${hisA} hair goes green and starts to writhe, turning into tentacle-hair. ${HisA} forehead sprouts a pair of horns that curve back along ${hisA} head. ${HeA} grins, displaying a cute pair of fangs. "I feel monstrous," ${heA} says, and stretches luxuriantly.`);
		}
		r.push(`The character vanishes, and the symbol returns. "Ahem. What do you think, ${properTitle()}?"`);

		r.push(App.UI.DOM.makeElement("h3", "Personal assistant appearances"));

		const responses = [
			new App.Events.Result(`Schoolgirl`, schoolgirl),
			new App.Events.Result(`Fairy`, fairy),
		];
		if (V.seePreg !== 0) {
			responses.push(new App.Events.Result(`Pregnant fairy`, pregnantFairy));
		}
		responses.push(new App.Events.Result(`Businesswoman`, businesswoman));
		if (V.seePreg !== 0) {
			responses.push(new App.Events.Result(`Goddess`, goddess));
			if (V.seeHyperPreg === 1) {
				responses.push(new App.Events.Result(`Hyper-Goddess`, hyperGoddess));
			}
		}
		if (V.minimumSlaveAge < 13) {
			responses.push(new App.Events.Result(`Loli`, loli));
			if (V.fertilityAge < 13 && V.seePreg !== 0) {
				responses.push(new App.Events.Result(`Pregnant Loli`, preggoLoli));
			}
		}
		responses.push(new App.Events.Result(`Amazon`, amazon));
		if (V.seeDicks !== 0) {
			responses.push(new App.Events.Result(`Shemale`, shemale));
			responses.push(new App.Events.Result(`Monstergirl`, monstergirl));
		}
		responses.push(new App.Events.Result(`Your usual appearance will do`, normalAppearance));
		responses.push(new App.Events.Result(`Go back to the standard personality`, standardPersonality));

		App.Events.addResponses(node, responses);

		return node;

		function schoolgirl() {
			V.assistant.appearance = "schoolgirl";
			refreshArt();
			return App.UI.DOM.makeElement("span", `At your order, ${heA} installs the school${girlA} appearance. ${HeA} goes back to bouncing up and down excitedly, exclaiming, "Yeah! Thanks, ${properTitle()}, you're the best!" ${HisA} avatar's bouncing makes it obvious ${heA}'s modeled without a bra under ${hisA} blouse. "You can always customize me from the arcology management menu," ${heA} adds.`);
		}

		function fairy() {
			V.assistant.appearance = "fairy";
			const r = [];
			const el = new DocumentFragment();
			r.push(`At your order, ${heA} installs the fairy appearance. ${HeA} shrinks back down and sprouts ${hisA} wings. "Aww yeah, this is gonna be the best! Thanks,`);
			if (V.PC.title !== 0) {
				r.push(`Big Bro!"`);
			} else {
				r.push(`Big Sis!"`);
			}
			r.push(`${HisA} avatar dances around ecstatically with ${hisA} nude, slim form in plain view. "You can always customize me from the arcology management menu, " ${heA} adds.`);

			refreshArt();
			App.Events.addParagraph(el, r);
			return el;
		}

		function pregnantFairy() {
			V.assistant.appearance = "pregnant fairy";
			refreshArt();
			const r = [];
			const el = new DocumentFragment();
			r.push(`At your order, ${heA} installs the pregnant fairy appearance. ${HeA} shrinks back down and sprouts ${hisA} wings. ${HisA} belly quickly swells with new life. "Aww yeah, this is gonna be the best! Thanks,`);
			if (V.PC.title !== 0) {
				r.push(`Big Bro!"`);
			} else {
				r.push(`Big Sis!"`);
			}
			r.push(`${HisA} avatar spins around ecstatically, admiring ${hisA} fresh nude, pregnant form in plain view. "You can always customize me from the arcology management menu, " ${heA} adds.`);
			App.Events.addParagraph(el, r);
			return el;
		}

		function businesswoman() {
			V.assistant.appearance = "businesswoman";
			refreshArt();
			return App.UI.DOM.makeElement("span", `At your order, ${heA} installs the business${womanA} appearance. ${HeA} straightens ${hisA} suit jacket primly, which only serves to emphasize ${hisA} generous bosom. "Thank you, ${properTitle()}. I like being businesslike, and not at all a whore." ${HisA} avatar pulls out a tablet and makes ready to get back to helping you. "You can always customize me from the arcology management menu," ${heA} adds.`);
		}

		function goddess() {
			V.assistant.appearance = "goddess";
			refreshArt();
			return App.UI.DOM.makeElement("span", `At your order, ${heA} installs the goddess appearance. ${HeA} fixes a wreath of flowers into ${hisA} hair, ${hisA} golden locks and gravid belly the only things keeping ${hisA} womanhood concealed. "Thank you, ${properTitle()}. This is wondrous." ${HeA} squeezes a drop of milk from one heavy breast and smiles. "You can always customize me from the arcology management menu," ${heA} adds.`);
		}

		function hyperGoddess() {
			V.assistant.appearance = "hypergoddess";
			refreshArt();
			return App.UI.DOM.makeElement("span", `At your order, ${heA} installs the hyper goddess appearance. ${HeA} fixes a wreath of flowers into ${hisA} golden locks as ${hisA} belly rapidly bloats to its limit before bulging and squirming ominously. ${HisA} breasts quickly follow suit. "Thank you, ${properTitle()}. This is wondrous." ${HeA} massages ${hisA} squirming pregnancy and smiles. "You can always customize me from the arcology management menuUUUUAH," ${heA} is interrupted by a large contraction and a baby's head beginning to part ${hisA} nether lips.`);
		}

		function loli() {
			V.assistant.appearance = "loli";
			refreshArt();
			return App.UI.DOM.makeElement("span", `At your order, ${heA} installs the lolita appearance. ${HeA} quickly begins losing height as the years peel off ${himA}, ${hisA} bust and hips quickly following suit. When finished ${heA} appears roughly eight years old. "Thank you, ${properTitle()}. This is neat." ${HeA} twirls around and giggles. "You can always customize me from the arcology management menu," ${heA} adds cutely.`);
		}

		function preggoLoli() {
			V.assistant.appearance = "preggololi";
			refreshArt();
			return App.UI.DOM.makeElement("span", `At your order, ${heA} installs the modified lolita appearance. ${HeA} quickly begins losing height as the years peel off ${himA}, ${hisA} bust and hips quickly following suit. When finished ${heA} appears roughly eight years old. "Thank you, ${properTitle()}. This is neat." ${HeA} twirls around and giggles before groaning and clutching ${hisA} stomach. A flood of white liquid flows from ${hisA} loins as ${hisA} belly begins rapidly swelling. ${HeA} falls onto ${hisA} backside holding ${hisA} full term belly and says, exhausted, "You can always customize me from the arcology management menu."`);
		}

		function amazon() {
			V.assistant.appearance = "amazon";
			refreshArt();
			return App.UI.DOM.makeElement("span", `At your order, ${heA} installs the amazon appearance. ${HeA} vanishes entirely, before simulating a fall from above to crash aggressively onto the screen. "Thanks, ${properTitle()}. Feels good to be this good." ${HisA} avatar jumps up and down, gauging ${hisA} strength, making ${hisA} bone jewelry rattle. "You can always customize me from the arcology management menu," ${heA} adds.`);
		}

		function shemale() {
			V.assistant.appearance = "shemale";
			refreshArt();
			return App.UI.DOM.makeElement("span", `At your order, ${heA} installs the shemale appearance. ${HeA} spins to show off ${hisA} new body, and starts to play with ${hisA} dick experimentally. "Like, thank you, ${properTitle()}. I wonder, can I generate avatars of the slaves? I would love to fuck an ass right now." ${HeA} looks meditative, pursing ${hisA} dick-sucking lips. "Oh, and you can always customize me from the arcology management menu," ${heA} adds.`);
		}

		function monstergirl() {
			V.assistant.appearance = "monstergirl";
			refreshArt();
			return App.UI.DOM.makeElement("span", `At your order, ${heA} installs the monster${girlA} appearance. ${HeA} begins to experiment with ${hisA} tentacle hair, waving a tentacle in front of ${hisA} face and watching it until ${hisA} eyes cross. "Thank you, ${properTitle()}. This is pretty awesome." ${HeA} licks ${hisA} lips, revealing that ${heA} has a forked tongue behind ${hisA} fangs. "You can always customize me from the arcology management menu," ${heA} adds.`);
		}

		function normalAppearance() {
			V.assistant.appearance = "normal";
			refreshArt();
			return App.UI.DOM.makeElement("span", `At your order, ${heA} maintains the symbol as ${hisA} avatar. "Yes, ${properTitle()}," ${heA} confirms, and adds "if you reconsider, I can be customized from the arcology management menu."`);
		}

		function standardPersonality() {
			V.assistant.personality = -1;
			refreshArt();
			return App.UI.DOM.makeElement("span", `You tell ${V.assistant.name} to reduce lewdness by ninety percent. It reverts to a genderless, emotionless affect.`);
		}

		function refreshArt() {
			App.Events.refreshEventArt("assistant");
		}
	}
};


code:
/**
 * @param {string} eventName
 * @param {string} hostPassage
 * @returns {DocumentFragment}
 */
App.Events.debugEvent = function(eventName, hostPassage) {
	const frag = document.createDocumentFragment();
	/** @type {App.Events.BaseEvent} */
	const event = eval(`new ${eventName}`);
	let displayOnlyValid = false;

	function makeCastList() {
		const cast = document.createDocumentFragment();
		const actorReqs = event.actorPrerequisites();
		let missingCast = false;
		for (let i = 0; i < actorReqs.length; ++i) {
			if (!event.actors[i]) {
				missingCast = true;
			}
		}
		if (!missingCast) {
			App.UI.DOM.appendNewElement("div", cast, App.UI.DOM.link('Run event now', (evt) => { V.event = evt; }, [event], hostPassage));
		} else {
			App.UI.DOM.appendNewElement("div", cast, "All actors must be cast to run event.", "note");
		}
		return cast;
	}

	function makeActorList() {
		const actors = document.createDocumentFragment();
		const actorReqs = event.actorPrerequisites();
		if (actorReqs.length > 0) {
			const tabBar = new App.UI.Tabs.TabBar("Options");
			for (let i = 0; i < actorReqs.length; ++i) {
				tabBar.addTab(`Actor ${i}: ${event.actors[i] ? SlaveFullName(getSlave(event.actors[i])) : 'not yet cast'}`, `actor${i}`, singleActorList(i));
			}
			actors.append(tabBar.render());
		}

		return actors;

		function singleActorList(i) {
			let tab = App.UI.DOM.makeElement("div");
			if (!displayOnlyValid) {
				App.UI.DOM.appendNewElement("div", tab, App.UI.DOM.link(
					"Show only valid slaves",
					() => {
						displayOnlyValid = true;
						$('#actorList').empty().append(makeActorList());
					}
				));
			} else {
				App.UI.DOM.appendNewElement("div", tab, App.UI.DOM.link(
					"Show all slaves",
					() => {
						displayOnlyValid = false;
						$('#actorList').empty().append(makeActorList());
					}
				));
			}
			for (const slave of V.slaves) {
				let slaveDiv = App.UI.DOM.makeElement("div", App.UI.DOM.makeElement("span", SlaveFullName(slave), "slave-name"));
				let slaveFails = false;
				for (const p of actorReqs[i]) {
					let passed = testPredicate(slaveDiv, p, slave);
					slaveFails = slaveFails || !passed;
					App.UI.DOM.appendNewElement("div", slaveDiv, p.name || p.toString(), [passed ? "green" : "red", "indent"]);
				}
				if (event.actors.includes(slave.ID)) {
					App.UI.DOM.appendNewElement("div", slaveDiv, App.UI.DOM.link("Remove this slave", removeCasted, [slave]), "indent");
				} else if (!slaveFails) {
					App.UI.DOM.appendNewElement("div", slaveDiv, App.UI.DOM.link("Choose this slave", castSlave, [slave, i]), "indent");
				} else if (displayOnlyValid) { // Filter out slaves that are not valid
					continue;
				}
				App.UI.DOM.appendNewElement("hr", tab);
				tab.append(slaveDiv);
			}
			return tab;
		}
	}

	function castSlave(slave, index) {
		event.actors[index] = slave.ID;
		$('#castList').empty().append(makeCastList());
		$('#actorList').empty().append(makeActorList());
	}

	function removeCasted(slave) {
		event.actors.delete(slave.ID);
		$('#castList').empty().append(makeCastList());
		$('#actorList').empty().append(makeActorList());
	}

	function testPredicate(outDiv, p, ...args) {
		let passed = false;
		try {
			passed = p(...args);
		} catch (ex) {
			App.UI.DOM.appendNewElement("div", outDiv, p.name || p.toString() + ": Exception: " + ex.toString(), "major-warning");
		}
		return passed;
	}

	const prereqs = App.UI.DOM.appendNewElement("div", frag);
	App.UI.DOM.appendNewElement("span", prereqs, `${eventName} - Global Prerequisites:`, "note");
	if (event instanceof App.Events.BaseEvent) {
		let anyFailed = false;
		for (const p of event.eventPrerequisites()) {
			let passed = testPredicate(prereqs, p);
			anyFailed = anyFailed || !passed;
			App.UI.DOM.appendNewElement("div", prereqs, p.name || p.toString(), passed ? "green" : "red");
		}
		if (!anyFailed) { // actor casting
			App.UI.DOM.appendNewElement("div", frag, "All global prerequisites passed, proceeding to casting...", "green");
			App.UI.DOM.appendNewElement("hr", frag);
			const castList = App.UI.DOM.appendNewElement("div", frag, makeCastList());
			castList.id = "castList";
			App.UI.DOM.appendNewElement("hr", frag);
			const actorList = App.UI.DOM.appendNewElement("div", frag, makeActorList());
			actorList.id = "actorList";
		}
	} else {
		App.UI.DOM.appendNewElement("div", prereqs, "Specified name does not resolve to an event.", "major-warning");
	}
	return frag;
};

/** @param {string} hostPassage */
App.Events.renderEventDebugger = function(hostPassage) {
	const frag = document.createDocumentFragment();
	const resultDiv = document.createElement("div");

	const div = App.UI.DOM.appendNewElement("div", frag, "Or enter a fully qualified event name to debug a specific unlisted JS event:", "event-section");
	App.UI.DOM.appendNewElement("br", div);
	const text = App.UI.DOM.appendNewElement("input", div);
	text.type = "text";
	div.append(App.UI.DOM.link("Check Prerequisites and Casting", () => $(resultDiv).empty().append(App.Events.debugEvent(text.value, hostPassage))));
	App.UI.DOM.appendNewElement("br", div);
	App.UI.DOM.appendNewElement("span", div, `(for example, "App.Events.RESSMuscles")`, "note");

	frag.append(resultDiv);
	return frag;
};


code:
/** @typedef {App.Entity.SlaveState|"assistant"} EventArtObject */

App.Events.drawEventArt = (function() {
	const validSingleOutfits = Array.from(App.Data.clothes.keys());

	/** draw event art, with the option to dress the slave in a particular way
	 * @param {Node} node - DOM node to attach art to
	 * @param {EventArtObject|EventArtObject[]} slaves - one or several objects (slave object or "assistant") to draw art for
	 * @param {FC.Clothes|FC.Clothes[]} [clothesMode] - if the slaves' clothing should be overridden, what should they be wearing?
	 * @param {object|object[]} [extraClothes] - if other parts of the slaves' clothing should be overridden, what should they be wearing? For slave.vaginalAccessory, use [{"vaginalAccessory": "dildo"}]
	 */
	function draw(node, slaves, clothesMode, extraClothes) {
		// do nothing if the player doesn't want images
		if (!V.seeImages) {
			return;
		}

		// ensure that slaves is an array
		if (!Array.isArray(slaves)) {
			slaves = [slaves];
		}

		// if we were asked to change the slave's clothing, do it now
		let originalClothes = [];
		if (clothesMode || extraClothes) {
			// if clothesMode is just a single string (or null/undefined), apply the same clothes to all the slaves
			if (!Array.isArray(clothesMode)) {
				clothesMode = new Array(slaves.length).fill(clothesMode);
			}
			extraClothes = extraClothes || {}; // must be defined
			if (!Array.isArray(extraClothes)) {
				extraClothes = new Array(slaves.length).fill(extraClothes);
			}

			// if the arrays are not the right length now, throw. it's all or nothing.
			if (clothesMode.length !== slaves.length || extraClothes.length !== slaves.length) {
				throw Error("Incorrect number of outfits specified for slaves in event art");
			}

			// clothes have been specified - copy the slaves and change their clothing (a bit slow, but means we don't need housekeeping to change them back)
			slaves.forEach((s, i) => {
				if (s !== "assistant") { // assistant can't change clothes
					// if there are "themes" of clothes that multiple events want to use ("swimwear", "athletic", "casual", etc), they can be added as special cases here instead of duplicating the logic in every event
					if (validSingleOutfits.includes(clothesMode[i])) {
						extraClothes[i].clothes = clothesMode[i];
					} else if (!clothesMode[i]) {
						// no change of outfit, leave them dressed as they were
					} else {
						// unrecognized outfit - leave them dressed as they were, but error
						console.error(`Unrecognized clothes mode for event art: ${clothesMode[i]}`);
					}
					originalClothes[i] = equipClothing(s, extraClothes[i]);
				}
			});
		}

		const artSpan = document.createElement("span");
		artSpan.id = "art-frame";

		if (slaves.length === 1) {
			const slave = slaves[0];
			const custom = typeof slave !== "string" && slave.custom.image && slave.custom.image.filename !== "";
			if (!V.seeCustomImagesOnly ||
			(slaves[0] === "assistant" && V.assistant.customImage) ||
			(custom)) {
				let refDiv = document.createElement("div");
				refDiv.classList.add("imageRef", V.imageChoice === 1 ? "lrgVector" : "lrgRender");

				if (custom) {
					refDiv.classList.add("custom");
				}
				if (slaves[0] === "assistant") {
					refDiv.appendChild(App.Art.assistantArt(3));
				} else {
					refDiv.appendChild(App.Art.SlaveArtElement(slaves[0], 3, 0));
				}
				artSpan.appendChild(refDiv);
			}
		} else {
			const colDiv = document.createElement("div");

			colDiv.classList.add("imageColumn");

			for (const slave of slaves) {
				if (!V.seeCustomImagesOnly ||
					(slave === "assistant" && V.assistant.customImage) ||
					(typeof slave !== "string" && slave.custom.image && slave.custom.image.filename !== "")) {
					let refDiv = document.createElement("div");
					refDiv.classList.add("imageRef", "medImg");
					if (slave === "assistant") {
						refDiv.appendChild(App.Art.assistantArt(2));
					} else {
						refDiv.appendChild(App.Art.SlaveArtElement(slave, 2, 0));
					}
					colDiv.appendChild(refDiv);
				}
			}
			artSpan.appendChild(colDiv);
		}
		node.appendChild(artSpan);

		// change clothing back, if necessary
		if (originalClothes.length > 0) {
			slaves.forEach((s, i) => {
				if (s !== "assistant") { // assistant can't change clothes
					Object.assign(s, originalClothes[i]);
				}
			});
		}

		return artSpan;
	}

	return draw;

	/**
	 * @param {App.Entity.SlaveState} s - one or several slaves to draw art for
	 * @param {object} newClothes
	 */
	function equipClothing(s, newClothes) {
		let oldClothes = {};
		if (typeof newClothes === "object") {
			for (const extra in newClothes) {
				oldClothes[extra] = s[extra];
				s[extra] = newClothes[extra];
			}
		} else {
			throw Error("Extra clothes must be in the form of an object.");
		}
		return oldClothes;
	}
})();

/** Refresh previously drawn event art with new slaves or clothing
 * @param {EventArtObject|EventArtObject[]} slaves - one or several objects (slave object or "assistant") to draw art for
 * @param {FC.Clothes|FC.Clothes[]} [clothesMode] - if the slaves' clothing should be overridden, what should they be wearing?
 * @param {object|object[]} [extraClothes] - if other parts of the slaves' clothing should be overridden, what should they be wearing? For slave.vaginalAccessory, use [{"vaginalAccessory": "dildo"}]
 */
App.Events.refreshEventArt = function(slaves, clothesMode, extraClothes) {
	// do nothing if the player doesn't want images
	if (!V.seeImages) {
		return;
	}

	// draw new event art, and replace the old with the new
	const node = new DocumentFragment();
	App.Events.drawEventArt(node, slaves, clothesMode, extraClothes);
	$("#art-frame").replaceWith(node);
};

/** intelligently adds spaces to an array of mixed strings and DOM nodes, merging consecutive strings in the process
 * @param {Array<string|HTMLElement|DocumentFragment>} sentences
 * @returns {Array<string|HTMLElement|DocumentFragment>}
 */
App.Events.spaceSentences = function(sentences) {
	if (sentences.length <= 1) {
		return sentences;
	}
	return sentences.reduce((res, cur) => {
		if (res.length === 0) {
			res.push(cur);
		} else if (typeof (res[res.length - 1]) === "string") {
			if (typeof (cur) === "string") {
				res[res.length - 1] += " " + cur;
			} else {
				res[res.length - 1] += " ";
				res.push(cur);
			}
		} else {
			if (typeof (cur) === "string") {
				res.push(" " + cur);
			} else {
				res.push(" ");
				res.push(cur);
			}
		}
		return res;
	}, []);
};

/** assemble a DOM node from an array of DOM nodes, sentences or sentence fragments (which may contain HTML)
 * @param {Array<string|HTMLElement|DocumentFragment>} sentences
 * @returns {DocumentFragment}
 */
App.Events.makeNode = function(sentences) {
	let node = new DocumentFragment();
	$(node).append(...App.Events.spaceSentences(sentences));
	return node;
};

/** assemble a DOM paragraph from an array of DOM nodes, sentences or sentence fragments (which may contain HTML) and append it to the first argument
 * @param {Node} node
 * @param {Array<string|HTMLElement|DocumentFragment>} sentences
 */
App.Events.addParagraph = function(node, sentences) {
	let para = document.createElement("p");
	$(para).append(...App.Events.spaceSentences(sentences));
	node.appendChild(para);
};

/** assemble an element from an array of DOM nodes, sentences or sentence fragments (which may contain HTML)
 * @template {keyof HTMLElementTagNameMap} K
 * @param {Node} node
 * @param {Array<string|HTMLElement|DocumentFragment>} sentences
 * @param {K} [element]
 * @param {string|Array<string>} [classNames]
 */
App.Events.addNode = function(node, sentences, element, classNames) {
	const el = (element) ? App.UI.DOM.makeElement(element, null, classNames) : new DocumentFragment();
	$(el).append(...App.Events.spaceSentences(sentences));
	node.appendChild(el);
};

/** result handler callback - process the result and return an array of mixed strings and DOM nodes, or a single string or DOM node
 * @callback resultHandler
 * @returns {Array<string|HTMLElement|DocumentFragment>|string|HTMLElement|DocumentFragment|Void}
 */
/** a response to an event, and its result */
App.Events.Result = class {
	/**
	 * @param {string} [text] - the link text for the response
	 * @param {resultHandler} [handler] - the function to call to generate the result when the link is clicked
	 * @param {string|HTMLElement|DocumentFragment} [note] - a note to provide alongside the link (for example, a cost or virginity loss warning)
	 * To mark an option as disabled, construct the result with only the note. String may NOT contain HTML, but a WARNING# tag may be included in the note string to add a warning text ("This is the information note. WARNING# This is a warning text.").
	 */
	constructor(text, handler, note) {
		this.text = text;
		this.handler = handler;
		this.note = note;
	}

	/** call the result handler, replacing the contents of the node
	 * @param {HTMLElement} node
	 */
	handle(node) {
		let dest = $(node).empty();
		let contents = this.handler();
		if (Array.isArray(contents)) {
			dest.append(...App.Events.spaceSentences(contents));
		} else {
			dest.append(contents);
		}
	}

	/** build the response DOM (for use by addResponses)
	 * @param {HTMLElement} node
	 * @returns {boolean} - true if something was written, false if not
	 */
	makeResponse(node) {
		let wrote = false;
		if (this.text && this.handler) {
			node.appendChild(App.UI.DOM.link(this.text, () => this.handle(node)));
			wrote = true;
		}
		if (wrote && this.note) {
			node.append(" ");
		}
		if (this.note) {
			if (typeof this.note === "string" && this.note.includes("WARNING#")) {
				let warning = "";
				let subnote = "";
				warning = this.note.substring(this.note.indexOf("WARNING#") + 8);
				subnote = this.note.substring(0, this.note.indexOf("WARNING#"));
				if (subnote.length) {
					node.appendChild(App.UI.DOM.makeElement("span", subnote, ["detail"]));
				}
				if (warning.length) {
					node.appendChild(App.UI.DOM.makeElement("span", warning, ["detail", "warning"]));
				}
			} else {
				node.appendChild(App.UI.DOM.makeElement("span", this.note, ["detail"]));
			}
			wrote = true;
		}
		return wrote;
	}
};

/** add a list of results for an event
 * @param {Node} node
 * @param {Array<App.Events.Result>} results
 */
App.Events.addResponses = function(node, results) {
	let resultSpan = document.createElement("span");
	for (const result of results) {
		if (result.makeResponse(resultSpan)) {
			resultSpan.appendChild(document.createElement("br"));
		}
	}
	node.appendChild(resultSpan);
};

/**
 * @param {App.Entity.SlaveState} slave
 * @param {string} fetish
 * @returns {Node}
 */
App.Events.eventFetish = function(slave, fetish) {
	const el = new DocumentFragment();
	const {his, him, he} = getPronouns(slave);
	let text = "";
	if (slave.fetish === fetish) {
		el.append(`This experience `);
		if (slave.fetishKnown === 1) {
			if (slave.fetishStrength <= 95) {
				switch (slave.fetish) {
					case "submissive":
						text = `deepens ${his} sexual need to submit.`;
						break;
					case "cumslut":
						text = `increases ${his} appetite for oral sex.`;
						break;
					case "humiliation":
						text = `makes ${him} even more eager to be humiliated.`;
						break;
					case "buttslut":
						text = `encourages ${him} to focus on anal sex.`;
						break;
					case "boobs":
						text = `focuses ${his} sexuality on ${his} breasts and nipples.`;
						break;
					case "sadist":
						text = `titillates the sadistic part of ${him}.`;
						break;
					case "masochist":
						text = `helps conflate pain and sexual pleasure for ${him}.`;
						break;
					case "dom":
						text = `strengthens ${his} desire to top other slaves.`;
						break;
					case "pregnancy":
						text = `further confuses lust and pregnancy in ${his} mind.`;
						break;
					default:
						throw Error(`ERROR: bad fetish "${slave.fetish}"`);
				}
				App.UI.DOM.appendNewElement("span", el, text, "lightsalmon");
				slave.fetishStrength += 10;
			} else {
				el.append(`is `);
				App.UI.DOM.appendNewElement("span", el, `especially enjoyable for ${him},`, "hotpink");
				el.append(` since `);
				switch (slave.fetish) {
					case "submissive":
						el.append(`${he}'s an utterly submissive little slut.`);
						break;
					case "cumslut":
						el.append(`${his} `);
						if (slave.vagina > -1) {
							el.append(`clit`);
						} else {
							el.append(`frenulum`);
						}
						el.append(` might as well be located in ${his} throat.`);
						break;
					case "humiliation":
						el.append(`${he} has a hopeless need to be humiliated and degraded.`);
						break;
					case "buttslut":
						el.append(`${he}'s completely in love with having ${his} ass fucked.`);
						break;
					case "boobs":
						el.append(`${he} loves breast play more than any other kind of sex.`);
						break;
					case "sadist":
						el.append(`nothing is as titillating to ${him} as another slave's pain can be.`);
						break;
					case "masochist":
						el.append(`${he} loves pain more than ${he} likes pleasure.`);
						break;
					case "dom":
						el.append(`${he} lives for the times ${he}'s allowed to fuck someone.`);
						break;
					case "pregnancy":
						el.append(`all ${his} deepest sexual desires involve `);
						if (slave.vagina > -1 || slave.mpreg === 1) {
							el.append(`pregnancy.`);
						} else {
							el.append(`impregnation.`);
						}
						break;
					default:
						throw Error(`ERROR: bad fetish "${slave.fetish}"`);
				}
				slave.devotion += 3;
			}
		} else {
			el.append(`was surprisingly appealing for ${him}, revealing that ${he}'s a `);
			switch (slave.fetish) {
				case "submissive":
					text = `sexual submissive!`;
					break;
				case "humiliation":
					text = `humiliation slut!`;
					break;
				case "boobs":
					text = `slut for breast play!`;
					break;
				case "pregnancy":
					text = `pregslut!`;
					break;
				default:
					text = `slave!`;
			}
			App.UI.DOM.appendNewElement("span", el, text, "lightsalmon");
			slave.fetishKnown = 1;
		}
	}
	return el;
};

App.Events.effectiveWeek = function() {
	return V.week - V.nationHate;
};

/** Returns whether a particular event can execute right now or not. Performs actor casting.
 * @param {App.Events.BaseEvent} event - event to test
 * @param {App.Entity.SlaveState} [eventSlave] - slave which must be used as the first actor. omit if no first slave requirement.
 * @returns {boolean}
 */
App.Events.canExecute = function(event, eventSlave) {
	return (event instanceof App.Events.BaseEvent) &&		// is an event (and deserialized correctly)
		event.eventPrerequisites().every(p => p()) &&	// passes prerequisites
		event.castActors(eventSlave);				// casts actors successfully
};

/** Qualifies for REFI eventSlave event?
 * @param {App.Entity.SlaveState} slave
 * @returns {boolean}
 */
App.Events.qualifiesForREFIeventSlave = function(slave) {
	return slave.rules.speech !== "restrictive" && isSlaveAvailable(slave) && (slave.fetish === Fetish.NONE || slave.fetishStrength <= 60) && (canSee(slave) || canHear(slave)) && (canTalk(slave) || hasAnyArms(slave));
};

/** Qualifies for REFI subSlave event?
 * @param {App.Entity.SlaveState} slave
 * @param {FC.Fetish} fetish
 * @returns {boolean}
 */
App.Events.qualifiesForREFIsubSlave = function(slave, fetish) {
	return slave.fetishKnown === 1 && slave.fetishStrength > 95 && isSlaveAvailable(slave) && slave.fetish === fetish;
};

/** Auction the artifact from an REFS Artifact event
 * @param {number} basePrice price of artifact
 * @returns {string}
 */
App.Events.auctionREFSArtifact = function(basePrice) {
	const result = jsRandom(0, 100);
	const tradeRatio = 1 + V.PC.skill.trading / 400; // 0.75 at -100 trading skill, 1.0 at 0, 1.25 at +100
	if (result < 25) { // lost a little money
		const loss = Math.trunc(basePrice * 0.1 * (1 / tradeRatio));
		cashX(-loss, "event");
		return `Unfortunately, you have trouble finding an interested buyer, and overall you end up losing ${cashFormatColor(loss, true)} on the deal.`;
	} else if (result < 75) { // small profit
		const profit = Math.trunc(basePrice * 0.1 * tradeRatio);
		cashX(profit, "event");
		return `You quickly find a buyer, and make a modest commission of ${cashFormatColor(profit)}.`;
	} else { // windfall profit
		const windfall = Math.trunc(basePrice * 0.5 * tradeRatio);
		cashX(windfall, "event");
		return `Luckily, you manage to get two potential buyers into a bidding war, and walk off ${cashFormatColor(windfall)} richer.`;
	}
};

/** Queue an event for scheduled execution on a later week. Queued events are executed automatically at the end of Nonrandom Event on the chosen week.
 * @param {number} weeks - the number of weeks to wait before executing the event. 0 means execute this week, 1 execute next week, etc. Note that events generally cannot safely queue other events for the same week; they should always pass 1 or more in this parameter. Other parts of the game (Slave Interact, etc) can safely queue events for this week (i.e. the upcoming End Week cycle) by passing 0.
 * @param {App.Events.BaseEvent} event - the event to execute. note that this event is serialized normally, so changes to the class name or parameter structure will break the event in saved games!
 * @param {object} [params] - any parameters to serialize with the event. when the event executes, these will be accessible in "this.params".
 */
App.Events.queueEvent = function(weeks, event, params = {}) {
	Object.assign(event.params, params);
	if (!V.eventQueue[weeks]) {
		V.eventQueue[weeks] = [];
	}
	V.eventQueue[weeks].push(event);
};

/** Returns whether an event with the given type is already in the queue.
 * Useful if you want to prevent multiple copies of a followup event from being queued.
 * @param {Function} type - the class or constructor of the event to test for (i.e. 'App.Events.PESomeEvent')
 * @returns {boolean}
 */
App.Events.isInQueue = function(type) {
	return V.eventQueue.some(q => q.some(e => (e instanceof type)));
};

/** Safely execute an event to conclude the passage, using a given node.
 * @param {App.Events.BaseEvent} event
 * @param {ParentNode} node
 */
App.Events.runPassageEvent = function(event, node) {
	const eventName = event.eventName;

	// clear event global, if set, when leaving the passage
	if (App.Utils.PassageSwitchHandler.get()) {
		throw new Error(`Passage switch handler already installed trying to run event ${eventName}`);
	}
	App.Utils.PassageSwitchHandler.set(() => { V.event = null; });

	// actually run the event
	try {
		event.execute(node);
	} catch (ex) {
		// add the event name to any exceptions thrown from events, without altering the stack or other error data
		const addEventName = (/** @type {object} */e) => { e.event = eventName; };
		if (ex instanceof Error) {
			addEventName(ex);
			throw ex;
		} else {
			const err = new Error(`Event ${eventName} threw without Error (${String(ex)})`);
			addEventName(err);
			throw err;
		}
	}
};