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

	/** Custom casting: all slaves ready for retirement are cast automatically. if no slaves are cast, casting fails and the event does not run. */
	castActors() {
		this.actors = V.slaves.filter(s => retirementReady(s)).map(s => s.ID);
		return this.actors.length > 0;
	}

	execute(node) {
		const artRenderer = V.seeImages && V.seeReportImages ? new App.Art.SlaveArtBatch(this.actors, 2, 0) : null;
		if (artRenderer) {
			node.append(artRenderer.writePreamble());
		}

		for (const id of this.actors) {
			const slave = getSlave(id);
			if (slave) {
				App.UI.DOM.appendNewElement("div", node, retireScene(slave));
				node.append(sectionBreak());
			}
		}

		function sectionBreak() {
			const hr = document.createElement("hr");
			hr.style.margin = "0";
			return hr;
		}
	}
};

/**
 * @param {App.Entity.SlaveState} originalSlave
 * @param {App.Art.SlaveArtBatch} [artRenderer]
 */
globalThis.retireScene = function(originalSlave, artRenderer) {
	const el = new DocumentFragment();
	const slave = clone(originalSlave);
	removeSlave(originalSlave);
	let r = [];
	const {
		He, His, Him,
		he, his, him, himself, wife, woman, girl
	} = getPronouns(slave);
	const {title: Master} = getEnunciation(slave);
	let his2;
	let He2;
	let he2;
	let him2;
	let girl2;
	const lover = slave.relationship > 3 ? getSlave(slave.relationshipTarget) : null;
	if (lover) {
		({
			his2, He2, he2, him2, girl2
		} = getPronouns(lover).appendSuffix("2"));
	}

	const {heU, hisU, himU, girlU} = getNonlocalPronouns(V.seeDicks).appendSuffix('U');
	const art = (V.seeImages) ? App.UI.DOM.drawOneSlaveRight(el, slave, artRenderer) : document.createElement("div");

	const desc = App.UI.DOM.appendNewElement("div", el);
	const result = App.UI.DOM.appendNewElement("div", el);

	r.push(App.UI.DOM.slaveDescriptionDialog(slave));
	r.push(`is retiring from sexual slavery this week,`);

	if (V.policies.retirement.fate === "citizen") {
		r.push(`in a way that will fill the rest of your property with envy and <span class="mediumaquamarine">trust.</span>`);
		for (const s of V.slaves) {
			s.trust += 3;
		}
		if (lover) {
			r.push(`${lover.slaveName}, for ${his2} part, is overjoyed, though also a bit sad. Although ${he2} knows ${he2} will ${lover.assignment} for a while longer, ${he2} looks forward to joining ${slave.slaveName} one day.`);
			lover.devotion += 10;
		}
		App.Events.addParagraph(desc, r);
		r = [];

		r.push(`${He} is retiring into citizenship, with a substantial annuity that will provide ${him} with a secure if not luxurious life.`);
		if (slave.relationship === -3) {
			if (slave.fetish === "mindbroken") {
				r.push(`Sadly, ${he} is not mentally equipped to look after ${himself}, but the arcology hosts several fine institutions capable of caring for ${him}. They'll have someone check in on ${him} daily. ${Him} being your ${wife} is ultimately irrelevant; ${he} never realized it in the first place.`);
			} else if (slave.devotion + slave.trust >= 175) {
				r.push(`${He} wishes ${he} could continue to be your slave ${wife}, but ${he} understands that marriages between slaves and slaveowners are predicated on the slave relationship. ${He} knows that ${his} retirement has come, meaning that ${his} slave relationship to you is ending. ${He}'s had a long time to get used to the idea, and gets through the process with dignity, doing ${his} best to avoid embarrassing you.`);
			} else if (slave.devotion < -20 && slave.trust > 20) {
				r.push(`${He} is glad ${he} no longer has to be your slave ${wife}, as ${he} never wanted to be in the first place, though ${he} will miss taking advantage of the position. ${He} understands that marriages between slaves and slaveowners are predicated on the slave relationship. ${He} knows that ${his} retirement has come, meaning that ${his} slave relationship to you is ending. ${He}'s had a long time to dream of the idea, and goes through the process with unremitting joy, doing ${his} best to embarrass you.`);
			} else if (slave.devotion < -20) {
				r.push(`${He} is glad ${he} no longer has to be your slave ${wife}, as ${he} never wanted to be in the first place. ${He} understands that marriages between slaves and slaveowners are predicated on the slave relationship. ${He} knows that ${his} retirement has come, meaning that ${his} slave relationship to you is ending. ${He}'s had a long time to dream of the idea, and goes through the process with unremitting joy, doing ${his} best to avoid embarrassing you while ${he}'s still subject to your whims and your punishments.`);
			} else {
				r.push(`${He} is glad ${he} no longer has to be your slave ${wife}, as ${he} never wanted to be in the first place. ${He} understands that marriages between slaves and slaveowners are predicated on the slave relationship. ${He} knows that ${his} retirement has come, meaning that ${his} slave relationship to you is ending. ${He}'s had a long time to get used to the idea, and gets through the process dutifully, doing ${his} best to avoid embarrassing you.`);
			}
		} else if (slave.fetish === "mindbroken" || slave.actualAge < 3) {
			r.push(`Sadly, ${he} is not mentally equipped to look after ${himself}, but the arcology hosts several fine institutions capable of caring for ${him}. They'll have someone check in on ${him} daily.`);
		} else if (slave.devotion > 95) {
			r.push(`${He} desperately wishes ${he} could continue to be your sex slave, but ${he} understands that ${his} retirement has come. More importantly, ${he}'s had a long time to get used to the idea, and gets through the process with resolution, doing ${his} best to avoid embarrassing ${himself} or you.`);
		} else if (slave.devotion > 20) {
			r.push(`${He} is very happy to be a free person again, though ${he} does ${his} best to do you the favor of not being too ostentatious about this.`);
		} else {
			r.push(`It is with an ill-disguised triumphalism that ${he} leaves sexual slavery behind ${him}, and enters into a life in which ${he} can decline to have things inserted into ${his} body.`);
		}
		r.push(`${He}'s certainly going to have some adjustments to make.`);
		if (slave.energy > 90) {
			r.push(`Notably, dealing with ${his} formidable sex drive is now ${his} business. You suspect the arcology's clubs are about to receive a fanatical new regular, and the arcology's whores may not know what hit them when ${he} realizes that ${he}'s now quite capable of buying whatever ${he} wants on a semi-regular basis.`);
			if (slave.skill.anal + slave.skill.oral >= 120) {
				r.push(`${He}'s so sexually skilled, though, that ${he} probably won't have much trouble. ${He}'ll probably have more than a few eager lovers within days.`);
			}
			if (slave.face > 40) {
				r.push(`${He}'s certainly attractive enough that ${he}'ll have no trouble finding as many casual hookups as ${he} likes.`);
			}
		}
		App.Events.addParagraph(desc, r);
		r = [];
		if (slave.prestigeDesc && slave.prestigeDesc.includes("Head Girl") || V.HeadGirlID === slave.ID) {
			r.push(`${He} has a reputation from ${his} long service as your Head Girl. To ${his} bemusement, and considerable satisfaction, ${he} has multiple job offers from slaving operations without even having to circulate ${his} resume.`);
			if (slave.fetish === "sadist") {
				r.push(`The prospect of a virtually unlimited field for abuse and rape is something ${he}'d pay for, now that ${he} has ${his} own money. ${He}'s excited beyond description to find that there are people interested in paying ${him} to exercise ${his} exquisitely horrible skills.`);
			} else if (slave.fetish === "dom") {
				r.push(`Dominance is second nature to ${him}. Though ${he} doesn't have to work, ${his} slaving skills are valuable enough that ${he}'d probably be tempted by the pay ${he} can expect, even if ${he} didn't derive real pleasure from exercising them.`);
			} else {
				r.push(`${His} annuity means that ${he} doesn't have to work, but ${he}'s inclined to do so. ${His} skills command reasonable wages in the slave training field, and between those prospects and ${his} annuity, ${he} stands to become wealthy.`);
			}
		} else if (slave.porn.prestigeDesc && slave.porn.prestigeDesc.includes("is world famous for")) {
			let pornFame = slave.porn.prestigeDesc;
			pornFame = pornFame.replace("$He is world famous for $his career in slave pornography. Millions are intimately familiar with", "enjoy");
			pornFame = pornFame.replace(".", ",");
			r.push(`In addition to ${his} annuity, you've laid the groundwork for ${him} to become wealthy by the way you publicized pornography of ${him}. Many thousands of people across the world are willing to pay to ${pornFame} and they enjoy it in part because ${he} doesn't mind it, either. ${He}'s in a position to make great money for doing on camera what ${he} would probably do anyway.`);
		} else if ((slave.intelligence + slave.intelligenceImplant >= -50) && (slave.muscles > 5) && (slave.skill.combat >= 1) && hasAllLimbs(slave) && (slave.face > 10)) {
			r.push(`${He}'s pretty and deadly. If ${he} feels ${he} prefers wealth and danger to living on ${his} annuity, ${he}'ll have no trouble finding work. In fact, ${he}'ll likely have trouble sifting through all the mercenary organizations, businesses in need of attractive and competent guards for public spaces, and citizens looking for effective bodyguards willing to hire ${him}.`);
		} else if ((slave.intelligence + slave.intelligenceImplant > 50) && (slave.intelligenceImplant >= 15)) {
			r.push(`${He} has no skills extraordinary enough to bring prospective employers in search of ${him}, in this new, slaveowning economy, but ${he} is highly intelligent, educated, and has a small income. As you know from your own abundant personal experience, ${his} intelligence is a lever, ${his} annuity is a fulcrum, and with the two, ${he} may move the world someday. You have no doubt that, at the very least, ${he} will be far from the poorest of your citizens.`);
		}
		App.Events.addParagraph(desc, r);
		r = [];
		r.push(`As ${he} takes ${his} leave, heading the short distance down to ${his} modest little apartment, ${he} presents a strange appearance. ${He}'s wearing cheap but not unattractive clothing, and you are struck by a crystal-clear mental image of what ${he} looks like nude.`);
		if (slave.fetish !== "mindbroken") {
			if (slave.devotion > 20) {
				if (slave.devotion > 95) {
					r.push(`${He}'s doing ${his} absolute best not to sob, but ${his} lips are quivering.`);
				} else {
					r.push(`${He} looks like ${he} might cry.`);
				}
				if (!canTalk(slave)) {
					r.push(`${He} gestures ${his} thanks, and ironically indicates that ${he}'ll see you around.`);
				} else {
					r.push(Spoken(slave, `"Well, thanks, ${Master}, um, I mean ${V.PC.slaveName}. I g-guess I'll see you around${(!canSee(slave)) ? `, uh, as they say` : ``}. I mean, the arcology. Anyway. Bye."`));
				}
				if (slave.devotion > 95) {
					r.push(`${He} turns resolutely away and flees, trying to choke back ${his} tears.`);
				} else {
					r.push(`${He} turns resolutely away.`);
				}
			}
		}
		App.Events.addParagraph(desc, r);
		r = [];
		if (slave.relationship === -3) {
			r.push(`When you return to your desk you realize something.`);
			if (slave.fetish === "mindbroken") {
				r.push(`The ring ${he} wore when ${he} was your slave ${wife} is nowhere to be seen; ${he}'s likely forgotten ${he} was wearing it, but no matter: you can always get more.`);
			} else if (slave.devotion + slave.trust >= 175) {
				r.push(`The ring ${he} wore when ${he} was your slave ${wife} is nowhere to be seen; ${he}'s likely taken it with ${him} to remember you by.`);
			} else if (slave.devotion < -20 && slave.trust > 20) {
				r.push(`The ring ${he} wore when ${he} was your slave ${wife} is nowhere to be seen; ${he}'s likely taken it with ${him} to either try and pawn or to dispose of. It doesn't matter: you can always get more.`);
			} else if (slave.devotion < -20) {
				r.push(`The ring ${he} wore when ${he} was your slave ${wife} was left on your desk; ${he} likely ripped it off as soon as ${he} was free.`);
			} else {
				r.push(`The ring ${he} wore when ${he} was your slave ${wife} is nowhere to be seen; ${he}'s either taken it with ${him} as a souvenir, or left it back in ${his} sleeping area. If it's the former, no matter: you can always get more.`);
			}
			App.Events.addNode(el, r, "div");
			r = [];
		}

		r.push(`Your arcology has gained a well-off citizen.`);
		V.upperClass += 1;

		if (slave.energy > 50) {
			if (slave.devotion > 20) {
				App.UI.DOM.appendNewElement("div", result, App.UI.DOM.link(
					`See ${him} around`,
					() => {
						const r = [];
						const el = new DocumentFragment();
						r.push(`Later that week,`);
						if (V.club > 0) {
							r.push(`as you take an evening to enjoy ${V.clubName} in person,`);
						} else {
							r.push(`out in one of ${V.arcologies[0].name}'s better clubs,`);
						}
						r.push(`you run into ${slave.slaveName}. ${He} looks good, and happy, and is not at all displeased to see you. ${He} sidles up to you and makes it clear without a`);
						if (!canTalk(slave)) {
							r.push(`gesture`);
						} else {
							r.push(`word`);
						}
						r.push(`that ${he}'s quite eager to fuck you as a free ${woman}.`);
						if (slave.relationship === -3) {
							if (slave.devotion + slave.trust >= 175) {
								r.push(`When ${he} knows ${he} has your attention, ${he} flashes`);
								if (hasAnyArms(slave)) {
									r.push(`${his} hand, revealing the steel ring that ${he} wore when ${he} was your slave ${wife}.`);
								} else {
									r.push(`the steel ring that ${he} wore when ${he} was your slave ${wife} attached to the same chain you placed around ${his} neck on your wedding.`);
								}
								r.push(`Even though the ring is meaningless to society, it holds a special meaning to you and ${him}.`);
							} else {
								r.push(`When ${he} knows ${he} has your attention, ${he} produces the steel ring that ${he} wore when ${he} was your slave ${wife}. ${He} doesn't put it on, but ${he} kisses it suggestively before putting it back in ${his} purse.`);
							}
						}
						if (slave.fetish === "submissive" && slave.fetishKnown === 1) {
							r.push(`Taking the lead as you know ${he} prefers, you lead ${him} to a private booth and make love to ${him}, holding ${him} down with the gentle but firm grip that never fails to bring ${him} through a long and gasping climax.`);
						} else if (slave.fetish === "cumslut" && slave.fetishKnown === 1) {
							r.push(`${He}`);
							if (V.PC.dick !== 0) {
								r.push(`sucks your dick`);
								if (V.PC.vagina !== -1) {
									r.push(`and`);
								}
							}
							if (V.PC.vagina !== -1) {
								r.push(`eats you out`);
							}
							r.push(`right there, eagerly`);
							if (slave.vagina > -1) {
								r.push(`jilling off`);
							} else {
								r.push(`jacking off`);
							}
							r.push(`as ${he} enjoys your infinitely familiar`);
							if (canTaste(slave) && canSmell(slave)) {
								r.push(`taste and scent.`);
							} else if (canTaste(slave)) {
								r.push(`taste.`);
							} else if (canSmell(slave)) {
								r.push(`scent.`);
							} else {
								r.push(`body.`);
							}
						} else if (slave.fetish === "humiliation" && slave.fetishKnown === 1) {
							r.push(`You take ${him} right there, the humiliation slut getting what ${he} came to the club to get: an opportunity to orgasm in public with many eyes enjoying the sight of ${his} pleasure.`);
						} else if (slave.fetish === "buttslut" && slave.fetishKnown === 1) {
							r.push(`Your`);
							if (V.PC.dick !== 0) {
								r.push(`dick is`);
							} else {
								r.push(`fingers are`);
							}
							r.push(`up ${his} ass in no time, and ${he}'s so primed for anal that ${he} climaxes with indecent speed. ${He} begs you to keep fucking ${his} butt, and you do.`);
						} else if (slave.fetish === "boobs" && slave.fetishKnown === 1) {
							r.push(`${He} grinds shamelessly against you, your hands holding ${his} breasts just the way you know ${he} loves them held. Your`);
							if (V.PC.boobs >= 300) {
								r.push(`own tits press softly`);
							} else if (V.PC.title === 0) {
								r.push(`flat chest presses`);
							} else {
								r.push(`manly chest presses`);
							}
							r.push(`against ${his} back as ${he} cranes back to kiss you.`);
						} else if (slave.fetish === "pregnancy" && slave.fetishKnown === 1) {
							r.push(`${He} begs shamelessly for your seed, right here and right now, and`);
							if (V.PC.dick !== 0) {
								r.push(`you give it to ${him}, producing the usual perverted orgasm as ${he} feels it inside ${him}.`);
							} else {
								r.push(`as usual, ${he} doesn't care that the phallus you fuck ${him} with is actually a strap-on. ${He} manages to pretend it's a cock knocking ${him} up.`);
							}
						} else if (slave.fetish === "dom" && slave.fetishKnown === 1) {
							r.push(`After some mutually aggressive dancing that leaves you both panting and sweaty, you work together to attract another free dancer, a ${girlU} who ${slave.slaveName} had ${his} eye on already. Before long, the poor ${girlU} is screaming with orgasm in a private booth as you take ${himU} together.`);
						} else if (slave.fetish === "sadist" && slave.fetishKnown === 1) {
							r.push(`After some mutually aggressive dancing that leaves you both panting and sweaty, you mutually select one of the club's slaves, and drag ${himU} back to a private booth. Before long, ${hisU} screams for mercy are audible on the floor.`);
						} else if (slave.fetish === "masochist" && slave.fetishKnown === 1) {
							r.push(`You don't have the setup for really elaborate pain, so you fuck ${him} hard and fast, to give ${him} that edge of discomfort that ${he} now requires to get off. ${He} gasps as ${he} gets what ${he} needs, not free of ${his} perversions despite ${his} status as a citizen.`);
						} else {
							r.push(`You remember ${his} uncomplicated tastes well, though the total confidence that ${his} willingness and pleasure are unfeigned is novel. You dance, you laugh, and you make love to ${him}, all through the night.`);
						}
						App.Events.addNode(el, r);
						jQuery(result).empty().append(el);
					}
				));
				if (lover) {
					App.UI.DOM.appendNewElement("div", result, App.UI.DOM.link(
						`Send ${his} ${girl2} into retirement with ${him}`,
						() => {
							const el = new DocumentFragment();
							let r = [];
							if (V.seeImages) {
								let colDiv = document.createElement("div");
								colDiv.classList.add("imageColumn");
								App.UI.DOM.drawOneSlaveRight(colDiv, slave);
								App.UI.DOM.drawOneSlaveRight(colDiv, lover);
								jQuery(art).replaceWith(colDiv);
							}
							r.push(`${He} doesn't get far before ${he}`);
							if (canHear(slave)) {
								r.push(`hears a desperate pursuit behind ${him}.`);
							} else {
								r.push(`feels a gentle tap on ${his} shoulder.`);
							}
							r.push(`It's ${contextualIntro(slave, lover)},`);
							if (canHear(slave)) {
								r.push(`hurrying to catch`);
							} else {
								r.push(`finally catching`);
							}
							r.push(`up. Watching on the monitors, you see ${slave.slaveName}'s mixed pleasure and pain at seeing ${him2} again so soon, followed by a tearful explanation and an embrace so heartfelt that the pair of ex-slaves collapse to the floor together, sobbing.`);
							removeSlave(lover);
							App.Events.addParagraph(el, r);
							r = [];
							if (V.arcologies[0].FSPaternalist !== "unset") {
								r.push(`Of course, your paternalistic arcology thinks this almost too romantic, and there are jesting suggestions that outcomes this adorable ought to be illegal. The pair becomes celebrated citizens immediately.`);
								repX(10 * V.FSSingleSlaveRep * (V.arcologies[0].FSPaternalist / V.FSLockinLevel), "futureSocieties");
								V.arcologies[0].FSPaternalist += 0.1 * V.FSSingleSlaveRep;
							} else {
								r.push(`Though it is not ordinarily paternalistic, even your society thinks this is <span class="green">pretty romantic.</span>`);
								repX(5 * V.FSSingleSlaveRep, "futureSocieties");
							}
							App.Events.addParagraph(el, r);
							App.UI.DOM.appendNewElement("p", result, "You have gained an additional well-off citizen.");
							V.upperClass += 1;

							jQuery(result).empty().append(el);
						}
					));
				}
			}
		}
	} else if (V.policies.retirement.fate === "bioreactor") {
		r.push(`in a way that will inevitably fill the rest of your property with <span class="gold">fear.</span>`);
		for (const s of V.slaves) {
			s.trust -= 3;
		}

		if (lover) {
			r.push(`${lover.slaveName}, for ${his2} part, is <span class="mediumorchid">horrified.</span>`);
			lover.devotion -= 20;
		}
		App.Events.addParagraph(desc, r);
		r = [];

		r.push(`${He} is retiring into a featureless existence where the only realities are the phalli ejaculating food, fluid, and drugs into ${his}`);
		if (slave.vagina > -1) {
			r.push(`vagina,`);
		}
		r.push(`anus, and throat,`);
		if (slave.balls > 0) {
			r.push(`the relentless sodomy forcing semen out of ${his} distended balls,`);
		}
		r.push(`and the milk flowing into the milkers tugging at ${his} painfully engorged nipples.`);
		if (slave.fetish === "mindbroken") {
			r.push(`${He}'s already broken in spirit, and ${he} complies with ${his} installation into a milking machine with the dumb obedience of the animal ${he} has become.`);
		} else if (slave.devotion > 20) {
			r.push(`${He} complies with ${his} installation into a milking machine with the dumb obedience of someone whose mind will not allow them to understand their true situation out of simple immediate self-preservation.`);
		} else if (slave.trust < 50) {
			r.push(`${He} is so terrified of punishment that ${he} complies with ${his} installation into a milking machine to avoid pain. ${He} knows that if ${he} does not obey, there will be pain, and if ${he} obeys, there may be pain but it will come later.`);
		} else {
			r.push(`${He} resists, of course, giving the compliance systems an excuse to unload quite a few volts of electricity into ${him}. This disobedience is one of ${his} more abortive attempts to resist your will, and it is ${his} last.`);
		}
		App.Events.addParagraph(desc, r);
		r = [];

		r.push(`It will take ${him} some time to reach full production, a state that ${he}'ll be kept in until it becomes impossible for the most reckless drug regime to keep ${him} there. Near the end of the week, you check in on ${him} idly. ${His} breasts are already swelling under the hormonal treatments that can only be applied when the sole priority is production. The rhythm of the milkers gives them a slight pulsing heave, first one, then the other. ${His} milk whitens the lines running away from ${his} udders.`);
		App.Events.addParagraph(desc, r);
		r = [];

		App.UI.DOM.appendNewElement("div", result, App.UI.DOM.link(
			`Have a taste`,
			() => {
				const el = new DocumentFragment();
				App.UI.DOM.appendNewElement("p", el, `You tug one of the milkers off a nipple, producing a lewd sucking noise as the wet flesh pops free of the machinery. It must have been quite painful, but the feeding apparatus that covers much of the slave's face affords no indication of ${his} reaction, if any. You heft the boob with both hands and take the nipple into your mouth, sucking gently. A rich jet of cream hits your tongue, the milkfat luscious with hints of vanilla. The warm breastflesh fills your hands, and you fancy that you can feel the prosperity under your fingers as ${his} body desperately hurries to make more.`);
				jQuery(result).empty().append(el);
			}
		));
		r.push(`You have <span class="yellowgreen">gained a standard bioreactor.</span>`);
		App.Events.addParagraph(result, r);
		V.menialBioreactors += 1;
	} else if (V.policies.retirement.fate === "arcade") {
		r.push(`in a way that will inevitably fill the rest of your property with <span class="gold">fear.</span>`);
		for (const s of V.slaves) {
			s.trust -= 3;
		}

		if (lover) {
			r.push(`${lover.slaveName}, for ${his2} part, is <span class="mediumorchid">horrified.</span>`);
			lover.devotion -= 20;
		}
		App.Events.addParagraph(desc, r);
		r = [];

		r.push(`${He} is retiring into a dark, featureless eternity in which the only realities are phalli intruding into ${his}`);
		if (slave.vagina > -1) {
			r.push(`vagina,`);
		}
		r.push(`anus, and throat, and the drug-induced haze that will leave ${him} no choice but to orgasm when ${he} is penetrated.`);
		if (slave.fetish === "mindbroken") {
			r.push(`${He}'s already broken in spirit, and ${he} complies with the conversion process with the dumb obedience of the animal ${he} has become.`);
		} else if (slave.devotion > 20) {
			r.push(`${He} complies with the conversion process with the dumb obedience of someone whose mind will not allow them to understand their true situation out of simple immediate self-preservation.`);
		} else if (slave.trust < 50) {
			r.push(`${He} is so terrified of punishment that ${he} complies with the conversion process to avoid pain. ${He} knows that if ${he} does not obey, there will be pain, and if ${he} obeys, there may be pain but it will come later.`);
		} else {
			r.push(`${He} resists, of course, giving the compliance systems an excuse to unload quite a few volts of electricity into ${him}. This disobedience is one of ${his} more abortive attempts to resist your will, and it is ${his} last.`);
		}
		App.Events.addParagraph(desc, r);
		r = [];

		r.push(`${He} is brought down to`);
		if (V.arcade !== 0) {
			r.push(`${V.arcadeName},`);
		} else {
			r.push(`the autosurgery,`);
		}
		r.push(`and, a disturbingly short time later, there is a new Fuckdoll, a humanoid figure encased in a tough black bodysuit, in your office.`);
		if (!hasAnyLegs(slave)) {
			r.push(`Its`);
			if (isAmputee(slave)) {
				r.push(`limbless`);
			} else {
				r.push(`legless`);
			}
			r.push(`form is not obviously human. It's a sex toy, with several interesting holes and nothing else worth noticing.`);
		} else {
			r.push(`It stands immobile, the hydraulic system hidden within the suit stiffened to make voluntary movement impossible.`);
		}
		if (slave.boobs > 2000) {
			r.push(`The suit has a pair of gaps for its monstrous breasts, bare expanses of ${slave.skin} skin.`);
		}
		if (slave.belly >= 5000) {
			r.push(`The suit has a gap for its big belly; a round dome of ${slave.skin} skin.`);
		}
		if (slave.lips > 40) {
			r.push(`Its upper hole is surrounded by a ludicrous set of swollen lips.`);
		}
		if (slave.labia > 0) {
			r.push(`The conversion process left its labia permanently engorged.`);
		}
		if (slave.vaginaLube > 0) {
			r.push(`Its front hole is dripping streams of natural lubrication.`);
		}
		if (slave.anus > 2) {
			r.push(`The gap in the suit over its rear hole opens into the Fuckdoll's interior, since it's the same size as the Fuckdoll's loose sphincter.`);
		}
		App.Events.addParagraph(desc, r);
		r = [];

		const fuck = App.UI.DOM.appendNewElement("div", result, App.UI.DOM.link(
			`Fuck it`,
			() => {
				const r = [];
				if (V.PC.dick !== 0) {
					r.push(`You enter a command, and the Fuckdoll instantly`);
					if (hasAnyLegs(slave)) {
						r.push(`collapses to its knee${(hasBothLegs(slave)) ? `s` : ``}.`);
					} else {
						r.push(`presents its upper hole.`);
					}
					r.push(`You tug the plug clear of its upper hole, and insert your cock. The Fuckdoll's nose ports open when it needs to breathe, but periodically close without warning to force its throat to spasm. When you're bored of this, you pull your dick clear and haul the Fuckdoll over to the couch, entering the command that forces it to present its rear hole. Your saliva-slicked shaft slides readily inside the sex toy's warm interior. After a while, you enter the tightening command, and the Fuckdoll's sphincter obediently cinches down, encouraging you to shoot your load inside it. A low moaning sound issues from its upper hole.`);
				} else {
					r.push(`You shove the Fuckdoll backward onto the couch, and enter a command that forces it into a bridged position.`);
					if (slave.vagina > -1) {
						r.push(`Its clit is brought to full hardness, and its front hole becomes wet and flushed. You ride this until you orgasm, the Fuckdoll's copious juices adding lewd noises to each grinding motion.`);
					} else {
						r.push(`Its dick is forced to perfect hardness. Its tubes have been tied to prevent any unseemly contamination, allowing you to ride it until you are satisfied. When you're done, the Fuckdoll is allowed to go soft. It did not climax.`);
					}
				}
				r.push(`You leave it where it is, your personal assistant directing a slave to perform maintenance on it when ${heU} has the time.`);
				return jQuery(fuck).empty().append(r.join(" "));
			}
		));

		r.push(`You have <span class="yellowgreen">gained a Fuckdoll.</span>`);
		App.Events.addParagraph(desc, r);
		r = [];
		V.fuckdolls += 1;
	} else {
		r.push(`into a life of menial drudgery. This has little impact on your other human property.`);
		if (lover) {
			r.push(`${lover.slaveName}, for ${his2} part, is <span class="mediumorchid">saddened,</span> but not seriously affected. ${He2} knew this was coming.`);
			lover.devotion -= 5;
		}
		r.push(`There are a thousand things a slave like ${him} can usefully do around the arcology, and ${he}'ll do them. But ${he}'s reached the age where it's time for you and the arcology's citizens to fuck younger ${girl}s.`);

		App.Events.addParagraph(desc, r);
		r = [];
		r.push(`You have <span class="yellowgreen">gained a menial slave.</span>`);
		V.menials += 1;
	}

	App.Events.addNode(el, r);
	App.UI.DOM.appendNewElement("h3", el, `Final notes?`);
	const note = App.UI.DOM.appendNewElement("div", el, null, "note");
	App.UI.DOM.appendNewElement("div", note, `${His} most recent task was to ${(V.assignmentRecords[slave]) ? `${slave.assignment}, and before that to ${V.assignmentRecords[slave]}` : slave.assignment}.`, "indent");
	note.append(slaveImpactLongTerm(slave));

	return el;
};


code:
/** Get the slave (or player) who's taking care of this patient's sexual needs this week.
 * @param {App.Entity.SlaveState} slave
 * @returns {{type: "player" | "lover" | "friend" | "family" | "nurse" | null, slave?: App.Entity.SlaveState}}
 */
App.EndWeek.getClinicPartner = function(slave) {
	const validVisitingPartner = (/** @type {App.Entity.SlaveState} */ s) => s && canMove(s) && isSlaveAvailable(s) && App.Utils.sexAllowed(slave, s);
	if (slave.relationship === -3) { // player visits wife
		return {type: "player"};
	}
	if (slave.relationship > 0) {
		const partner = getSlave(slave.relationshipTarget);
		if (validVisitingPartner(partner)) {
			if (slave.relationship > 2) { // lover
				return {type: "lover", slave: partner};
			} else { // friend
				return {type: "friend", slave: partner};
			}
		}
	}
	if (V.seeIncest === 1) { // close family member
		const partner = randomRelatedSlave(slave, validVisitingPartner);
		if (partner) {
			return {type: "family", slave: partner};
		}
	}
	if (S.Nurse && App.Utils.sexAllowed(S.Nurse, slave)) {
		return {type: "nurse"};
	}
	return {type: null};
};

/** Determines which employees a given facility leader is having sex with this week
 * @param {App.Entity.Facilities.Facility} facility
 * @returns {Set<number>}
 */
App.EndWeek.getFLSex = function(facility) {
	/** @type {Set<number>} */
	const employeeSex = new Set();
	const fl = facility.manager ? facility.manager.currentEmployee : null;
	if (fl && App.Data.misc.sexFromDevelopmentLeaders.includes[fl.assignment]) {
		facility.employees().filter(s => flWillFuck(s)).forEach(s => employeeSex.add(s.ID));
	}
	return employeeSex;

	/** @param {App.Entity.SlaveState} emp */
	function flWillFuck(emp) {
		const horny = (s) => s.devotion >= -50 /* not unhappy */ && s.energy > 20/* not frigid */;
		if (fl.assignment === Job.WARDEN && fl.fetish === "mindbroken") {
			return true; // mindbroken warden ignores rules, rapes everyone
		}
		if (fl.assignment === Job.NURSE && App.EndWeek.getClinicPartner(emp).type !== "nurse") {
			return false; // nurse is busy, will not have sex with patients who are satisfied by someone else
		}
		if (fl.assignment === Job.WARDEN && emp.relationship === -3) {
			return false; // wardeness will never molest the PC's spouse
		}
		if (horny(emp) || fl.assignment === Job.WARDEN) { // only the warden will routinely rape frigid/unhappy slaves
			if (App.Utils.sexAllowed(emp, fl)) { // no sex with a slave you've forbidden them to fuck
				return true;
			}
		}
		return false;
	}
};

repo_name: Banyanael/fc

license: mit


code:
/* Condition
	The current physical condition of the slave.
	Any health improvements get added here.
	Short term damage reduces it as it degrades.

Short term damage
	Anything that hurts a slave gets transferred into this.
	At the end of the week 25% of it will be removed and turned into condition damage instead.
	Usage of preventatives or curatives reduces the actual condition damage by 50%.

Long term damage
	Once ageing beyond 30 years old there is a chance of long term damage that increases with time. Calculated on birthday.
		Math.floor((slave.physicalAge - 25 + jsRandom(1, 15)) / 20)
	25% of the actual condition damage taken during a week also gets added to the pool (therefore gets reduced by preventatives and curatives if active).
	Nothing can reduce this value.
	Perhaps the effect can still be reduced through surgical implant with high upkeep.

Carcinogens
	Aside from a source of regular short term damage high levels will also increase the chances for severe illnesses
		3d6 rolls for illness
			illness > 8 -- 1 62.5%
			illness > 6 -- 2 21.3%
			illness > 5 -- 3 11.6%
			illness > 4 -- 4 2.8%
			illness = 3 or 4 -- 5 1.8%
		Carcinogens subtract Math.trunc(chem / 150) from the dice rolls for a max of -6 at >= 90
	There should be a natural decay of carcinogens every week of 10% of the level. But at the price of 0.2 short term damage per point of chem.
	Add carcinogen damage to serious medical procedures due to use of potent pharmaceuticals during them.

Illness
	There is always a chance a slave gets sick. Often they will just get better on their own, but sometimes it can be more serious and require a stay in the clinic.
	Sick slaves work at reduced effectiveness and will see their health lowered.

Tiredness
	Depending on various factors (living conditions, assignment, rewards, muscles, health) a slave may become more or less tired.
	Once tiredness reached 60 there will be negative effects for productivity and at 90 they become even more extreme.
	Being tired or exhausted also reduces a slave's ability to resist the player, increasing devotion and fear.

Health
	The aggregate of condition, short term damage and long term damage to provide an indication of the current overall state of the slave. The slave will die once this reached -100.
*/

/* Getting ill depends on the following factors;
	- current condition
	- long term damage (accumulated through getting old(er) and residual from short term damage)
	- short term damage (accumulated through serious illness, chemical carcinogens, damaging surgeries and other health damage sources) 125%
	- chemical carcinogens (more serious illness chance with high carcinogen levels)
	- age (long term damage takes care of older slaves, the young ones need a specific vulnerability)
	- use of curatives
	- assignment (rest, clinic, spa and master suite less likely, whoring, slutting and gloryholes more likely.)
	- random chance
	Can be blocked with preventatives.
*/

/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
globalThis.illness = function(slave) {
	const random = jsRandom(1, 100); // high rolls are good
	const H = slave.health;
	let r = ``;
	let assignBonus = 0; // bonus for healthy assignments

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

	const sicknessDegree = ["fine", "minor illness", "illness", "bad illness", "severe illness", "life-threatening illness"];

	// On the macro side of things disease could also happen to the arcology's population as the arcology becomes crowded, killing citizens and putting slaves at greater risk of getting ill. Again with upgrades/policies to mitigate the issue made available TODO?
	if (slave.assignment === Job.AGENTPARTNER || slave.assignment === Job.AGENT) {
		if (H.illness !== 0) {
			H.illness = 0;
		}
		return r;
	} // Let's make sure agents don't get sick and accidentally die, they should take care of themselves
	if (slave.fuckdoll !== 0) {
		assignBonus += 50;
	} else if (slave.assignment === Job.CLINIC || slave.assignment === Job.NURSE) {
		assignBonus += 40;
	} else if (slave.assignment === Job.DAIRY && V.dairyRestraintsSetting > 1) { // industrial dairy immunization boost
		assignBonus += 30;
	} else {
		if (slave.assignment === Job.SPA || slave.assignment === Job.ATTENDANT || slave.assignment === Job.REST) {
			assignBonus += 20;
		} else if ((slave.assignment === Job.MASTERSUITE || slave.assignment === Job.FUCKTOY || slave.assignment === Job.CONCUBINE || slave.assignment === Job.HEADGIRL) && V.PC.skill.medicine >= 40) {
			assignBonus += 10;
		}
		if (App.Data.Careers.Leader.nurse.includes(slave.career) || slave.skill.nurse > 120 || slave.intelligence + slave.intelligenceImplant > 95) { // Let slaves with experience or brains use it
			assignBonus += 10;
		}
	}
	if (random < 2 && canCatchIllness(slave)) { // Always a 2% (one week per slave per year) base chance of a slave even in otherwise-safe conditions spontaneously catching an illness
		getIll(slave);
		r += ` ${He} has come down with <span class="health dec">${addA(sicknessDegree[H.illness])}.</span>`;
	} else if (random < 6 && H.illness > 0) { // Always a 5% chance of a sick slave feeling worse
		H.illness += 1 + Math.trunc((slave.chem / 10 + jsRandom(1, 50) + 15) / 100); // Illness progresses with 1, unless chem > 350, then there's a chance for 2
		r += ` <span class="health dec">${His} sickness has progressed.</span>`;
		if (H.illness > 5) {
			healthDamage(slave, 20 * (H.illness - 5)); // Condition penalty for going over maximum illness, very dangerous
			H.illness = 5;
			r += ` ${His} illness <span class="health dec">makes an attempt to claim ${his} life.</span>`;
		}
	} else if (random > 95 && H.illness > 0) { // Always a 5% chance of a sick slave getting better
		H.illness -= 1;
		if (H.illness === 0) {
			improveCondition(slave, 5);
			r += ` <span class="health inc">${His} sickness has waned</span> and ${he} now feels better.`;
		} else {
			r += ` ${His} immune system <span class="health inc">fights back</span> against ${his} illness.`;
		}
	} else {
		const nurseEffect = nurseEffectiveness(slave); // small (~5 or less) for prevention, large (~20 or more) for cure
		const ageModifier = Math.min(slave.physicalAge - 15, 0); // always negative (-15 to 0); younger kids are slightly more likely to get sick
		const healthAdjusted = H.condition - H.longDamage - H.shortDamage * 1.25 + ageModifier; // -100 to +200, roughly
		const assignmentFactor = 1 + assignBonus / 100; // 1.0 to 1.5
		const nurseFactor = 1 + nurseEffect / 100; // 1.0 to 1.4
		const healthFactor = Math.clamp(1 + healthAdjusted / 100, 0.5, 1.5); // 0.5 to 1.5
		const curativesBonus = (slave.curatives > 1 || slave.inflationType === "curative") ? 2 : 1; // 1.0 or 2.0
		if (V.debugMode) {
			r += ` (Illness factors: health ${healthFactor}, nurse ${nurseFactor}, assignment ${assignmentFactor}, curative ${curativesBonus}${H.illness > 0 ? `; cure roll ${random}` : ``})`;
		}

		// When ill, a slave in average health with a level 1 illness has a 60% chance of getting better the next week at complete default, 78% in the clinic with a great nurse, 80% with curatives alone, 89% with both benefits - note that bonus factors have a bigger effect on more advanced illnesses
		if (H.illness > 0 && random > (30 + (H.illness * 10)) / (curativesBonus * assignmentFactor * nurseFactor * healthFactor)) {
			if (nurseEffect > 30 && (jsRandom(1, 2) === 2 || slave.assignment === Job.CLINIC) && H.illness > 1) { // A particularly effective nurse can improve illness faster
				H.illness -= 2;
				r += ` ${S.Nurse.slaveName} <span class="health inc">successfully treats</span> ${his} illness.`;
			} else {
				H.illness -= 1;
				r += ` ${His} body <span class="health inc">fights back</span> against ${his} illness.`;
			}
			if (H.illness === 0) {
				r += ` ${He} no longer <span class="health inc">shows any signs</span> of ${his} previous sickness.`;
			}
		} else if (canCatchIllness(slave)) {
			/** an adult slave in average condition in an otherwise unprotected environment (no drugs or modifiers) will have `baseChance` chance of catching an illness when exposed
			 * note the independent roll for each exposure; we're ignoring the original random roll here
			 * @param {number} baseChance
			 * @returns {boolean}
			 */
			const catchesIllness = (baseChance) => {
				const roll = jsRandom(1, 100);
				if (V.debugMode) {
					r += ` (Transmission roll: ${roll} vs ${baseChance}*mods)`;
				}
				return roll < baseChance / (curativesBonus * assignmentFactor * nurseFactor * healthFactor);
			};

			if (hasOutsideContact(slave)) {
				if (catchesIllness(15)) {
					getIll(slave);
					r += ` ${He} has come down with <span class="health dec">${addA(sicknessDegree[H.illness])}.</span>`;
				}
			}

			// if she didn't/couldn't catch an illness outside, maybe she'll get one from another slave
			if (![Job.CLINIC, Job.NURSE].includes(slave.assignment)) { // slaves in the clinic are monitored and can't catch new illnesses from visitors or patients
				// a slave is likely to catch something from her friend/partner
				if (H.illness === 0 && slave.relationship > 0) {
					const rel = getSlave(slave.relationshipTarget);
					if (rel && rel.health.illness > 1) {
						const chance = rel.assignment === Job.CLINIC ? 15 : 45; // you CAN still catch a disease from visiting your sick friend while she's in the clinic for treatment, but it's much less likely
						if (catchesIllness(chance)) {
							H.illness = rel.health.illness - 1; // reduced severity
							r += ` ${He} has <span class="health dec">caught ${addA(sicknessDegree[H.illness])}</span> from ${his} ${relationshipTerm(rel)} ${rel.slaveName}.`;
						}
					}
				}
				// or she might catch something from a sick coworker
				const job = App.Utils.jobForAssignment(slave.assignment);
				if (H.illness === 0 && job) {
					const contacts = 20; // limits max spread rate in large facilities - not everyone comes into contact with everyone else every week
					for (const other of job.facility.employees().randomMany(contacts).filter(s => s.health.illness > 1)) {
						if (catchesIllness(25)) {
							H.illness = other.health.illness - 1; // reduced severity
							r += ` ${He} has <span class="health dec">caught ${addA(sicknessDegree[H.illness])}</span> from ${his} coworker ${other.slaveName}.`;
							break;
						}
					}
				}
			}
		} else if (H.illness > 0) {
			if (jsRandom(1, 100) > 75 && H.illness === 1 && curativesBonus < 2 && slave.assignment !== Job.CLINIC && V.week > 8) {
				// independent 25% chance of getting worse if you have a level 1 illness, aren't being treated, AND already failed your recovery roll (i.e. you've spent more than one week sick)
				r += ` ${He}'s <span class="health dec">feeling much worse</span> after spending so much time with a minor illness.`;
				H.illness += 1;
			} else {
				r += ` ${He} <span class="health dec">suffers under ${his} ${sicknessDegree[H.illness]}.</span>`;
			}
			// note: health damage from continuing illness is deducted in endWeekHealthDamage
		}
	}
	return r;
};

/** Determine whether a given slave can catch an illness at all, so we don't have to check chances.
 * @param {App.Entity.SlaveState} slave
 * @returns {boolean}
 */
globalThis.canCatchIllness = function(slave) {
	if (V.seeIllness === 0) { // illness is disabled globally
		return false;
	}
	if (slave.health.illness > 0) { // already sick
		return false;
	}
	if (slave.curatives === 1 || slave.inflationType === "curative") { // on preventatives, or inflated with curatives
		return false;
	}
	if (slave.assignment === Job.CLINIC) { // slaves in the clinic are monitored
		return false;
	}
	return true;
};

/** Does this slave have regular contact with people other than you and your slaves?
 * @param {App.Entity.SlaveState} slave
 * @returns {boolean}
 */
globalThis.hasOutsideContact = function(slave) {
	/** @type {Job[]} */
	const jobsWithOutsideContact = [Job.BODYGUARD, Job.DJ, Job.MADAM, Job.ARCADE, Job.GLORYHOLE, Job.CLUB, Job.PUBLIC, Job.WHORE, Job.BROTHEL];
	if (V.recruiterTarget === "other arcologies") {
		jobsWithOutsideContact.push(Job.RECRUITER);
	}
	return jobsWithOutsideContact.includes(slave.assignment);
};

/** Once a new illness is rolled this determines how bad it is initially, chem levels seriously increase the chances of a higher initial value. Health also factors in with weakened slaves being more likely to catch ill.
 * @param {App.Entity.SlaveState} slave
 */
globalThis.getIll = function(slave) {
	const H = slave.health;
	if (V.week <= 8) {
		// new game protection: do not directly spawn any transmissible illnesses for the first 8 weeks
		H.illness = 1;
	} else {
		const illness = jsRandom(1, 6) + jsRandom(1, 6) + jsRandom(1, 6) - Math.trunc(slave.chem / 150) + Math.trunc(H.condition / 25);
		if (illness < 4) {
			H.illness = 5; // 0.5% chance
		} else if (illness < 5) {
			H.illness = 4; // 1.4% chance
		} else if (illness < 6) {
			H.illness = 3; // 2.7% chance
		} else if (illness < 8) {
			H.illness = 2; // 11.6% chance
		} else {
			H.illness = 1; // 83.8% chance
		}
	}
};

/** Reduce slave need if ill or tired
 * @param {App.Entity.SlaveState} slave
 * @returns {void}
 */
globalThis.poorHealthNeedReduction = function(slave) {
	if (slave.energy > 20) {
		slave.need = Math.trunc(slave.need * healthPenalty(slave));
	}
};

/**
 * A better nurse and/or less slaves/patients to look out for makes for a better chance of curing illness
 * @param {App.Entity.SlaveState} slave
 * @returns {number}
 */
globalThis.nurseEffectiveness = function(slave) {
	const H = slave.health;
	const clinicUpgrade = 1 + (V.clinicUpgradePathogenSequencer || 0);
	const clinicScreening = V.clinicRegularCheckups || 0;
	if (S.Nurse) {
		const nurseSkill = App.Data.Careers.Leader.nurse.includes(S.Nurse.career) ? 200 : S.Nurse.skill.nurse;
		let nurseEffectiveness = Math.trunc((nurseSkill * clinicUpgrade / Math.max((App.Entity.facilities.clinic.employeesIDs().size * 10 + (V.slaves.length * 2) * clinicScreening), 1)) * 20);
		if (H.illness > 1 && slave.assignment === Job.CLINIC) {
			if (nurseEffectiveness < 20) {
				return nurseEffectiveness;
			} else if (nurseSkill > 80) {
				return Math.min(nurseEffectiveness, 40);
			} else if (nurseSkill > 40) {
				return Math.min(nurseEffectiveness, 30);
			} else {
				return 20;
			}
		} else if (H.illness < 2 && (clinicScreening || slave.assignment === Job.CLINIC)) { // reasonably ill slaves get no benefit from the nurse unless they are in the clinic, otherwise she can provide benefits to prevent illness in the first place and clearing up illnesses of level 1
			nurseEffectiveness = Math.trunc(nurseEffectiveness / 4);
			if (nurseEffectiveness < 5) {
				return nurseEffectiveness;
			} else {
				return 5;
			}
		}
	}
	return 0;
};

/**
 * Run at the end of the week to take care of health changes
 * @param {FC.HumanState} slave
 * @returns {void}
 */
globalThis.endWeekHealthDamage = function(slave) {
	const H = slave.health;
	let chemToShort = 0;
	let shortToCondition = 0;
	let shortToLong = 0;

	// Checking if we are dealing with the player
	// Player does not make use of most things slaves deal with, only short to long term damage
	if (slave.ID !== -1) {
		// dealing with carcinogens
		// They decay naturally at a rate of 10%, but at as they decay cause short term damage
		if (slave.chem > 0) {
			if (slave.chem > 10) {
				chemToShort += Math.max(Math.trunc(slave.chem * 0.1), 1);
			} else if (slave.chem > jsRandom(0, 9)) {
				chemToShort += 1;
			}
			slave.chem -= chemToShort;
			H.shortDamage += Math.max(Math.trunc(chemToShort * 0.1), 2);
		}

		// dealing with illness
		if (H.illness > 0) {
			H.shortDamage += Math.trunc(Math.pow(H.illness, 1.52) * 3 + 2); // 5, 10, 17, 26, 36 points of damage per respective level of illness
		}

		// Long term damage due to age calculated on birthdays only
		if (slave.birthWeek === 0 && slave.physicalAge > 29) {
			H.longDamage += Math.trunc((slave.physicalAge - 25 + jsRandom(1, 15)) / 20);
		}
	} else if (H.condition < 100) { // The player gets an automatic 5 condition recovery each weak up to 100
		H.condition = Math.min(H.condition + 5, 100);
	}

	// recovering and transferring short term damage to condition and long term
	if (H.shortDamage > 0) {
		shortToCondition += Math.max(Math.trunc(H.shortDamage * 0.5), 1); // 50% of short term damage gets transferred
		H.shortDamage -= shortToCondition;
		const assignment = slave.ID !== -1 ? asSlave(slave).assignment : null;
		if (assignment === Job.CLINIC) {
			H.shortDamage = Math.trunc(H.shortDamage * 0.5); // An additional 50% of short term damage reduction (75% total) for getting treatment in the clinic
		} else if (assignment === Job.REST || assignment === Job.SPA) {
			H.shortDamage = Math.trunc(H.shortDamage * 0.75); // An additional 25% of short term damage reduction (62.5% total) for resting
		}
		if (slave.curatives > 0 || slave.ID === -1) { // transferred damage is half if on preventatives/curatives or target is the player
			shortToCondition = Math.trunc(shortToCondition * 0.5);
		}
		if (assignment === Job.CLINIC) {
			shortToCondition = Math.trunc(shortToCondition * 0.75);
		}
		shortToLong += Math.trunc(shortToCondition * 0.1); // 10% of transferred damage gets added to long term damage, minimum of 20 short term damage before any long term damage is accumulated
		H.longDamage += shortToLong;
	}
	if (V.baseDifficulty === 1) { // Reducing longDamage up to a certain point depending on the difficulty
		if (H.longDamage > 0) {
			H.longDamage -= Math.min(Math.trunc(H.longDamage * 0.1), 1);
		}
	} else if (V.baseDifficulty === 2) {
		if (H.longDamage > 20) {
			H.longDamage -= Math.min(Math.trunc((H.longDamage - 20) * 0.1), 1);
		}
	} else if (V.baseDifficulty === 3) {
		if (H.longDamage > 40) {
			H.longDamage -= Math.min(Math.trunc((H.longDamage - 40) * 0.1), 1);
		}
	} else if (V.baseDifficulty === 4) {
		if (H.longDamage > 60) {
			H.longDamage -= Math.min(Math.trunc((H.longDamage - 60) * 0.1), 1);
		}
	}
	if (V.disableLongDamage) {
		H.longDamage = 0;
	}

	// Making sure condition doesn't get too high
	if (H.condition > 150) {
		H.condition -= Math.trunc(Math.pow(H.condition - 150, 0.5));
	}

	updateHealth(slave);
};

/**
 * Tells if a slave will willingly work to death
 * @param {App.Entity.SlaveState} slave
 * @returns {boolean}
 */
globalThis.willWorkToDeath = function(slave) {
	// More to come in the future
	if (slave.trust < -50) { // Maybe lower
		return true;
	} else if (slave.devotion > 50) {
		return true;
	} else if (slave.sexualFlaw === "self hating") {
		return true;
	} else if (slave.fetish === "mindbroken") {
		return true;
	} else if (V.MadamID !== 0 && (slave.assignment === Job.BROTHEL || (slave.assignment === Job.WHORE && V.brothel > 0 && V.universalRulesFacilityWork === 1 && V.brothelSpots > 0))) {
		return true;
	} else if (S.DJ && (slave.assignment === Job.CLUB || (slave.assignment === Job.PUBLIC && V.club > 0 && V.universalRulesFacilityWork === 1 && V.clubSpots > 0))) {
		return true;
	}
	return false;
};

/**
 * Tells if a slave is taking the week off to rest
 * @param {App.Entity.SlaveState} slave
 * @returns {boolean}
 */
globalThis.slaveResting = function(slave) {
	if (slave.rules.rest === "cruel" && slave.health.tired > 90) {
		return true;
	} else if (slave.rules.rest === "restrictive" && slave.health.tired > 60) {
		return true;
	} else if (slave.rules.rest === "permissive" && slave.health.tired > 30) {
		return true;
	}
	return false;
};

/**
 * Run at the end of the week to take care of tiredness changes
 * @param {FC.ReportSlave} slave
 * @returns {void}
 */
globalThis.tired = function(slave) {
	const H = slave.health;
	let livingRules = 0;
	let restRules = 0;
	let assignment = 0;
	let reward = 0;
	let punishment = 0;
	// let muscles;
	// let health;
	let tiredChange;
	let spaFlag = 0;
	let dormPop = V.dormitoryPopulation - V.dormitory;

	if (!slave.fuckdoll) {
		// Assignment
		if ([Job.SPA].includes(slave.assignment)) {
			assignment -= 40 * (V.spaUpgrade + 1); // Reduces tired by an average of 40 points while in the spa, double with the upgraded spa
			if (S.Attendant) {
				let skillBonus;
				if (App.Data.Careers.Leader.attendant.includes(S.Attendant.career)) {
					skillBonus = 200;
				} else {
					skillBonus = S.Attendant.skill.attendant;
				}
				assignment -= Math.trunc(skillBonus / 10); // Maximum of 20 extra points of negative tiredness due to attendant skill
			}
		} else if ([Job.REST, Job.CLINIC].includes(slave.assignment)) {
			assignment -= 40; // Major tired reduction due to a solid week of rest
		} else if ([Job.BODYGUARD].includes(slave.assignment)) {
			assignment += 18; // A tough assignment with a girl that doesn't use her provided room unless it is attached to yours.
		} else if ([Job.HEADGIRL].includes(slave.assignment)) {
			if (slaveResting(slave)) {
				assignment -= 40;
				slave.slaveUsedRest = 1;
			} else {
				assignment += 22; // Always busy. Could benefit from a helper...
			}
		} else if (App.Data.misc.facilityHeads.includes(slave.assignment)) { // Heads are very busy, but always have luxurious conditions, so it balances out, save for the exceptions
			if (slaveResting(slave)) {
				assignment -= 10;
				slave.slaveUsedRest = 1;
			} else {
				assignment += 15;
			}
		} else if ([Job.ATTENDANT, Job.CONCUBINE].includes(slave.assignment)) { // Cushy head positions
			assignment += 5;
		} else if ([Job.RECRUITER].includes(slave.assignment)) {
			if (H.tired > 80) { // I'll take it easy a week to better recruit the next.
				assignment -= 20;
			} else {
				assignment += 10;
			}
		} else if ([Job.HEADGIRLSUITE].includes(slave.assignment)) {
			if (slave.health.tired > 60) {
				assignment += 2;
			} else if (slave.devotion > 20) {
				assignment += 5;
			} else {
				assignment += 10;
			}
		} else if ([Job.SUBORDINATE].includes(slave.assignment)) {
			if (slaveResting(slave)) {
				assignment -= 20;
				slave.slaveUsedRest = 1;
			} else if (slave.subTarget === -1) {
				if (slave.health.tired + 5 >= 90 && !willWorkToDeath(slave)) {
					assignment += 1;
				} else if (slave.devotion > 20) {
					assignment += 3;
				} else {
					assignment += 5;
				}
			} else if (slave.subTarget === 0) {
				if (slave.devotion > 20) {
					assignment += 7;
				} else {
					assignment += 10;
				}
				assignment = Math.min(Math.ceil(assignment / App.EndWeek.saVars.subSlaveRatio), 50); // up to 50 if very overloaded, make sure to have enough girls serving!
			} else {
				if (slave.relationshipTarget === slave.subTarget && slave.health.tired > 60) {
					assignment += 2;
				} else if (slave.health.tired + 10 >= 90 && !willWorkToDeath(slave)) {
					assignment += 1;
				} else if (slave.devotion > 20 || slave.relationshipTarget === slave.subTarget) {
					assignment += 5;
				} else {
					assignment += 10;
				}
			}
		} else if ([Job.DAIRY].includes(slave.assignment)) {
			if (V.dairyRestraintsSetting > 1) {
				assignment -= 100; // Full industrial Dairy is mind dulling (leaving the stupor is devastating)
			} else if (V.dairyRestraintsSetting > 0) {
				// Restraining while milking is a little stressful
				// Additional invasions multiply it
				if (slaveResting(slave)) {
					assignment -= 20;
					slave.slaveUsedRest = 1;
				} else if (slave.health.tired + 9 >= 90 && !willWorkToDeath(slave)) {
					assignment += 2;
				} else if (slave.devotion > 20) {
					assignment += 4;
				} else {
					assignment += 9;
				}
				if (slave.balls > 0) {
					assignment += 1;
				}
				assignment *= 1 + (V.dairyFeedersSetting + V.dairyStimulatorsSetting + V.dairyPregSetting);
			} else { // Being a free range cow is relatively relaxing
				if (slaveResting(slave)) {
					assignment -= 40;
					slave.slaveUsedRest = 1;
				} else if (slave.health.tired + 5 >= 90 && !willWorkToDeath(slave)) {
					assignment += 2;
				} else if (slave.devotion > 20) {
					assignment -= 5;
				} else {
					assignment += 5;
				}
				if (slave.balls > 0) {
					assignment += 1;
				}
			}
		} else if ([Job.MILKED].includes(slave.assignment)) {
			if (slaveResting(slave)) {
				assignment -= 5;
				slave.slaveUsedRest = 1;
			} else if (slave.health.tired + 8 >= 90 && !willWorkToDeath(slave)) {
				assignment += 1;
			} else if (slave.devotion > 20) {
				assignment += 2;
			} else {
				assignment += 8;
			}
			if (slave.balls > 0) {
				assignment += 1;
			}
		} else if ([Job.CELLBLOCK, Job.CONFINEMENT].includes(slave.assignment)) { // Generally not tiring unless a Wardeness is present, in which case she uses sleep deprivation to break slaves.
			if (slave.assignment === Job.CELLBLOCK && V.WardenessID !== 0 && slave.fetish !== "mindbroken") {
				if (S.Wardeness.fetish === "mindbroken") {
					if (H.tired > 80) {
						assignment -= 8;
					} else {
						assignment += 40;
					}
				} else if (S.Wardeness.sexualQuirk === "caring") {
					assignment += 5;
				} else if (S.Wardeness.sexualFlaw === "malicious" || S.Wardeness.sexualFlaw === "abusive") {
					if (H.condition > 20) {
						assignment += 40;
					} else if (H.tired > 80) {
						assignment -= 8;
					} else {
						assignment += 20;
					}
				} else if (H.tired > 50) {
					assignment -= 8;
				} else if (H.tired <= 30) {
					assignment += 33;
				} else {
					assignment += 20;
				}
			} else {
				assignment -= 8;
			}
		} else if ([Job.ARCADE].includes(slave.assignment)) {
			assignment += 35;
			if (V.arcadeUpgradeHealth === 2) {
				assignment -= 60;
			} else if (V.arcadeUpgradeHealth === 1) {
				assignment -= 30;
			}
		} else if ([Job.GLORYHOLE, Job.FARMYARD].includes(slave.assignment)) { // Hard assignments
			if (slaveResting(slave)) {
				assignment -= 20;
				slave.slaveUsedRest = 1;
			} else if (slave.health.tired + 20 >= 90 && !willWorkToDeath(slave)) {
				assignment += 1;
			} else if (slave.devotion > 20) {
				assignment += 15;
			} else {
				assignment += 20;
			}
		} else if (App.Data.misc.whoringAssignments.includes(slave.assignment)) { // Moderate assignments
			if (slaveResting(slave)) {
				assignment -= 20;
				slave.slaveUsedRest = 1;
			} else if (slave.health.tired + 15 >= 90 && !willWorkToDeath(slave)) {
				assignment += 1;
			} else if (slave.devotion > 20) {
				assignment += 10;
			} else {
				assignment += 15;
			}
		} else if ([Job.FUCKTOY, Job.HOUSE, Job.QUARTER].includes(slave.assignment)) { // Easy assignments
			if (slaveResting(slave)) {
				assignment -= 20;
				slave.slaveUsedRest = 1;
			} else if (slave.health.tired + 11 >= 90 && !willWorkToDeath(slave)) {
				assignment += 1;
			} else if (slave.devotion > 20) {
				assignment += 7;
			} else {
				assignment += 11;
			}
		} else if ([Job.SCHOOL, Job.CLASSES, Job.MASTERSUITE].includes(slave.assignment)) { // Trivial assignments
			if (slave.health.tired > 80) {
				assignment += 2;
			} else if (slave.devotion > 20) {
				assignment += 2;
			} else {
				assignment += 5;
			}
		}

		// Living Conditions
		if ((slave.assignment === Job.BODYGUARD && V.dojo === 2) || (slave.assignment === Job.HEADGIRL && V.HGSuite === 1)) {
			livingRules -= 20;
		} else if (slave.assignment === Job.BODYGUARD) {
			livingRules -= 6; // Remove maybe?
		} else if (slave.rules.living === "luxurious") {
			livingRules -= 15;
		} else if (slave.rules.living === "spare") {
			livingRules -= 2; // Barely reduce tiredness while sleeping in spare conditions
			if (dormPop > 10) { // Overcrowding penalty
				livingRules += 12;
			} else if (dormPop > 5) {
				livingRules += 7;
			}
		} else {
			livingRules -= 10;
			if (dormPop > 10) { // Overcrowding penalty
				livingRules += 15;
			} else if (dormPop > 5) {
				livingRules += 10;
			}
		}

		// Rewards
		if (slave.rules.reward === "drugs") {
			reward -= 4;
		} else if (slave.rules.reward === "relaxation") {
			if (V.spaSpots > 0) {
				reward -= 7;
				spaFlag = 1;
			} else {
				reward -= 5;
			}
		} else if (slave.rules.reward === "situational") {
			if (V.spaSpots > 0) {
				reward -= 4;
				spaFlag = 1;
			} else {
				reward -= 3;
			}
		}
		if (slave.devotion > 50) { // Considering how often the slave gets rewarded
			reward *= 3;
		} else if (slave.devotion > 20) {
			reward *= 2;
		} else if (slave.devotion < -20 || slave.trust >= -20) {
			reward = 0;
		}
		if (spaFlag) {
			V.spaSpots -= Math.abs(reward); // Reducing the available space in the spa depending on how often the slave can be found there
		}
		if (reward > 0) {
			if (spaFlag) {
				reward *= V.spaUpgrade + 1;
			}
		}

		// Punishments
		if (slave.rules.reward === "confinement" && V.cellblock !== 0) {
			punishment -= 2;
		}
		if (slave.devotion > 50) { // Considering how often the slave gets punished
			punishment = 0;
		} else if (slave.devotion >= -20) {
			if (slave.trust >= -20) {
				punishment *= 2;
			}
		} else {
			if (slave.trust >= -50) {
				punishment *= 3;
			}
		}

		/* Disabled for balancing
		// Muscles
		if (slave.muscles < 0) {
			muscles = -Math.trunc((slave.muscles / 10) * (1 + normalRandInt(0, 5) / 100)); // Being weak increases tiredness, building muscles eventually reduces tiredness
		} else {
			muscles = -Math.trunc(5 * (1 + normalRandInt(0, 5) / 100)); // Muscle benefits max out at 50
		}

		// Health
		health = Math.trunc((H.shortDamage / 2 - H.condition / 10) * (1 + normalRandInt(0, 5) / 100)); // Current condition reduces tiredness, health damage increases tiredness
		if (slave.assignment === Job.REST || slave.assignment === Job.CLINIC || slave.assignment === Job.SPA) {
			health = Math.max(0, health); // break vicious cycle - no additional tiredness accumulates from bad health for slaves assigned to rest
		}
		*/

		// Add advanced pregnancy/high .bellyPreg (it is either caused by an advanced pregnancy or high multiples, both draining) tiredness gain gated under preg effects
		// Add pregnancy speed up effects

		// day of rest
		if (slave.rules.rest === "mandatory") {
			if ([Job.GLORYHOLE, Job.FARMYARD, Job.CLUB, Job.PUBLIC, Job.WHORE, Job.BROTHEL, Job.SUBORDINATE, Job.HOUSE, Job.QUARTER, Job.FUCKTOY, Job.MASTERSUITE, Job.MILKED].includes(slave.assignment) || (V.dairyRestraintsSetting < 2 && slave.assignment === Job.DAIRY)) {
				restRules -= 20;
			}
		}

		tiredChange = livingRules + assignment + restRules + reward + punishment; // + muscles + health
		H.tired += tiredChange;

		// HG special cases
		if (slave.assignment === Job.HEADGIRL) {
			if (App.EndWeek.saVars.HGSlaveSuccess) {
				H.tired -= 5;
			}
			if (V.personalAttention.task === PersonalAttention.SUPPORTHG) {
				H.tired -= 10;
			}
		}
	} else {
		// fuckdolls get a static tiredness drop due to drugs and suit control
		H.tired -= 30;
	}
	H.tired = Math.clamp(H.tired, 0, 100);
};

/**
 * @param {App.Entity.SlaveState} slave
 * @param {number} [exhaustion=0]
 * @returns {number}
 */
globalThis.restEffects = function(slave, exhaustion = 0) {
	// exhaustion holds the weekly .tired gain from the assignment.
	if (!slave.fuckdoll) {
		if (slave.rules.rest === "mandatory") {
			return 0.86;
		} else if (slaveResting(slave)) {
			if (slave.assignment === window.Job.HOUSE || slave.assignment === window.Job.QUARTER || window.Job.SUBORDINATE || window.Job.FARMER || window.Job.STEWARD) {
				return 0.60;
			} else {
				return 0.25;
			}
		} else if (slave.health.tired + exhaustion >= 90 && !willWorkToDeath(slave)) {
			return 0.10;
		} else {
			return healthPenalty(slave);
		}
	}
	return 1;
};

/**
 * @param {App.Entity.SlaveState} slave
 * @returns {void}
 */
globalThis.tiredFucks = function(slave) {
	if (!slave.fuckdoll) {
		let acceptance = 0;
		acceptance += Math.trunc(slave.energy / 10);
		acceptance -= Math.trunc((slave.intelligence + slave.intelligenceImplant) / 10);
		if (slave.fetish === "masochist" || slave.fetish === "humiliation") {
			acceptance += Math.trunc(slave.fetishStrength / 10);
		}
		if (slave.assignment === Job.GLORYHOLE) {
			if ((acceptance > 20 && slave.devotion > 20) || slave.sexualFlaw === "self hating") {
				slave.health.tired += Math.trunc(slave.sexAmount * (1 + normalRandInt(0, 5) / 100) / 100);
			} else {
				slave.health.tired += Math.trunc(slave.sexAmount * (1 + normalRandInt(0, 5) / 100) / 50);
			}
		} else {
			if ((acceptance > 20 && slave.devotion > 20) || slave.sexualFlaw === "self hating") {
				slave.health.tired += Math.trunc(slave.sexAmount * (1 + normalRandInt(0, 5) / 100) / 50);
			} else {
				slave.health.tired += Math.trunc(slave.sexAmount * (1 + normalRandInt(0, 5) / 100) / 25);
			}
		}
	}
};


code:
App.EndWeek.labReport = function() {
	const frag = document.createDocumentFragment();
	let r = [];
	if (V.researchLab.hired + V.researchLab.menials > 0) {
		if (V.researchLab.tasks.length === 0) {
			const cash = (V.researchLab.speed * 90);
			r.push(`Since the lab is currently not working on any projects it takes contract work and earns you <span class="yellowgreen">${cashFormat(cash)}.</span>`);
			cashX(cash, "lab");
		} else {
			let work = V.researchLab.speed;
			while (work > 0) {
				const task = V.researchLab.tasks[0];
				if (!task) {
					const cash = Math.round(work * 90);
					work = 0;
					r.push(`<br>Your lab has <span class="positive">finished all projects.</span> The remaining time is used for contract work earning you <span class="yellowgreen">${cashFormat(cash)}.</span>`);
					cashX(cash, "lab");
				} else if (work < task.workLeft) {
					task.workLeft -= work;
					work = 0;
					r.push(`The lab continues ${task.type === "research" ? "research" : "work"} on ${addA(App.Data.prosthetics[task.id].name)}. It will take approximately ${numberWithPluralNonZero(Math.floor(task.workLeft / V.researchLab.speed) + 1, "week")} to complete.`);
				} else {
					work -= task.workLeft;
					r.push(`Your lab staff have <span class="positive">completed</span> their`);
					switch (task.type) {
						case "research":
							V.prosthetics[task.id].research = 1;
							r.push(`${App.Data.prosthetics[task.id].name} research project.`);
							break;
						case "craft":
							V.prosthetics[task.id].amount += 1;
							r.push(`${App.Data.prosthetics[task.id].name} construction project.`);
							break;
						case "craftFit":
							task.workLeft = 0;
							V.adjustProsthetics.push(task);
							V.adjustProstheticsCompleted++;
							r.push(`project to construct ${addA(App.Data.prosthetics[task.id].name)} for ${SlaveFullName(getSlave(task.slaveID))}.`);
							break;
					}
					V.researchLab.tasks.shift();
				}
				r.push(`<br>`);
			}
		}
	} else if (V.researchLab.tasks.length > 0) {
		r.push(`<span class="note">Without researchers your tasks will never be finished.</span>`);
	}
	return $(frag).append(r.join(' '))[0];
};


code:
/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
globalThis.minorInjuryResponse = function(slave) {
	const arcology = V.arcologies[0];
	const arcologyUpgrade = V.arcologyUpgrade;
	const {he, himself, He} = getPronouns(slave);

	return responseWithTracking(trackedCategory());

	/**
	 * @returns {keyof App.Data.Records.LastWeeksCash}
	 */
	function trackedCategory() {
		switch (slave.assignment) {
			case Job.WHORE:
				return "slaveAssignmentWhore";
			case Job.MADAM:
				return "slaveAssignmentMadam";
			case Job.BROTHEL:
				return "slaveAssignmentBrothel";
			case Job.PUBLIC:
				return "slaveAssignmentPublic";
			case Job.DJ:
				return "slaveAssignmentDj";
			case Job.CLUB:
				return "slaveAssignmentClub";
			default:
				throw new Error(`Minor injury response requested for unexpected assignment ${slave.assignment}`);
		}
	}

	/**
	 * @param {keyof App.Data.Records.LastWeeksCash} category
	 * @returns {string}
	 */
	function responseWithTracking(category) {
		let o = "";
		if (arcology.FSDegradationist > 20) {
			o += ` ${He} carries on, knowing that in your degradationist arcology, this is accepted behavior.`;
		} else if (arcology.FSPaternalist > 20) {
			if (arcologyUpgrade.drones === 1 && jsRandom(1, 100) > 50) {
				o += ` The security drones successfully detain him and oblige him to pay significant <span class="yellowgreen">compensation,</span> since abusing slaves is discouraged here.`;
				cashX(50, category, slave);
			} else if (arcologyUpgrade.grid === 1 && jsRandom(1, 100) > 50) {
				o += ` The computer systems successfully detain him and require him to pay significant <span class="yellowgreen">compensation,</span> since abusing slaves is discouraged here.`;
				cashX(50, category, slave);
			} else if (slave.skill.whoring > jsRandom(1, 100)) {
				o += ` ${slave.slaveName} is used to this sort of thing, and convinces him to pay significant <span class="yellowgreen">compensation,</span> since abusing slaves is discouraged here.`;
				cashX(50, category, slave);
			} else if (slave.skill.combat > 0) {
				o += ` ${slave.slaveName} can take care of ${himself}, and ${he} successfully forces him to pay significant <span class="yellowgreen">compensation,</span> since abusing slaves is discouraged here.`;
				cashX(50, category, slave);
			}
		} else {
			if (arcologyUpgrade.drones === 1 && jsRandom(1, 100) > 50) {
				o += ` The security drones successfully detain him and oblige him to pay minor <span class="yellowgreen">compensation.</span>`;
				cashX(10, category, slave);
			} else if (arcologyUpgrade.grid === 1 && jsRandom(1, 100) > 50) {
				o += ` The computer systems successfully detain him and require him to pay minor <span class="yellowgreen">compensation.</span>`;
				cashX(10, category, slave);
			} else if (slave.skill.whoring > jsRandom(1, 100)) {
				o += ` ${slave.slaveName} is used to this sort of thing, and convinces him to pay minor <span class="yellowgreen">compensation.</span>`;
				cashX(10, category, slave);
			} else if (slave.skill.combat > 0) {
				o += ` ${slave.slaveName} can take care of ${himself}, and ${he} successfully forces him to pay minor <span class="yellowgreen">compensation.</span>`;
				cashX(10, category, slave);
			}
		}
		return o;
	}
};


code:
App.EndWeek.nextWeek = function() {
	V.HackingSkillMultiplier = upgradeMultiplier('hacking');
	V.upgradeMultiplierArcology = upgradeMultiplier('engineering');
	V.upgradeMultiplierMedicine = upgradeMultiplier('medicine');
	V.upgradeMultiplierTrade = upgradeMultiplier('trading');

	const rival = V.arcologies.find(function(s) { return s.direction !== 0 && s.rival === 1; });
	if (rival && V.rivalOwner !== 0) {
		V.rivalOwner = rival.prosperity;
	} else if (!rival) {
		V.rivalSet = 0;
	}

	if (V.playerAging !== 0) {
		V.PC.birthWeek += 1;
		if (V.PC.ovaryAge >= 47 && V.PC.ovaries === 1 && (V.PC.preg === -1 || V.PC.preg === 0)) {
			V.PC.preg = -2;
		}
		if (V.PC.birthWeek >= 52) {
			V.PC.birthWeek = 0;
			if (V.playerAging === 2) {
				V.PC.physicalAge++;
				V.PC.actualAge++;
				V.PC.visualAge++;
				V.PC.ovaryAge++;
				agePCEffects();
			}
		}
	}
	if (V.menstruation === 1) {
		// TODO
	} else if (V.PC.geneticQuirks.superfetation === 2 && V.PC.womb.length > 0) {
		if (V.PC.fertPeak === 0) {
			V.PC.fertPeak = 1;
		}
		V.PC.fertPeak--;
	} else if (V.PC.fertPeak !== 0) {
		V.PC.fertPeak = 0;
	}
	if (V.PC.health.shortDamage > 0) {
		V.PC.health.shortDamage--;
	}

	// Adding random changes to the economy
	if (V.difficultySwitch === 1) {
		const globalEconSeed = random(1, 100);
		if (globalEconSeed > 98) {
			V.economy += 2;
		} else if (globalEconSeed > 85) {
			V.economy += 1;
		} else if (globalEconSeed <= 2) {
			V.economy -= 2;
		} else if (globalEconSeed <= 25 + V.econRate * 10) {
			V.economy -= 1;
		}
		if (V.economy < 20) {
			V.economy = 20;
		}
		const localEconSeed = random(1, 100);
		if (V.localEcon <= (V.economy + V.econAdvantage)) {
			if (localEconSeed > 95) {
				V.localEcon += 2;
			} else if (localEconSeed > 50) {
				V.localEcon += 1;
			} else if (localEconSeed <= 1) {
				V.localEcon -= 2;
			} else if (localEconSeed <= 10) {
				V.localEcon -= 1;
			}
		} else if (V.localEcon <= (V.economy + V.econAdvantage + 5)) {
			if (localEconSeed > 98) {
				V.localEcon += 2;
			} else if (localEconSeed > 66) {
				V.localEcon += 1;
			} else if (localEconSeed <= 2) {
				V.localEcon -= 2;
			} else if (localEconSeed <= 33) {
				V.localEcon -= 1;
			}
		} else if (localEconSeed > 99) {
			V.localEcon += 2;
		} else if (localEconSeed > 90) {
			V.localEcon += 1;
		} else if (localEconSeed <= 5) {
			V.localEcon -= 2;
		} else if (localEconSeed <= 50) {
			V.localEcon -= 1;
		}
		if (V.localEcon < 20) {
			V.localEcon = 20;
		}

		if (V.mods.food.market) {
			if (V.localEcon > 100) {
				V.mods.food.cost = Math.max(5 / (1 + (Math.trunc(1000 - 100000 / V.localEcon) / 10) / 100), 3.125);
			} else if (V.localEcon === 100) {
				V.mods.food.cost = 5;
			} else {
				V.mods.food.cost = Math.min(5 * (1 + 1.5 * Math.sqrt(Math.trunc(100000 / V.localEcon - 1000) / 10) / 100), 6.5);
			}
		}
		V.mods.food.cost = Math.trunc(2500 / V.localEcon);
		V.drugsCost = Math.trunc(10000 / V.localEcon);
		V.rulesCost = Math.trunc(10000 / V.localEcon);
		V.modCost = Math.trunc(5000 / V.localEcon);
		V.surgeryCost = Math.trunc(30000 / (V.localEcon * ((V.PC.career === "medicine" || V.PC.career === "medical assistant" || V.PC.career === "nurse") ? 2 : 1)));
	}

	V.arcologies[0].prosperity = Math.clamp(V.arcologies[0].prosperity, 1, V.AProsperityCap);

	V.averageTrust = 0;
	V.averageDevotion = 0;
	let slavesContributing = 0;
	let oldHG = -1;
	let newHG = -1;
	if (V.studio === 1) {
		for (const genre of App.Porn.getAllGenres()) {
			V.pornStars[genre.fameVar].p1count = 0;
		}
	}
	for (const slave of V.slaves) {
		ageSlaveWeeks(slave);
		if (slave.indenture > 0) {
			slave.indenture -= 1;
		}
		if (slave.induceLactation > 0) {
			slave.induceLactation--;
		}
		if (slave.lactation === 1) {
			if (slave.lactationDuration === 1) {
				slave.boobsMilk = Math.round(10 * slave.lactationAdaptation);
				slave.boobs += slave.boobsMilk;
			}
		}
		if (V.menstruation === 1) {
			// TODO
		} else if (slave.geneticQuirks.superfetation === 2 && slave.womb.length > 0) {
			if (slave.fertPeak === 0) {
				slave.fertPeak = 1;
			}
			slave.fertPeak--;
		} else if (slave.fertPeak !== 0) {
			slave.fertPeak = 0;
		}
		slave.trust = Number(slave.trust.toFixed(1));
		slave.devotion = Number(slave.devotion.toFixed(1));
		slave.oldDevotion = slave.devotion;
		slave.oldTrust = slave.trust;
		slave.minorInjury = 0;
		if (slave.sentence > 1) {
			slave.sentence -= 1;
		} else if (slave.sentence === 1) {
			removeJob(slave, slave.assignment);
		}
		if (slave.weekAcquired < 0) {
			slave.weekAcquired = 0;
		}
		if (slave.relationship === 0) {
			slave.relationshipTarget = 0;
		}
		if (slave.rivalry === 0) {
			slave.rivalryTarget = 0;
		} else if (slave.rivalry < 0) {
			slave.rivalryTarget = 0;
			slave.rivalry = 0;
		}
		if (slave.vagina < 0) {
			slave.vaginalAccessory = "none";
			slave.chastityVagina = 0;
			if (slave.piercing) {
				slave.piercing.vagina.weight = 0;
			}
		}
		if (slave.dick === 0) {
			slave.dickAccessory = "none";
			slave.chastityPenis = 0;
			slave.dickTat = 0;
			if (slave.piercing) {
				slave.piercing.dick.weight = 0;
			}
		}
		if (!hasAnyArms(slave)) {
			slave.armsTat = 0;
			slave.nails = 0;
			slave.armAccessory = "none";
		}
		if (!hasAnyLegs(slave)) {
			slave.heels = 0;
			slave.shoes = "none";
			slave.legAccessory = "none";
			slave.legsTat = 0;
		}
		/* irregular leptin production weight gain/loss setter */
		if (slave.geneticQuirks.wGain === 2 && slave.geneticQuirks.wLoss === 2) {
			slave.weightDirection = either(-1, 1);
		} else if (slave.geneticQuirks.wGain === 2) {
			slave.weightDirection = 1;
		} else if (slave.geneticQuirks.wLoss === 2) {
			slave.weightDirection = -1;
		} else {
			slave.weightDirection = 0;
		}
		/* Fix some possible floating point rounding errors, and bring precision to one decimal place. */
		SlaveStatClamp(slave);
		slave.energy = Math.clamp(slave.energy.toFixed(1), 0, 100);
		slave.attrXY = Math.clamp(slave.attrXY.toFixed(1), 0, 100);
		slave.attrXX = Math.clamp(slave.attrXX.toFixed(1), 0, 100);
		if (slave.fetishStrength > 95) {
			slave.fetishStrength = 100;
		} else {
			slave.fetishStrength = Math.clamp(slave.fetishStrength.toFixed(1), 0, 100);
		}
		slave.weight = Math.clamp(slave.weight.toFixed(1), -100, 200);
		slave.butt = Number(slave.butt.toFixed(1));
		slave.muscles = Math.clamp(slave.muscles.toFixed(1), -100, 100);
		slave.face = Math.clamp(slave.face.toFixed(1), -100, 100);
		slave.lips = Math.clamp(slave.lips.toFixed(1), 0, 100);
		slave.skill.oral = Math.clamp(slave.skill.oral.toFixed(1), 0, 100);
		slave.skill.vaginal = Math.clamp(slave.skill.vaginal.toFixed(1), 0, 100);
		slave.skill.anal = Math.clamp(slave.skill.anal.toFixed(1), 0, 100);
		slave.skill.whoring = Math.clamp(slave.skill.whoring.toFixed(1), 0, 100);
		slave.skill.entertainment = Math.clamp(slave.skill.entertainment.toFixed(1), 0, 100);
		slave.lactationAdaptation = Math.clamp(slave.lactationAdaptation.toFixed(1), 0, 100);
		slave.intelligenceImplant = Math.clamp(slave.intelligenceImplant.toFixed(1), -15, 30);
		slave.prematureBirth = 0;
		if (V.HGSuiteEquality === 1 && V.HeadGirlID !== 0 && slave.devotion > 50) {
			if (slave.assignment === "live with your Head Girl") {
				newHG = slave.ID;
			} else if (slave.ID === V.HeadGirlID) {
				oldHG = slave.ID;
			}
		}
		/* AVERAGE VALUES UPDATE */
		if (assignmentVisible(slave)) {
			V.averageTrust += slave.trust;
			V.averageDevotion += slave.devotion;
			slavesContributing++;
		} else if (
			slave.assignment !== "be confined in the cellblock" &&
			slave.assignment !== "be confined in the arcade" &&
			(slave.assignment !== "work in the dairy" || V.dairyRestraintsSetting < 2) &&
			slave.assignment !== "labor in the production line"
		) {
			V.averageTrust += slave.trust * 0.5;
			V.averageDevotion += slave.devotion * 0.5;
			slavesContributing += 0.5;
		}
		if (V.studio === 1) {
			const activeGenres = App.Porn.getAllGenres().filter((g) => slave.porn.fame[g.fameVar] > 0);
			for (const genre of activeGenres) {
				V.pornStars[genre.fameVar].p1count++;
			}
		}
		if (slave.choosesOwnAssignment > 0) {
			assignJob(slave, "choose her own job");
		}
	}
	if (slavesContributing !== 0) {
		V.averageTrust = V.averageTrust / slavesContributing;
		V.averageDevotion = V.averageDevotion / slavesContributing;
	}
	V.enduringTrust = (V.averageTrust + (V.enduringTrust * 3)) / 4;
	V.enduringDevotion = (V.averageDevotion + (V.enduringDevotion * 3)) / 4;

	if (oldHG !== -1 && newHG !== -1) {
		const oldTimeInGrade = V.HGTimeInGrade;
		// preserve time in grade during HG swaps
		const keepHelpingHG = (V.personalAttention.task === PersonalAttention.SUPPORTHG); // keep removeJob from clearing PC HG supporting.
		removeJob(getSlave(newHG), "live with your Head Girl");
		assignJob(getSlave(oldHG), "live with your Head Girl");
		assignJob(getSlave(newHG), "be your Head Girl");
		getSlave(newHG).diet = "healthy";
		V.HGTimeInGrade = oldTimeInGrade;
		if (keepHelpingHG) {
			V.personalAttention.task = PersonalAttention.SUPPORTHG;
		}
	}

	if (V.PC.refreshment.includes("fertility")) {
		V.PC.forcedFertDrugs = Math.max(+V.PC.forcedFertDrugs, 1);
	} else if (V.PC.forcedFertDrugs > 0) {
		V.PC.forcedFertDrugs--;
	}

	if (V.FCTV.receiver > 0) {
		if (V.FCTV.pcViewership.frequency !== -1) {
			// Count down to 0 for a show
			V.FCTV.pcViewership.count = Math.max((V.FCTV.pcViewership.count - 1), 0);
		}
	}

	V.week++;

	if (V.playerSurgery > 0) {
		V.playerSurgery--;
	}

	// advance the event queue
	if (V.eventQueue[0] && V.eventQueue[0].length > 0) {
		console.log("These events were queued for this week, but got skipped: ", V.eventQueue[0]);
	}
	V.eventQueue.shift();

	if (V.secExpEnabled > 0) {
		if (V.SecExp.buildings.riotCenter) {
			V.SecExp.buildings.riotCenter.sentUnitCooldown = Math.max(V.SecExp.buildings.riotCenter.sentUnitCooldown - 1, 0);
		}
		V.SecExp.proclamation.cooldown = Math.max(V.SecExp.proclamation.cooldown - 1, 0);
		V.SecExp.war = {foughtThisWeek: 0, type: ""};
	}

	App.EndWeek.weather();

	if (V.boomerangWeeks) {
		V.boomerangWeeks++;
	} else {
		V.boomerangSlave = 0;
	}
	if (V.traitorWeeks) {
		V.traitorWeeks++;
	}

	V.thisWeeksFSWares = V.merchantFSWares.randomMany(2);
	V.thisWeeksIllegalWares = V.merchantIllegalWares.randomMany(1);
	V.prisonCircuitIndex++;
	if (V.prisonCircuit[V.prisonCircuitIndex] === "juvenile detention" && (V.minimumSlaveAge >= 16 || V.pedo_mode === 1)) {
		V.prisonCircuitIndex++; // skip juvenile detention if juvenile slaves are not allowed, or we're in pedo mode (where all prisoners are juvenile)
	}
	if (V.prisonCircuitIndex >= V.prisonCircuit.length) {
		V.prisonCircuitIndex = 0;
	}

	V.RIESkip = [];
	V.independenceDay = 1;
	V.coursed = 0;
	V.JFC.reorder = 0;
	V.customSlaveReorder = 0;
	V.prestigeAuctioned = 0;
	V.eliteAuctioned = 0;
	V.shelterSlave = 0;
	V.shelterSlaveBought = 0;
	V.slaveMarketLimit = 10 + (V.rep / 1000);
	V.slavesSeen = 0;
	V.slavesSacrificedThisWeek = 0;

	if (V.pit) {
		V.pit.fought = false;
	}

	V.activeSlave = 0;
	V.returnTo = "";

	// delete endweek flag
	delete V.endweekFlag;

	if (V.autosave !== 0) {
		// @ts-ignore
		Save.autosave.save("Week Start Autosave");
	}

	if (V.SF.Toggle && V.SF.FS.Tension > 100) {
		if (V.rep > 17500) {
			V.rep = 17500;
		}
	}
	V.NaNArray = findNaN();

	function agePCEffects() {
		switch (V.PC.actualAge) {
			case 3:
				V.AgeTrainingLowerBoundPC = 18;
				V.AgeTrainingUpperBoundPC = 20;
				V.AgeEffectOnTrainerPricingPC = .1;
				V.AgeEffectOnTrainerEffectivenessPC = .1;
				break;
			case 4:
				V.AgeTrainingLowerBoundPC = 17;
				V.AgeTrainingUpperBoundPC = 19;
				V.AgeEffectOnTrainerPricingPC = .15;
				V.AgeEffectOnTrainerEffectivenessPC = .15;
				break;
			case 5:
				V.AgeTrainingLowerBoundPC = 16;
				V.AgeTrainingUpperBoundPC = 18;
				V.AgeEffectOnTrainerPricingPC = .35;
				V.AgeEffectOnTrainerEffectivenessPC = .35;
				break;
			case 6:
				V.AgeTrainingLowerBoundPC = 15;
				V.AgeTrainingUpperBoundPC = 17;
				V.AgeEffectOnTrainerPricingPC = .55;
				V.AgeEffectOnTrainerEffectivenessPC = .55;
				break;
			case 7:
				V.AgeTrainingLowerBoundPC = 14;
				V.AgeTrainingUpperBoundPC = 16;
				V.AgeEffectOnTrainerPricingPC = .75;
				V.AgeEffectOnTrainerEffectivenessPC = .75;
				break;
			case 8:
				V.AgeTrainingLowerBoundPC = 13;
				V.AgeTrainingUpperBoundPC = 15;
				V.AgeEffectOnTrainerPricingPC = .85;
				V.AgeEffectOnTrainerEffectivenessPC = .85;
				break;
			case 9:
				V.AgeTrainingLowerBoundPC = 12;
				V.AgeTrainingUpperBoundPC = 14;
				V.AgeEffectOnTrainerPricingPC = 1.00;
				V.AgeEffectOnTrainerEffectivenessPC = 1.00;
				break;
			case 10:
				V.AgeTrainingLowerBoundPC = 11;
				V.AgeTrainingUpperBoundPC = 13;
				V.AgeEffectOnTrainerPricingPC = 1.0005;
				V.AgeEffectOnTrainerEffectivenessPC = 1.0005;
				break;
			case 11:
				V.AgeTrainingLowerBoundPC = 10;
				V.AgeTrainingUpperBoundPC = 12;
				V.AgeEffectOnTrainerPricingPC = 1.01;
				V.AgeEffectOnTrainerEffectivenessPC = 1.01;
				break;
			case 12:
				V.AgeTrainingLowerBoundPC = 9;
				V.AgeTrainingUpperBoundPC = 11;
				V.AgeEffectOnTrainerPricingPC = 1.02;
				V.AgeEffectOnTrainerEffectivenessPC = 1.02;
				break;
			case 13:
				V.AgeTrainingLowerBoundPC = 8;
				V.AgeTrainingUpperBoundPC = 10;
				V.AgeEffectOnTrainerPricingPC = 1.03;
				V.AgeEffectOnTrainerEffectivenessPC = 1.03;
				break;
			case 14:
				V.AgeTrainingLowerBoundPC = 7;
				V.AgeTrainingUpperBoundPC = 9;
				V.AgeEffectOnTrainerPricingPC = 1.04;
				V.AgeEffectOnTrainerEffectivenessPC = 1.04;
				break;
			case 15:
				V.AgeTrainingLowerBoundPC = 6;
				V.AgeTrainingUpperBoundPC = 8;
				V.AgeEffectOnTrainerPricingPC = 1.05;
				V.AgeEffectOnTrainerEffectivenessPC = 1.05;
				break;
			case 16:
				V.AgeTrainingLowerBoundPC = 5;
				V.AgeTrainingUpperBoundPC = 7;
				V.AgeEffectOnTrainerPricingPC = 1.06;
				V.AgeEffectOnTrainerEffectivenessPC = 1.06;
				break;
			case 17:
				V.AgeTrainingLowerBoundPC = 4;
				V.AgeTrainingUpperBoundPC = 6;
				V.AgeEffectOnTrainerPricingPC = 1.07;
				V.AgeEffectOnTrainerEffectivenessPC = 1.07;
				break;
			case 18:
				V.AgeTrainingLowerBoundPC = 3;
				V.AgeTrainingUpperBoundPC = 5;
				V.AgeEffectOnTrainerPricingPC = 1.08;
				V.AgeEffectOnTrainerEffectivenessPC = 1.08;
				break;
		}
	}
};