code:
globalThis.endWeek = (function() {
	function doEndWeek() {
		// purge SugarCube's expired state cache
		State.expired.length = 0;

		// report setup
		setupLastWeeksCash();
		setupLastWeeksRep();

		// globals setup
		resetSlaveMarkets();
		resetSlaveCounters();
		for (const s of V.slaves) {
			slavePrep(s);
		}
		setUseWeights();
		saveWeekTotals();

		// pass time for objects that need it
		weather ();
		organs();
		prosthetics();
		nursery();
		food();
		PC();

		// week end is done, move on to gameover or SA reports
		resetMiscGlobals();
		advance();
	}

	function resetSlaveMarkets() {
		V.gingering = 0;
		V.market = null;
		for (const school of App.Data.misc.schools.keys()) {
			V[school].schoolSale = 0;
		}
	}

	function resetSlaveCounters() {
		V.subSlaves = 0;
	}

	function slavePrep(s) {
		if (s.assignment === Job.SUBORDINATE && s.subTarget === 0) {
			V.subSlaves++;
		}
		s.lastWeeksCashIncome = 0;
		s.lastWeeksRepIncome = 0;
		s.lastWeeksRepExpenses = 0;
	}

	function setUseWeights() {
		V.oralUseWeight = 5;
		V.vaginalUseWeight = 5;
		V.analUseWeight = 5;
		V.mammaryUseWeight = 1;
		V.penetrativeUseWeight = 1;

		if (V.policies.oralAppeal === 1) {
			V.oralUseWeight += 2;
			V.vaginalUseWeight -= 1;
			V.analUseWeight -= 1;
		} else if (V.policies.vaginalAppeal === 1) {
			V.oralUseWeight -= 1;
			V.vaginalUseWeight += 2;
			V.analUseWeight -= 1;
		} else if (V.policies.analAppeal === 1) {
			V.oralUseWeight -= 1;
			V.vaginalUseWeight -= 1;
			V.analUseWeight += 2;
		}

		if (V.policies.oralAppeal === -1) {
			V.oralUseWeight -= 2;
			V.vaginalUseWeight += 1;
			V.analUseWeight += 1;
		}
		if (V.policies.vaginalAppeal === -1) {
			V.oralUseWeight += 1;
			V.vaginalUseWeight -= 2;
			V.analUseWeight += 1;
		}
		if (V.policies.analAppeal === -1) {
			V.oralUseWeight += 1;
			V.vaginalUseWeight += 1;
			V.analUseWeight -= 2;
		}

		if (V.policies.gumjobFetishism === 1) {
			V.oralUseWeight += 2;
		}

		if (V.policies.sexualOpenness === 1) {
			V.penetrativeUseWeight += 1;
		}
	}

	function saveWeekTotals() {
		V.cashLastWeek = V.cash;
		V.repLastWeek = V.rep;
		V.foodLastWeek = V.food;
	}

	function weather() {
		if (V.weatherRemaining > 0) {
			V.weatherRemaining -= 1;
		}
	}

	function organs() {
		function advanceOrgan(o) {
			if (o.weeksToCompletion > 0) {
				if (V.organFarmUpgrade === 3) {
					o.weeksToCompletion -= 4;
				} else if (V.organFarmUpgrade === 2) {
					o.weeksToCompletion -= 2;
				} else {
					o.weeksToCompletion--;
				}
			}
		}

		for (const organ of V.organs) {
			advanceOrgan(organ);
		}

		// move completed non-incubator organs to V.completedOrgans
		V.organs = V.organs.filter(function(o) {
			if (o.weeksToCompletion <= 0) {
				V.completedOrgans.push(o);
				return false;
			}
			return true;
		});

		for (const organ of V.incubatorOrgans) {
			advanceOrgan(organ);
		}

		// TODO: nurseryOrgans too, if those ever exist...
	}

	function prosthetics() {
		for (const p of V.adjustProsthetics) {
			if (p.workLeft > 0) {
				if (V.prostheticsUpgrade === 3) {
					p.workLeft -= 40;
				} else if (V.prostheticsUpgrade === 2) {
					p.workLeft -= 20;
				} else {
					p.workLeft -= 10;
				}
				if (p.workLeft <= 0) {
					V.adjustProstheticsCompleted++;
				}
			}
		}
	}

	function nursery() {
		for (const c of V.cribs) {
			c.growTime--;
			c.birthWeek++;
			if (c.birthWeek >= 52) {
				c.birthWeek = 0;
				c.actualAge++;
			}
			if (c.actualAge >= 3) {
				App.Facilities.Nursery.infantToChild(c);
			}
		}
	}

	function food() {
		function foodConsumption(s) {
			if (s.diet === "restricted") {
				return 1.8;
			} else if (s.diet === "slimming") {
				return 1.9;
			} else if (s.diet === "muscle building") {
				return 2.1;
			} else if (s.diet === "fattening") {
				return 2.2;
			} else {
				return 2;
			}
		}

		if (V.foodMarket > 0) {
			V.foodConsumption = ((V.lowerClass*V.foodRate.lower) + (V.middleClass*V.foodRate.middle) + (V.upperClass*V.foodRate.upper) + (V.topClass*V.foodRate.top));
			V.foodConsumption += V.slaves.reduce((acc, cur) => acc += foodConsumption(cur), 0);
			V.food -= Math.max(V.foodConsumption, V.food);
			V.foodConsumption = 0;
		}
	}

	function PC() {
		V.PC.sexualEnergy = 4;
		if (V.PCSlutContacts === 2) {
			V.PC.sexualEnergy -= 3;
		}
		if (V.personalAttention === "sex") {
			V.PC.sexualEnergy += 2;
		}
		if (V.PC.physicalAge >= 80) {
			V.PC.sexualEnergy -= 6;
		} else if (V.PC.physicalAge >= 72) {
			V.PC.sexualEnergy -= 5;
		} else if (V.PC.physicalAge >= 65) {
			V.PC.sexualEnergy -= 4;
		} else if (V.PC.physicalAge >= 58) {
			V.PC.sexualEnergy -= 3;
		} else if (V.PC.physicalAge >= 50) {
			V.PC.sexualEnergy -= 2;
		} else if (V.PC.physicalAge >= 42) {
			V.PC.sexualEnergy -= 1;
		} else if (V.PC.physicalAge >= 35) {
			V.PC.sexualEnergy += 0;
		} else if (V.PC.physicalAge >= 31) {
			V.PC.sexualEnergy += 1;
		} else if (V.PC.physicalAge >= 28) {
			V.PC.sexualEnergy += 2;
		} else if (V.PC.physicalAge >= 21) {
			V.PC.sexualEnergy += 3;
		} else if (V.PC.physicalAge >= 13) {
			V.PC.sexualEnergy += 4;
		} else if (V.PC.physicalAge === 12) {
			V.PC.sexualEnergy += 1;
		} else if (V.PC.physicalAge === 11) {
			V.PC.sexualEnergy -= 2;
		} else if (V.PC.physicalAge >= 0) {
			V.PC.sexualEnergy -= 6;
		}
		if (V.PC.balls >= 10) {
			V.PC.sexualEnergy += 2;
		} else if (V.PC.balls >= 5) {
			V.PC.sexualEnergy++;
		}
		if (V.PC.preg > 20) {
			if (V.PC.pregMood === 2) {
				V.PC.sexualEnergy += 4;
			} else {
				V.PC.sexualEnergy -= 3;
			}
		} else if (V.PC.preg > 0) {
			V.PC.sexualEnergy -= 1;
		} else {
			if (V.PC.fertDrugs === 1) {
				V.PC.sexualEnergy++;
			}
			if (V.PC.forcedFertDrugs > 0) {
				V.PC.sexualEnergy += 2;
			}
		}
		if (V.PC.staminaPills > 0) {
			V.PC.sexualEnergy += 2;
		}
		if (V.PC.preg > 0) {
			WombProgress(V.PC, 1, 1);
			WombNormalizePreg(V.PC);
			V.PC.pregWeek = V.PC.preg;
			let newBelly = WombGetVolume(V.PC);
			if (newBelly >= V.PC.belly) {
				V.PC.belly = newBelly;
			} else if (V.PC.belly > 500) {
				V.PC.belly *= 0.75;
			}
			V.PC.fertDrugs = 0;
		} else if (V.PC.belly > 0) {
			if (V.PC.belly < 100) {
				V.PC.belly = 0;
			} else {
				V.PC.belly *= 0.75;
			}
		}
		if (V.PC.pregWeek < 0) {
			V.PC.pregWeek++;
		}
	}

	function resetMiscGlobals() {
		// if a global is going to be used by the end-of-week reports, it must be reset here instead of in Next Week
		V.encyclopedia = "How to Play";
		V.expiree = 0;
		V.retiree = 0;

		V.StudID = 0;
		V.fuckSlaves = 0;
		V.publicServants = 0;
		V.cumSlaves = 0;
	}

	function advance() {
		if (V.slaves.length < 1) {
			V.gameover = "no slaves";
			Engine.play("Gameover");
		} else if (V.arcologies[0].ownership < V.arcologies[0].minority) {
			V.gameover = "ownership";
			Engine.play("Gameover");
		} else {
			Engine.play("Slave Assignments Report");
		}
	}

	function confirmEndWeek() {
		if (!V.sideBarOptions.confirmWeekEnd || confirm("Are you sure you want to end the week?")) {
			App.UI.EndWeekAnim.start();
			setTimeout(doEndWeek, 0); // execute immediately, but after the event loop runs, so the loading screen gets shown
		}
	}

	return confirmEndWeek;
})();


code:
App.UI.EndWeekAnim = (function() {
	let loadLockID = -1;
	let infoDiv = null;

	function makeInfoDiv() {
		infoDiv = $(`

Processing week ${V.week}...

${V.arcologies[0].name} | ${V.slaves.length} slaves

		`);
	}

	function start() {
		if (loadLockID === -1) {
			makeInfoDiv();
			$("#init-screen").append(infoDiv);
			loadLockID = LoadScreen.lock();
		}
	}

	function end() {
		if (loadLockID !== -1) {
			setTimeout(() => {
				LoadScreen.unlock(loadLockID);
				infoDiv.remove();
				infoDiv = null;
				loadLockID = -1;
			}, 0);
		}
	}

	return {
		start,
		end
	};
})();

repo_name: Welptard/fc

license: mit


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;
	}
};


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

	// eslint-disable-next-line no-unused-vars
	let he, him, his, hers, himself, girl, loli, He, His;
	({
		// eslint-disable-next-line no-unused-vars
		he, him, his, hers, himself, girl, He, His, loli
	} = getPronouns(slave));
	let 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) {
		assignBonus += 40;
	} else if (slave.assignment === Job.SPA || slave.assignment === Job.REST) {
		assignBonus += 20;
	} else if ((slave.assignment === Job.MASTERSUITE || slave.assignment === Job.FUCKTOY) && V.PC.skill.medicine >= 40) {
		assignBonus += 10;
	} else if (setup.nurseCareers.includes(slave.career) || slave.skill.nurse >= 100 || slave.intelligence + slave.intelligenceImplant > 95) { // Let slaves with experience or brains use it
		assignBonus += 10;
	}
	if (random < 6) { // There is always a 5% chance of a slave feeling worse or coming in contact with an illness
		if (H.illness > 0) {
			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="red">${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="red">makes an attempt to claim ${his} life.</span>`;
			}
		} else {
			getIll(slave);
			if (H.illness > 0) {
				r += ` ${He} has come down with <span class="red">${addA(sicknessDegree[H.illness])}.</span>`;
			}
		}
	} else if (random > 95 && H.illness > 0) { // There is always a 5% chance of a slave getting better
		H.illness -= 1;
		if (H.illness < 0) {
			H.illness = 0;
			improveCondition(slave, 5);
			r += ` <span class="green">${His} sickness has waned</span> and ${he} now feels better.`;
		} else {
			r += ` ${His} immune system <span class="green">fights back</span> against ${his} illness.`;
		}
	} else {
		/* eslint-disable camelcase */
		let nurse_effectiveness = nurseEffectiveness(slave);
		let health_adjusted = H.condition - H.longDamage - H.shortDamage * 1.25;
		let age_modifier = Math.min(Math.trunc((slave.physicalAge - 18) / 3), 0);
		let bonus_modifiers = random + assignBonus + nurse_effectiveness;
		let curativesBonus = (slave.curatives > 1 || slave.inflationType === "curative") ? 2 : 1;
		let industrialDairyImmunoBoost = (V.dairyRestraintsSetting > 1 && slave.assignment === Job.DAIRY) ? 60 : 0;

		// When ill, a slave has a 60% chance of getting better the next week at complete default, 70% with a favorable assignment, 80% with curatives, 90% with both measures active and additional benefits depending on the nurse on duty
		if (H.illness > 0 && ((health_adjusted + age_modifier + industrialDairyImmunoBoost) / 3) + bonus_modifiers > (30 + (H.illness * 10)) / curativesBonus) {
			if (nurse_effectiveness > 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="green">successfully treats</span> ${his} illness.`;
			} else {
				H.illness -= 1;
				r += ` ${His} body <span class="green">fights back</span> against ${his} illness.`;
			}
			if (H.illness === 0) {
				r += ` ${He} no longer <span class="green">shows any signs</span> of ${his} previous sickness.`;
			}
		} else if (H.illness === 0) {
			if ([Job.BODYGUARD, Job.DJ, Job.MADAM, Job.ARCADE, Job.GLORYHOLE, Job.CLUB, Job.PUBLIC, Job.WHORE, Job.BROTHEL].includes(slave.assignment)) { // Limit to outside jobs only
				if (((Math.min(health_adjusted, 50) + age_modifier) / 3) + bonus_modifiers < 30 / Math.min(curativesBonus + 1, 2)) { // Chance of getting ill 30% at complete default, 20% with a favorable assignment, 15% with curatives or preventatives, 10% with both measures active and a small benefit from effective Nurse screening
					getIll(slave);
					r += ` ${He} has come down with <span class="red">${addA(sicknessDegree[H.illness])}.</span>`;
				}
			}
		} else {
			healthDamage(slave, Math.pow(H.illness, 2));
			r += ` ${He} <span class="red">suffers under ${his} ${sicknessDegree[H.illness]}.</span>`;
		}
		/* eslint-enable camelcase */
	}
	return r;
};

/**
 * 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
 * @returns {void}
 */
globalThis.getIll = function(slave) {
	const H = slave.health;
	const illness = jsRandom(1, 6) + jsRandom(1, 6) + jsRandom(1, 6) - Math.trunc(slave.chem / 150) + Math.trunc(H.condition / 20);
	if (V.seeIllness !== 0) {
		if (slave.curatives !== 1 && slave.inflationType !== "curative") {
			if (slave.assignment !== Job.CLINIC) {
				if (illness < 4) {
					H.illness = 5; // 1.8% chance
				} else if (illness < 5) {
					H.illness = 4; // 2.8% chance
				} else if (illness < 6) {
					H.illness = 3; // 11.6% chance
				} else if (illness < 8) {
					H.illness = 2; // 21.3% chance
				} else {
					H.illness = 1; // 62.5% chance
				}
			}
		}
	}
};

/**
 * Attempts to pass illness from slave1 to slave2.
 * @param {App.Entity.SlaveState} slave1
 * @param {App.Entity.SlaveState} slave2
 * @returns {string}
 */
globalThis.passIllness = function(slave1, slave2) {
	if (V.seeIllness !== 0) {
		if (slave1.curatives !== 1) {
			if (slave1.assignment !== Job.CLINIC) {
				slave1.health.illness = slave2.health.illness;
			}
		}
	}
	return ` ${slave1.slaveName} has caught ${slave2.slaveName}'s sickness.`;
};

/**
 * Once a new illness is rolled this determines how bad it is initially, chem levels seriously increase the chances of a higher initial value
 * @param {App.Entity.SlaveState} slave
 * @returns {void}
 */
globalThis.poorHealthNeedReduction = function(slave) {
	// Slave .need reduction if ill or tired
	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; // Creating a purchasable upgrade to increase the amount of slaves the nurse can handle -- TODO
	const clinicScreening = 1; // Assumes the clinic is set to screening all slaves to improve their chances of staying healthy. Turning it off would allow the nurse to focus on just her patients in the clinic -- TODO
	if (S.Nurse) {
		const nurseSkill = setup.nurseCareers.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) { // 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;
			}
		}
	} else {
		return 0;
	}
};

/**
 * Run at the end of the week to take care of health changes
 * @param {App.Entity.SlaveState} 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;
		if (slave.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 (slave.assignment === Job.REST || slave.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 (slave.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));
	}

	H.health = H.condition - H.longDamage - H.shortDamage;
};

/**
 * 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 {App.Entity.SlaveState} 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 (setup.attendantCareers.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;
				V.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;
				V.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;
				V.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) {
				const workload = ((V.dormitoryPopulation + V.roomsPopulation - V.subSlaves) > 5) ? (V.subSlaves / (V.dormitoryPopulation + V.roomsPopulation - V.subSlaves)) : 1;
				if (slave.devotion > 20) {
					assignment += 7;
				} else {
					assignment += 10;
				}
				assignment = Math.ceil(assignment / workload); // 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;
					V.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;
					V.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;
				V.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;
				V.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;
				V.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;
				V.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 === 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="green">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(setup.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="green">completed</span> their`);
					switch (task.type) {
						case "research":
							V.prosthetics[task.id].research = 1;
							r.push(`${setup.prosthetics[task.id].name} research project.`);
							break;
						case "craft":
							V.prosthetics[task.id].amount += 1;
							r.push(`${setup.prosthetics[task.id].name} construction project.`);
							break;
						case "craftFit":
							task.workLeft = 0;
							V.adjustProsthetics.push(task);
							V.adjustProstheticsCompleted++;
							r.push(`project to construct ${addA(setup.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:
App.EndWeek.masterSuiteReport = function() {
	let frag = document.createDocumentFragment();
	const slaves = App.Utils.sortedEmployees(App.Entity.facilities.masterSuite);
	const msAvg = App.Utils.masterSuiteAverages();

	// find a potential legendary abolitionist
	const abolitionist = slaves.find((s) => (s.devotion > 95) && (s.prestige === 0) && (
		(s.origin === "You sentenced $him to enslavement as a punishment for attempted theft of a slave.") ||
		(s.origin === "$He is an enslaved Daughter of Liberty.") ||
		(s.origin === "You got $him at the Slave Shelter. $He is an enslaved Daughter of Liberty, caught some weeks after the failed coup. $His previous owner used $him as a punching bag and dart board, then when he was bored of $him tattooed obscenities all over $his body and threw $him away.") ||
		(s.origin === "$He is an enslaved member of an anti-slavery extremist group.") ||
		(s.career === "an antislavery activist")
	));
	V.legendaryAbolitionistID = abolitionist ? abolitionist.ID : 0;

	const pregnantSlaves = V.masterSuiteUpgradePregnancy ? slaves.filter((s) => s.pregKnown > 0).length : 0;

	function concubineText() {
		let r = [];
		const {He, he, his, him, himself} = getPronouns(S.Concubine);

		r.push(`Your concubine ${SlaveFullName(S.Concubine)} is serving you in ${V.masterSuiteName}. More than any other slave, ${his} sexual brilliance and physical appeal are critical to your reputation.`);

		if ((S.Concubine.prestigeDesc === "You bankrupted and enslaved $him in revenge for $his part in the attack on your arcology by the Daughters of Liberty.") && (S.Concubine.newGamePlus === 0)) {
			r.push(`${He} was once your rival, and your relationship is widely thought to be <span class="green">the perfect modern romance.</span>`);
			repX(500, "concubine", S.Concubine);
		} else if ((S.Concubine.prestige > 0)) {
			repX(500*S.Concubine.prestige, "concubine", S.Concubine);
			if (V.verboseDescriptions === 1) {
				r.push(`Keeping such a prestigious slave as your concubine <span class="green">adds to your fame.</span>`);
				if (S.Concubine.prestigeDesc === "$He is a famed Free Cities whore, and commands top prices.") {
					r.push(`When ${he} has a free moment, ${he} refines ${his} flexibility so that ${he} is prepared for any sexual position you can think of, and many more that ${he} researched just for your pleasure.`);
				}
				if (S.Concubine.prestigeDesc === "$He is a famed Free Cities slut, and can please anyone.") {
					r.push(`When ${he} has a free moment, ${he} pretties ${himself} up so that ${he} may be as beautiful as possible to make you look even better.`);
				}
				if (S.Concubine.prestigeDesc === "$He is remembered for winning best in show as a cockmilker.") {
					if (S.Concubine.balls > 10 || S.Concubine.prostate > 1) {
						r.push(`${He} does ${his} best to prevent ${himself} from making a mess when you don't want one. When ${he} has free time, ${he} researches new techniques to make use of ${his} huge loads to entertain you.`);
					} else if (S.Concubine.balls > 0) {
						r.push(`When ${he} has a free moment, ${he} researches ways to increase the size of ${his} loads for you; ${he} dreams of the day ${he} show you just what ${he} was capable of.`);
					} else {
						r.push(`${He} wishes ${he} could blow huge loads for you, but without balls, there is little ${he} can do.`);
					}
				}
				if (S.Concubine.prestigeDesc === "$He is remembered for winning best in show as a dairy cow.") {
					if (S.Concubine.lactation > 1 || S.Concubine.lactationAdaptation > 90) {
						r.push(`${He} does ${his} best to prevent ${himself} from making a mess when you don't want one. When ${he} has free time, ${he} researches new techniques to make use of ${his} excessive milk to entertain you.`);
					} else if (S.Concubine.lactation > 0) {
						r.push(`${He} does ${his} best to prevent ${himself} from making a mess when you don't want one. When ${he} has free time, ${he} researches new techniques to make use of ${his} breast milk to entertain you.`);
					} else {
						r.push(`${He} wishes ${he} could lactate for you, but ${he} has dried up since ${his} glory days.`);
					}
				}
				if (S.Concubine.prestigeDesc === "$He is remembered for winning best in show as a breeder.") {
					if (S.Concubine.bellyPreg >= 5000) {
						r.push(`When ${he} has a free moment, ${he} refines ${his} flexibility so that ${he} can perform any sexual position possible for ${him} in ${his} motherly state. ${He} takes the time to look up new positions to work around ${his} growing pregnancy.`);
					} else if (isFertile(S.Concubine) || S.Concubine.preg > 0) {
						r.push(`When ${he} has a free moment, ${he} refines ${his} flexibility so that ${he} is prepared for any sexual position you can think of, no matter how heavy ${he} becomes with children.`);
					} else {
						r.push(`When ${he} has a free moment, ${he} researches ways to restore ${his} fertility; ${he} dreams of the day ${he} can carry `);
						if (V.PC.dick !== 0) {
							r.push(`your children.`);
						} else {
							r.push(`children for you.`);
						}
					}
				}
			}
		}
		if (S.Concubine.porn.prestige > 2) {
			repX(800, "concubine", S.Concubine);
			r.push(`Having a porn star as your personal bed warmer <span class="green">reflects on your standing.</span> Your citizens can only wonder at what kinky things happen behind closed doors.`);
		} else if (S.Concubine.porn.prestige > 1) {
			repX(300, "concubine", S.Concubine);
			r.push(`Having a rising porn star as your personal bed warmer <span class="green">reflects on your standing.</span>`);
		}
		if (S.Concubine.counter.oral + S.Concubine.counter.anal + S.Concubine.counter.vaginal + S.Concubine.counter.mammary + S.Concubine.counter.penetrative > 1000) {
			if (V.verboseDescriptions === 1) {
				r.push(`Many citizens `);
				if (S.Concubine.counter.publicUse > 10) {
					r.push(`remember having had ${him} themselves, and`);
				}
				r.push(`<span class="green">respectfully</span> envy you ${his} exclusive company.`);
			}
			repX(300, "concubine", S.Concubine);
		}
		/* Perform facility based rule changes - FIXME - dev/trust living condition changes probably should be in saRules; there's no text reporting these changes here */
		if (V.masterSuiteUpgradeLuxury > 0) {
			S.Concubine.rules.living = "luxurious";
			S.Concubine.devotion += 4;
			S.Concubine.trust += 4;
		} else {
			S.Concubine.rules.living = "normal";
			S.Concubine.devotion += 2;
			S.Concubine.trust += 2;
		}
		repX(Beauty(S.Concubine) * 5 + (S.Concubine.skill.vaginal || 0) + (S.Concubine.skill.anal || 0) + (S.Concubine.skill.oral || 0) + (S.Concubine.skill.whoring || 0) + (S.Concubine.skill.entertainment || 0), "concubine", S.Concubine);
		return r.join(' ');
	}

	/** Generate text specific to non-concubine MS slaves
	 * @param {App.Entity.SlaveState} slave
	 * @returns {string}
	 */
	function nonConcubineText(slave) {
		let r = [];
		r.push(`<span class='slave-name'>${SlaveFullName(slave)}</span>`);
		if (slave.choosesOwnAssignment === 2) {
			r.push(`${App.SlaveAssignment.choosesOwnJob(slave)}`);
		} else {
			r.push(`sees to your pleasure in ${V.masterSuiteName}.`);
		}
		/* Perform facility based rule changes - FIXME - dev/trust living condition changes probably should be in saRules; there's no text reporting these changes here */
		if (V.masterSuiteUpgradeLuxury === 1) {
			slave.rules.living = "luxurious";
			if (slave.devotion <= 95) {
				slave.devotion += 2;
			}
			if (slave.trust < 60) {
				slave.trust++;
			}
		} else if (V.masterSuiteUpgradeLuxury === 2) {
			slave.rules.living = "luxurious";
			if (slave.energy > 90) {
				if (slave.devotion <= 95) {
					slave.devotion += 2;
				}
				if (slave.trust <= 95) {
					slave.trust += 2;
				}
			} else {
				if (slave.devotion <= 60) {
					slave.devotion++;
				}
				if (slave.trust < 60) {
					slave.trust++;
				}
			}
		} else {
			slave.rules.living = "spare";
			if ((slave.devotion <= 20) && (slave.trust >= -20)) {
				slave.devotion -= 2;
				slave.trust -= 5;
			} else if ((slave.devotion <= 60)) {
				slave.devotion += 2;
			} else if ((slave.devotion > 60)) {
				slave.devotion -= 2;
			}
			if (slave.trust < 60) {
				slave.trust++;
			}
		}
		// decoration dev bonus (reported at end)
		if (V.masterSuiteDecoration !== "standard") {
			slave.devotion++;
		}
		return r.join(' ');
	}

	/** Generate text shared by concubine and non-concubine MS slaves
	 * @param {App.Entity.SlaveState} slave
	 * @returns {DocumentFragment}
	 */
	function commonText(slave) {
		const smallFrag = document.createDocumentFragment();
		let r = [];
		const {He, he, His, his, him, himself} = getPronouns(slave);

		if (V.masterSuiteUpgradeLuxury === 2 && msAvg.energy > random(40, 90)) {
			const energy = (Math.ceil(slave.energy / 5) * 7);
			SimpleSexAct.Slave(slave, energy);
			if (canPenetrate(slave)) {
				actX(slave, "penetrative", random(1, 3) * energy);
			}
			if (slave.nipples === "fuckable" && msAvg.dick > 2) {
				actX(slave, "mammary", random(1, 3) * energy);
			}
			if ((slave.trust >= -20) && (slave.devotion > -10) && (slave.fetishStrength <= 95) && slave.fetish !== "mindbroken") {
				const fetishChange = fetishChangeChance(slave);
				if ((msAvg.milk > 2000) && (fetishChange > random(0, 50))) {
					if (slave.fetish === "boobs") {
						if (V.verboseDescriptions === 1) {
							r.push(`${His}`);
						} else {
							r.push(`${slave.slaveName}'s`);
						}
						r.push(`<span class="lightcoral">boob fetish is strengthened</span> by the constant availability of milky nipples for ${him} to play with.`);
						slave.fetishStrength += 4;
					} else {
						if (V.verboseDescriptions === 1) {
							r.push(`${He}`);
						} else {
							r.push(slave.slaveName);
						}
						r.push(`<span class="lightcoral">acquires a boob fetish</span> after spending a lot of time in the fuckpit drinking from ${his} fellow fucktoys' tits.`);
						slave.fetish = "boobs";
						slave.fetishStrength = 65;
					}
				} else if ((msAvg.dick > 3) && (slave.anus > 0) && (fetishChange > random(0, 50))) {
					r.push(`${He}`);
					if (slave.fetish === "buttslut") {
						r.push(`<span class="lightcoral">sinks farther into anal pleasure,</span> since ${he} spends ${his} time in the fuckpit with at least one of the many available cocks up ${his} butt.`);
						slave.fetishStrength += 4;
					} else {
						r.push(`<span class="lightcoral">acquires an anal fetish</span> after helplessly orgasming at the mercy of your many fucktoys eager to shove their big stiff penises up ${his} ass.`);
						slave.fetish = "buttslut";
						slave.fetishStrength = 65;
					}
				} else if ((msAvg.cum > 3) && (fetishChange > random(0, 50))) {
					r.push(`${He}`);
					if (slave.fetish === "cumslut") {
						r.push(`<span class="lightcoral">sinks farther into cum addiction,</span> since ${he} spends ${his} time in the fuckpit eagerly sucking down ejaculate, straight from the many sources.`);
						slave.fetishStrength += 4;
					} else {
						r.push(`<span class="lightcoral">acquires an oral fixation</span> after orally servicing your many fucktoys eager to blow their loads down ${his} throat.`);
						slave.fetish = "cumslut";
						slave.fetishStrength = 65;
					}
				} else if ((msAvg.preg > 10) && (fetishChange > random(0, 50))) {
					r.push(`${He}`);
					if (slave.fetish === "pregnancy") {
						r.push(`<span class="lightcoral">sinks farther into pregnancy obsession,</span> since ${he} never wants for a pregnant girl to make love to.`);
						slave.fetishStrength += 4;
					} else {
						r.push(`<span class="lightcoral">acquires a pregnancy fetish,</span> since many of ${his} sexual partners in the fuckpit are heavily pregnant.`);
						slave.fetish = "pregnancy";
						slave.fetishStrength = 65;
					}
				} else if ((msAvg.dom < -25) && (fetishChange > random(0, 50))) {
					r.push(`${He}`);
					if (slave.fetish === "dom") {
						r.push(`<span class="lightcoral">becomes more dominant,</span> since there are so many subs in the fuckpit who beg ${him} to fuck them hard.`);
						slave.fetishStrength += 4;
					} else {
						r.push(`<span class="lightcoral">becomes sexually dominant</span> after having fun satisfying the many submissive fucktoys in the fuckpit who beg ${him} to top them.`);
						slave.fetish = "dom";
						slave.fetishStrength = 65;
					}
				} else if ((msAvg.dom > 25) && (fetishChange > random(0, 50))) {
					r.push(`${He}`);
					if (slave.fetish === "submissive") {
						r.push(`<span class="lightcoral">becomes even more submissive,</span> since there are so many doms in the fuckpit that ${he}'s often used by more than one at once.`);
						slave.fetishStrength += 4;
					} else {
						r.push(`<span class="lightcoral">becomes sexually submissive</span> after the many dominant slaves in the fuckpit hold ${him} down and use ${him} for their pleasure.`);
						slave.fetish = "submissive";
						slave.fetishStrength = 65;
					}
				} else if ((msAvg.sadism < -25) && (fetishChange > random(0, 50))) {
					r.push(`${He}`);
					if (slave.fetish === "sadist") {
						r.push(`<span class="lightcoral">becomes more sadistic,</span> since there are so many sluts in the fuckpit who will do anything for ${him} if ${he}'ll only spank them.`);
						slave.fetishStrength += 4;
					} else {
						r.push(`<span class="lightcoral">becomes a bit of a sadist</span> after ${he} notices that so many of ${his} fellow fucktoys cum harder if ${he} gives them a good slap.`);
						slave.fetish = "sadist";
						slave.fetishStrength = 65;
					}
				} else if ((msAvg.sadism > 25) && (fetishChange > random(0, 50))) {
					if (slave.fetish === "masochist") {
						if (V.verboseDescriptions === 1) {
							r.push(`${His}`);
						} else {
							r.push(`${slave.slaveName}'s`);
						}
						r.push(`<span class="lightcoral">pain addiction deepens,</span> since the fuckpit is full of ladies happy to fuck ${him} while ${he} screams.`);
						slave.fetishStrength += 4;
					} else {
						if (V.verboseDescriptions === 1) {
							r.push(`${He}`);
						} else {
							r.push(slave.slaveName);
						}
						r.push(`<span class="lightcoral">learns masochism</span> after experiencing many orgasms under the exquisite sexual torture of the sadists in the fuckpit.`);
						slave.fetish = "masochist";
						slave.fetishStrength = 65;
					}
				}
			}
			// FIXME: fuckpit means servant milkers get no milk at all??
			if (slave.lactation > 0) {
				slave.lactationDuration = 2;
				slave.boobs -= slave.boobsMilk;
				slave.boobsMilk = 0;
			}
			if (slave.energy > 40 && slave.energy < 95) {
				r.push(`Being a constant part of the fuckpit orgy <span class="green">greatly heightens ${his} libido.</span>`);
				slave.energy += 2;
			}
			slave.need -= 50;
		}

		if (V.masterSuiteUpgradePregnancy === 1) {
			/* If they're not on fertility drugs and the toggle is active, stick them on (if they can take them). Otherwise take them off. */
			if ((V.masterSuitePregnancyFertilityDrugs === 1) && (slave.drugs !== "fertility drugs") && canGetPregnant(slave)) {
				slave.drugs = "fertility drugs";
			} else if ((V.masterSuiteHyperPregnancy === 1) && (slave.drugs !== "super fertility drugs") && canGetPregnant(slave)) {
				slave.drugs = "super fertility drugs";
			} else if ((((V.masterSuitePregnancyFertilityDrugs === 0) && (slave.drugs === "fertility drugs")) || ((V.masterSuiteHyperPregnancy === 0) && (slave.drugs === "super fertility drugs"))) || (!canGetPregnant(slave) && ["fertility drugs", "super fertility drugs"].includes(slave.drugs))) {
				slave.drugs = "no drugs";
			}
			/* We don't know they're pregnant for a month or so by game logic */
			if (slave.pregKnown === 1) {
				/* FIXME: should these effects have associated text? */
				/* If they're preggo and in the upgraded suite, give them extra devotion. More if they're being given lighter duties. */
				if (slave.devotion <= 100) {
					if (V.masterSuitePregnancySlaveLuxuries === 0) {
						slave.devotion += 2;
					} else {
						slave.devotion += 5;
					}
				}
				/* If they're preggo and in the upgraded suite, give them extra trust. More if they're being given lighter duties. */
				if (slave.trust <= 100) {
					if (V.masterSuitePregnancySlaveLuxuries === 0) {
						slave.trust += 2;
					} else {
						slave.trust += 5;
					}
				}
				/* If they're preggo and in the upgraded suite, give them extra health. More if they're being given lighter duties. */
				if (slave.health.condition < 100) {
					if (V.masterSuitePregnancySlaveLuxuries === 0) {
						improveCondition(slave, 15);
					} else {
						improveCondition(slave, 25);
					}
				}
			}
		}

		$(smallFrag).append(r.join(' '));

		V.i = V.slaveIndices[slave.ID];
		App.Utils.setLocalPronouns(slave); // need this for the includes
		if (V.verboseDescriptions === 1) {
			const msContent = App.UI.DOM.appendNewElement("div", smallFrag, '', "indent");
			$(msContent).append(`${He} ${App.SlaveAssignment.pleaseYou(slave)}`);

			if (V.servantMilkers === 1 && slave.lactation > 0 && slave.fuckdoll === 0 && slave.fetish !== "mindbroken" && canMove(slave) && slave.intelligence+slave.intelligenceImplant >= -90) {
				const milkingResults = App.SlaveAssignment.getMilked(slave, 0.25);
				const milkDiv = App.UI.DOM.appendNewElement("div", smallFrag, `When ${his} breasts begin to feel full and you aren't around, ${he} avails ${himself} to the penthouse milkers and gives ${milkingResults.milk} liters of milk over the week, which is sold for `, "indent");
				App.UI.DOM.appendNewElement("span", milkDiv, `${cashFormat(milkingResults.milkSale)}.`, ["cash", "inc"]);
			}
			const commonContent = App.UI.DOM.appendNewElement("div", smallFrag, '', "indent");
			commonContent.append(App.SlaveAssignment.standardSlaveReport(slave, false));
		} else {
			// discard return values silently
			App.SlaveAssignment.choosesOwnJob(slave);
			App.SlaveAssignment.pleaseYou(slave);
			if (V.servantMilkers === 1 && slave.lactation > 0 && slave.fuckdoll === 0 && slave.fetish !== "mindbroken" && canMove(slave) && slave.intelligence+slave.intelligenceImplant >= -90) {
				App.SlaveAssignment.getMilked(slave, 0.25);
			}
			App.SlaveAssignment.standardSlaveReport(slave, true);
		}
		if (slave.health.condition < 80) {
			if (V.masterSuiteUpgradeLuxury === 1) {
				improveCondition(slave, 20);
			} else {
				improveCondition(slave, 10);
			}
		}

		return smallFrag;
	}

	if (slaves.length > 0) {
		const intro = App.UI.DOM.appendNewElement("p", frag, '', "indent");
		let r = [];
		if (slaves.length > 1) {
			r.push(`<strong>There are ${slaves.length} slaves`);
		} else {
			r.push(`<strong>There is one slave`);
		}
		r.push(`seeing to your pleasure in the master suite.</strong> Such sexual opulence <span class="green">improves</span> your reputation.`);

		if ((V.arcologies[0].FSEgyptianRevivalist > 0) && (slaves.length >= 5)) {
			r.push(`Society <span class="green">approves</span> of your keeping a large number of women. This advances the Egyptian revivalist ideal of multiple concubinage.`);
			FutureSocieties.Change("EgyptianRevivalist", 2);
		}
		if (pregnantSlaves >= 1) {
			r.push(`The suite is supporting the pregnancies of the slaves`);
			if (V.masterSuitePregnancyFertilityDrugs === 1 || V.masterSuiteHyperPregnancy === 1) {
				r.push(`within, and is providing them with fertility drugs`);
				if (V.masterSuitePregnancyFertilitySupplements === 1) {
					r.push(`and supplements to encourage impregnation.`);
				} else {
					r.push(`to encourage impregnation.`);
				}
			} else {
				r.push(`within.`);
			}
			if (V.arcologies[0].FSHedonisticDecadence > 0) {
				r.push(`Society <span class="green">approves</span> of the pampering your pregnant harem receives. This advances the ideal that everyone's desires should be fulfilled.`);
				FutureSocieties.Change("Hedonistic", 1);
			}
		}
		if (slaves.length > 1) {
			r.push(`The level of sexual energy in the suite is`);
			if (V.masterSuiteUpgradeLuxury === 1) {
				if (msAvg.energy > 90) {
					r.push(`intense. When you enter your luxurious retreat, you can set off pent-up orgasms with a touch.`);
				} else if (msAvg.energy > 60) {
					r.push(`high; there is strong competition for your favors whenever you enter your retreat.`);
				} else {
					r.push(`relatively normal; the slaves serve your pleasure before their own.`);
				}
			} else if (V.masterSuiteUpgradeLuxury === 2) {
				if (msAvg.energy > 90) {
					r.push(`intense. Your slaves spend almost all their time in the fuckpit, having sex in a big pile.`);
				} else if (msAvg.energy > 60) {
					r.push(`high; your slaves spend much of their time in the fuckpit, having sex with each other.`);
				} else {
					r.push(`relatively normal; the slaves lounging in the fuckpit get each other off when they feel like it.`);
				}
				if (msAvg.cum > 4) {
					r.push(`Unless it's right after an automated cleaning, everything in the fuckpit is spattered with cum.`);
				}
				if (msAvg.milk > 4000) {
					r.push(`There's so much lactation going on that the lowest level of the fuckpit is a pool of milk.`);
				}
			} else {
				r.push(`relatively normal.`);
			}
		}
		$(intro).append(r.join(' '));
	}

	if (S.Concubine) {
		const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
		if (V.seeImages && V.seeReportImages) {
			App.UI.DOM.appendNewElement("div", slaveEntry, App.Art.SlaveArtElement(S.Concubine, 0, 0), ["imageRef", "tinyImg"]);
		}
		slaveEntry.append(App.EndWeek.favoriteIcon(S.Concubine), " ");
		$(slaveEntry).append(concubineText(), commonText(S.Concubine));
	}

	for (const slave of slaves) {
		const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");
		if (V.seeImages && V.seeReportImages) {
			App.UI.DOM.appendNewElement("div", slaveEntry, App.Art.SlaveArtElement(slave, 0, 0), ["imageRef", "tinyImg"]);
		}
		slaveEntry.append(App.EndWeek.favoriteIcon(slave), " ");
		$(slaveEntry).append(nonConcubineText(slave), commonText(slave));
	}

	if (pregnantSlaves > 0 && V.arcologies[0].FSRestart !== "unset" && V.propOutcome !== 1 && V.eugenicsFullControl !== 1) {
		const eliteEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");
		$(eliteEffects).append(`The Societal Elite know what you are doing with your bedslaves. <span class="red">They do not approve.</span>`);
		V.failedElite += (5 * pregnantSlaves);
	}

	if (V.masterSuiteDecoration !== "standard") {
		const decorationEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");
		$(decorationEffects).append(`${capFirstChar(V.masterSuiteName)}'s ${V.masterSuiteDecoration} atmosphere <span class="hotpink">has a minor impact on your fucktoys.</span>`);
	}

	return frag;
};


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);
	let r = "";
	let trackedCategory = "";

	switch (slave.assignment) {
		case Job.WHORE:
			trackedCategory = "slaveAssignmentWhore";
			break;
		case Job.MADAM:
			trackedCategory = "slaveAssignmentMadam";
			break;
		case Job.BROTHEL:
			trackedCategory = "slaveAssignmentBrothel";
			break;
		case Job.PUBLIC:
			trackedCategory = "slaveAssignmentPublic";
			break;
		case Job.DJ:
			trackedCategory = "slaveAssignmentDj";
			break;
		case Job.CLUB:
			trackedCategory = "slaveAssignmentClub";
			break;
		default:
			trackedCategory = "slaveAssignmentUndefined";
			break;
	}
	r = responseWithTracking(slave, trackedCategory);

	function responseWithTracking(s, 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;
	}

	return r;
};


code:
/**
 * Details week-to-week changes in children in the Nursery
 * @returns {DocumentFragment}
 */
App.Facilities.Nursery.childrenReport = function childrenReport() {
	const frag = new DocumentFragment();

	const Matron = S.Matron;
	const nannies = App.Utils.sortedEmployees(App.Entity.facilities.nursery);
	const NL = App.Entity.facilities.nursery.employeesIDs().size;
	const CL = V.cribs.length;

	const medianNannyIntelligence = NL ? findMedianNannyIntelligence() : null;
	const medianNannyIntelligenceImplant = NL ? findMedianNannyIntelligenceImplant() : null;

	for (const child of V.cribs) {
		const childDiv = App.UI.DOM.appendNewElement("div", frag, '', "child-section");

		childDiv.append(childGrowTime(child));

		if (child.actualAge >= 3) {
			if (Matron) {
				if (Matron.fetish !== "none") {
					childDiv.append(matronFetishEffects(child));
				}

				childDiv.append(matronEducationEffects(child));
				// childDiv.append(matronFitnessEffects(child));
			}

			if (NL > 0) {
				const randomNanny = NL > 1 ? jsRandom(0, nannies.length - 1) : 0;
				const nanny = nannies[randomNanny];

				if (nanny.fetish !== "none") {
					childDiv.append(nannyFetishEffects(child, nanny));
				}

				childDiv.append(nannyEducationEffects(child));
				// childDiv.append(nannyFitnessEffects(child));
			}

			if (multipleChildrenOverTargetAge(V.cribs.findIndex(c => c.ID === child.ID))) {
				childDiv.append(childFriendshipRivalries(child));
			}

			// TODO: rework these entirely
			if (Matron || nannies) {
				childDiv.appendChild(weightRulesEffects(child));
				childDiv.appendChild(musclesRulesEffects(child));
			}
		} else {
			// TODO:
		}
	}

	// MARK: Matron Effects

	function matronFetishEffects(child) {
		const chance = jsRandom(1, 100);

		if ((chance > 90 && child.fetish === "none") || chance > 95) {
			child.fetish = Matron.fetish;

			return `${child.slaveName} has taken a few cues from ${Matron.slaveName}, and ${newChildFetish(child.fetish)}. `;
		}
	}

	function matronEducationEffects(child) {
		// TODO: expand this
		const { he, him, his } = getPronouns(Matron);

		const theChildren = CL > 1 ? `the children` : `${child.slaveName}`;

		if (Matron.intelligence + Matron.intelligenceImplant > 65) {
			child.intelligenceImplant += 3;

			return `${Matron.slaveName} is so intelligent and well-educated that ${he} is able to teach ${theChildren} very effectively, and so ${CL > 1 ? `they gradually grow` : `${child.slaveName} gradually grows`} smarter. `;
		} else if (Matron.intelligenceImplant > 20) {
			child.intelligenceImplant += 2;

			return `${Matron.slaveName}'s education makes up for the fact that ${he} isn't the brightest and allows ${him} to teach ${theChildren} quite effectively, and so ${CL > 1 ? `they grow` : `${child.slaveName} grows`} a bit smarter. `;
		} else if (Matron.intelligence > 50) {
			child.intelligenceImplant += 2;

			return `Though ${Matron.slaveName} has had little to no formal education, ${his} natural brilliance allows ${him} to teach ${theChildren} quite effectively, and so ${CL > 1 ? `they grow` : `${child.slaveName} grows`} a bit smarter. `;
		} else {
			const totalSpan = App.UI.DOM.makeElement("span", `${Matron.slaveName} isn't the brightest and not well educated, `);
			const damageSpan = App.UI.DOM.makeElement("span", `damaging the amount of real education ${theChildren} receive. `, "red");

			child.intelligenceImplant--;

			totalSpan.appendChild(damageSpan);

			return totalSpan;
		}
	}

	// function matronFitnessEffects(child) {
	// 	// TODO:
	// 	return;
	// }

	// MARK: Nanny Effects

	function nannyFetishEffects(child, slave) {
		const { he } = getPronouns(child);
		const chance = jsRandom(1, 100);

		if (chance > 85) {
			if (child.fetish === "none") {
				child.fetish = slave.fetish;

				return `${slave.slaveName} has left quite an impression on ${child.slaveName}, and ${he} ${newChildFetish(child.fetish)}. `;
			} else {
				if (chance > 90) {
					child.fetish = slave.fetish;

					return `${child.slaveName} seems to have taken to ${slave.slaveName}'s example, and ${newChildFetish(child.fetish)}. `;
				}
			}
		}
	}

	function nannyEducationEffects(child) {
		// TODO: redo this entire section
		// TODO: expand this
		const firstNanny = nannies[0];
		const theNanniesAre = NL > 1 ? `The nannies are mostly` : `${firstNanny.slaveName} is`;
		const theChildren = CL > 1 ? `the children` : child.slaveName;

		if (medianNannyIntelligence + medianNannyIntelligenceImplant > 65) {
			child.intelligenceImplant += 3;

			return `${theNanniesAre} very intelligent and well educated and are able to teach ${theChildren} very effectively. `;
		} else if (medianNannyIntelligence > 50) {
			child.intelligenceImplant += 2;

			return `${theNanniesAre} very intelligent and able to teach ${theChildren} quite effectively. `;
		} else if (medianNannyIntelligenceImplant > 25) {
			child.intelligenceImplant += 2;

			return `${theNanniesAre} very well educated and able to teach ${theChildren} quite effectively. `;
		} else if (medianNannyIntelligenceImplant > 15) {
			child.intelligenceImplant++;

			return `${theNanniesAre} well educated and able to teach ${theChildren} fairly effectively. `;
		}
	}

	// function nannyFitnessEffects(child) {
	// 	// TODO:
	// 	return;
	// }

	// MARK: Nursery Rules Effects

	function weightRulesEffects(child) {
		// TODO: redo this entire section
		// TODO: double check these classes, make sure they make sense
		const span = document.createElement("span");
		const {he, He, His} = getPronouns(child);

		if (V.nurseryWeight) {
			const firstNanny = NL > 0 ? nannies[0] : null;
			const caretaker = Matron ? Matron.slaveName : NL > 1 ? `A nanny` : firstNanny.slaveName;

			if (V.nurseryWeightSetting === 1) {
				const weightSpan = App.UI.DOM.makeElement("span", 'rapid weight gain.', ["health", "dec"]);

				if (child.weight < 200) {
					child.weight += 5;
				}

				span.append(`${He} is being fed an excessive amount of food, causing`, weightSpan);
			} else if (V.nurseryWeightSetting === 2) {
				const weightSpan = App.UI.DOM.makeElement("span", `decreases the amount of food ${he} eats. `, "improvement");

				if (child.weight > 10) {
					child.weight--;

					span.append(`${caretaker} notices ${he} is overweight and `, weightSpan);
				} else if (child.weight <= -10) {
					const weightSpan = App.UI.DOM.makeElement("span", `increases the amount of food ${he} eats. `, "improvement");

					child.weight++;

					span.append(`${caretaker} notices ${he} is underweight and `, weightSpan);
				} else {
					const weightSpan = App.UI.DOM.makeElement("span", 'currently a healthy weight;', ["change", "positive"]);

					span.append(`${He} is `, weightSpan, ` efforts will be made to maintain it. `);
				}
			} else if (V.nurseryWeightSetting === 0) {
				if (child.weight > -20) {
					const weightSpan = App.UI.DOM.makeElement("span", 'quickly sheds its gained weight.', ["health", "dec"]);

					child.weight -= 40;

					span.append(`${His} developing body `, weightSpan);
				}
			}
		} else {
			if (child.weight > -20) {
				const weightSpan = App.UI.DOM.makeElement("span", 'quickly sheds its gained weight. ', ["health", "dec"]);

				child.weight -= 40;

				span.append(`${His} developing body `, weightSpan);
			}
		}

		return span;
	}

	function musclesRulesEffects(child) {
		const div = document.createElement("div");

		// TODO: rewrite these
		// FIXME: this entire section needs a rewrite - numbers and text don't line up at all
		if (V.nurseryMuscles) {
			const firstNanny = NL > 0 ? nannies[0] : null;
			const caretaker = Matron ? Matron.slaveName : NL > 1 ? `A nanny` : firstNanny.slaveName;
			const { His, He, he } = getPronouns(child);

			const muscleSpan = App.UI.DOM.makeElement("div", 'rapid muscle development.', "improvement");

			div.append(`${He} is being worked out as often as possible, resulting in `, muscleSpan);

			if (V.nurseryMusclesSetting === 2) {
				const muscleSpan = App.UI.DOM.makeElement("span", `decreases the amount of exercise ${he} receives. `, "improvement");

				if (child.muscles > 100) {
					child.muscles -= 5;
				}

				div.append(`${caretaker} notices ${he} is overly muscular and `, muscleSpan);
			} else if (V.nurseryMusclesSetting === 1) {
				if (child.muscles < -10) {
					const muscleSpan = App.UI.DOM.makeElement("span", `increases the amount of exercise ${he} receives. `, "improvement");

					child.muscles--;

					div.append(`${caretaker} notices ${he} is weak and `, muscleSpan);
				} else if (child.muscles > 10) {
					const muscleSpan = App.UI.DOM.makeElement("span", 'a healthy musculature;', ["change", "positive"]);

					child.muscles++;

					div.append(`${He} has `, muscleSpan, ` efforts will be made to maintain it. `);
				} else {
					const muscleSpan = App.UI.DOM.makeElement("span", 'quickly loses its gained muscle.', ["health", "dec"]);

					div.append(`${His} developing body `, muscleSpan);
				}
			} else if (V.nurseryMusclesSetting === 0) {
				const muscleSpan = App.UI.DOM.makeElement("span", 'quickly loses its gained muscle.', ["health", "dec"]);

				if (child.muscles > 100) {
					child.muscles -= 40;
					div.append(`${His} developing body `, muscleSpan);
				}
			}
		}

		return div;
	}

	// MARK: Miscellaneous Functions

	function childFriendshipRivalries(child) {
		const cribsCopy = Array.from(V.cribs);

		cribsCopy.splice(V.cribs.findIndex(c => c.ID === child.ID));

		for (const target of cribsCopy) {
			const becomeFriends = () => `${child.slaveName} and ${target.slaveName} have realized that they have more in common that they originally thought, and have become friends. `;
			const becomeRivals = () => `${child.slaveName} and ${target.slaveName} have more differences between them than they could put aside and have become rivals. `;
			const haveSameFetish = () => child.fetish === target.fetish && child.fetish !== "none";
			const haveSameBehavioralQuirk = () => child.behavioralQuirk && child.behavioralQuirk === target.behavioralQuirk && child.behavioralQuirk !== "none";
			const haveSameSexualQuirk = () => child.sexualQuirk && child.sexualQuirk === target.sexualQuirk && child.sexualQuirk !== "none";

			const div = document.createElement("div");

			const { his } = getPronouns(target);
			const chance = jsRandom(1, 100);

			let friend = 0;
			let rival = 0;

			if (target.actualAge >= 3) {
				if (haveSameFetish()) {
					div.append(`${sameFetish(child, target)}, a fact over which they bond. `);

					friend++;
				}

				if (haveSameBehavioralQuirk()) {	// TODO:
					div.append(`Since ${sameBehavioralQuirk(child, target)}, they learn to get along a bit better. `);

					friend++;
				}

				if (haveSameSexualQuirk()) {
					div.append(`Because ${sameSexualQuirk(child, target, haveSameBehavioralQuirk())}, the two grow a bit closer. `);

					friend++;
				}

				if (target.fetish === "sadist" || target.fetish === "dom") {
					div.append(`${target.slaveName} is a ${target.fetish}, and ${child.slaveName} is often ${his} target, which ${child.slaveName} doesn't particularly like. `);

					rival++;
				} else if (child.fetish === "sadist" || child.fetish === "dom") {
					div.append(`${child.slaveName} is a ${child.fetish}, and ${target.slaveName} is often ${his} target, which ${target.slaveName} doesn't particularly like. `);

					rival++;
				}

				if (areRelated(child, target) || areCousins(child, target)) {
					if (areRelated(child, target)) {
						if (rival) {
							div.append(`${child.slaveName} and ${target.slaveName} are siblings, and find it difficult to really stay mad at each other, and they make up their differences somewhat. `);

							friend += 2;
						} else {
							div.append(`${child.slaveName} and ${target.slaveName} are siblings, a fact that draws them closer together. `);

							friend += 2;
						}
					} else {
						if (rival) {
							div.append(`${child.slaveName} and ${target.slaveName} are cousins, and find it difficult to really stay mad at each other, and they make up their differences somewhat. `);

							friend++;
						} else {
							div.append(`${child.slaveName} and ${target.slaveName} are cousins, a fact that draws them closer together. `);

							friend++;
						}
					}
				}

				if (friend) {
					if (rival) {
						if (friend > rival && child.relationshipTarget !== target.ID) {
							if (chance > 75) {
								div.append(becomeFriends());

								child.relationship = 1;
								child.relationshipTarget = target.ID;

								target.relationship = 1;
								target.relationshipTarget = child.ID;
							}
						}
					} else {
						if (chance > 60) {
							div.append(becomeRivals());

							child.relationship = 1;
							child.relationshipTarget = target.ID;

							target.relationship = 1;
							target.relationshipTarget = child.ID;
						}
					}
				}

				if (rival) {
					if (friend) {
						if (rival > friend) {
							if (chance > 75) {
								div.append(becomeRivals());
							}
						}
					} else {
						if (chance > 60) {
							div.append(becomeFriends());
						}
					}
				}
			}

			return div;
		}

		function sameFetish(child, target) {
			switch (child.fetish) {
				case "submissive":
					return `${child.slaveName} and ${target.slaveName} are both sexually submissive`;
				case "cumslut":
					return `Neither ${child.slaveName} nor ${target.slaveName} can get enough cum`;
				case "humiliation":
					return `Both ${child.slaveName} and ${target.slaveName} have a fetish for humiliation`;
				case "buttslut":
					return `Neither ${child.slaveName} nor ${target.slaveName} can get enough assplay`;
				case "boobs":
					return `${child.slaveName} and ${target.slaveName} both love breastplay`;
				case "sadist":
					return `Both ${child.slaveName} are ${target.slaveName} are sadists`;
				case "masochist":
					return `${child.slaveName} and ${target.slaveName} are both masochists`;
				case "dom":
					return `Both ${child.slaveName} and ${target.slaveName} are sexually dominant`;
				case "pregnancy":
					return `The idea of pregnancy titillates both ${child.slaveName} and ${target.slaveName}`;
				default:
					throw `Unexpected value ${child.fetish} in sameFetish(). Please report this.`;
			}
		}

		function sameBehavioralQuirk(child, target) {
			switch (child.behavioralQuirk) {
				case "confident":
					return `${child.slaveName} and ${target.slaveName} are both naturally confident`;
				case "cutting":
					return `both ${child.slaveName} and ${target.slaveName} have a cutting wit about them`;
				case "funny":
					return `${child.slaveName} and ${target.slaveName} can both make the other laugh`;
				case "fitness":
					return `${child.slaveName} and ${target.slaveName} both love to try to stay in shape`;
				case "adores women":
					return `${child.slaveName} and ${target.slaveName} both adore women`;
				case "adores men":
					return `both ${child.slaveName} are ${target.slaveName} adore men`;
				case "insecure":
					return `${child.slaveName} and ${target.slaveName} are both equally insecure`;
				case "sinful":
					return `both ${child.slaveName} and ${target.slaveName} love breaking cultural and religious mores`;
				case "advocate":
					return `${child.slaveName} and ${target.slaveName} can both make a strong case for slavery`;
				default:
					throw `Unexpected value ${child.behavioralQuirk} in sameBehavioralQuirk(). Please report this.`;
			}
		}

		// TODO: incorporate minimumSlaveAge
		function sameSexualQuirk(child, target, sameQuirk = false) {
			switch (child.sexualQuirk) {
				case "gagfuck queen":
					return `${sameQuirk ? `the two also` : `${child.slaveName} and ${target.slaveName} both`} love having their little throats fucked`;
				case "painal queen":
					return `${sameQuirk ? `neither` : `neither ${child.slaveName} nor ${target.slaveName}`} can get enough painal`;
				case "strugglefuck queen":
					return `${sameQuirk ? `the two also` : `${child.slaveName} and ${target.slaveName} both`} love to put up a struggle during sex`;
				case "tease":
					return `${sameQuirk ? `the two are also both teases` : `${child.slaveName} and ${target.slaveName} are both teases`}`;
				case "romantic":
					return `${sameQuirk ? `the two also` : `${child.slaveName} and ${target.slaveName} both`} see the world from under a romantic lens`;
				case "perverted":
					return `${sameQuirk ? `the two are also` : `${child.slaveName} and ${target.slaveName} are both`} big-time perverts`;
				case "caring":
					return `${sameQuirk ? `the two also` : `${child.slaveName} and ${target.slaveName} both`} care about their partners`;
				case "unflinching":
					return `${sameQuirk ? `the two can also` : `${child.slaveName} and ${target.slaveName} can both`} take whatever their partner might throw at them `;
				case "size queen":
					return `${sameQuirk ? `the two also` : `${child.slaveName} and ${target.slaveName} both`} have a love for huge cock`;
				default:
					throw `Unexpected value ${child.fetish} in sameSexualQuirk(). Please report this.`;
			}
		}
	}

	function newChildFetish(fetish = "none") {
		switch (fetish) {
			case "submissive":
				return `is now sexually submissive`;
			case "cumslut":
				return `is now a cumslut`;
			case "humiliation":
				return `now has a fetish for humiliation`;
			case "buttslut":
				return `is now a buttslut`;
			case "boobs":
				return `now has a fetish for all things breast-related`;
			case "sadist":
				return `now gets off on causing pain`;
			case "masochist":
				return `now gets off on pain`;
			case "dom":
				return `is now very sexually dominant`;
			case "pregnancy":
				return `has developed a fascination for all things pregnancy-related`;
			default:
				throw `<span class="error">Unexpected fetish value of "${fetish}" in newChildFetish(). Please report this.</span>`;
		}
	}

	function childGrowTime(child) {
		const nameSpan = App.UI.DOM.makeElement("span", child.slaveName, "pink");
		const limeSpan = App.UI.DOM.makeElement("span", 'ready for release.', "lime");
		const mainSpan = document.createElement("span");

		const {He} = getPronouns(child);

		if (child.growTime > 0) {
			mainSpan.append(nameSpan, ` is growing steadily. ${He} will be ready for release in about ${years(child.growTime)}. `);
		} else {
			mainSpan.append(nameSpan, ' is ', limeSpan, ` ${He} will be removed from ${V.nurseryName} upon your approach. `);
		}

		return mainSpan;
	}

	function findMedianNannyIntelligence() {
		return median(nannies.map(n => n.intelligence));
	}

	function findMedianNannyIntelligenceImplant() {
		return median(nannies.map(n => n.intelligenceImplant));
	}

	/**
	 * Checks if there are more than one children over the target age in the Nursery
	 * @param {number} index
	 * @param {number} [age=3]
	 */
	function multipleChildrenOverTargetAge(index, age = 3) {
		const cribsCopy = Array.from(V.cribs);

		cribsCopy.splice(index, 1);

		return V.cribs.length > 1 && cribsCopy.some(c => c.actualAge >= age);
	}

	return frag;
};


code:
/**
 * Creates a full report of the Nursery
 * @returns {DocumentFragment}
 */
App.Facilities.Nursery.nurseryReport = function nurseryReport() {
	const frag = new DocumentFragment();

	const slaves = App.Utils.sortedEmployees(App.Entity.facilities.nursery);
	const devBonus = (V.nurseryDecoration !== "standard") ? 1 : 0;
	const arcology = V.arcologies[0];

	let matronBonus = 0;

	V.flSex = App.EndWeek.getFLSex(App.Entity.facilities.nursery); // FIXME: should be local, passed as a parameter to saRules

	function matronChanges() {
		if (S.Matron) {
			S.Matron.devotion += devBonus;

			if (S.Matron.health.condition < -80) {
				improveCondition(S.Matron, 20);
			} else if (S.Matron.health.condition < -40) {
				improveCondition(S.Matron, 15);
			} else if (S.Matron.health.condition < 0) {
				improveCondition(S.Matron, 10);
			} else if (S.Matron.health.condition < 90) {
				improveCondition(S.Matron, 7);
			}

			if (S.Matron.devotion <= 60) {
				S.Matron.devotion++;
			}

			if (S.Matron.trust < 60) {
				S.Matron.trust++;
			}

			if (S.Matron.rules.living !== "luxurious") {
				S.Matron.rules.living = "luxurious";
			}
			if (S.Matron.rules.rest !== "restrictive") {
				S.Matron.rules.rest = "restrictive";
			}
		}
	}

	function matronText() {
		if (S.Matron) {
			const {He, he, His, his, him} = getPronouns(S.Matron);

			let r = [];

			r.push(`${SlaveFullName(S.Matron)} is serving as your Matron.`);

			if (S.Matron.relationship === -3 && S.Matron.devotion > 50) {
				r.push(`${He} does ${his} best to ${V.nurseryChildren ?
					`properly raise and look after the children in ${V.nurseryName}` :
					`look after ${V.nurseryName} and keep it tidy and running smoothly`}.`);
			}

			if (S.Matron.health.condition < 10) {
				r.push(`${He} does ${his} best to take good care of ${V.nurseryChildren ? `the children` : `${V.nurseryName}`}, but ${his} poor health limits ${his} ability to do so.`);
			} else if (S.Matron.health.condition < 80) {
				r.push(`${His} good health allows ${him} to keep up with the demands of ${V.nurseryName}${V.nurseryNannies ? `and work the nannies hard` : ``}.`);

				matronBonus += V.nurseryNannies ? 50 : 0;
			} else {
				r.push(`${His} perfect health allows ${him} to really stay on top of things in ${V.nurseryName}${V.nurseryNannies ? ` and really drive the nannies hard.` : ``}`);

				matronBonus += V.nurseryNannies ? 75 : 0;
			}

			if (setup.matronCareers.includes(S.Matron.career)) {
				r.push(`${He} has experience with looking after children from ${his} life before ${he} was a slave.`);

				matronBonus += 25;
			} else if (S.Matron.skill.matron >= V.masteredXP) {
				r.push(`${He} has applicable experience with taking care of children from working for you.`);

				matronBonus += 25;
			} else {
				S.Matron.skill.matron += jsRandom(1, Math.ceil((
					S.Matron.intelligence + S.Matron.intelligenceImplant
				) / 15) + 8);
			}

			if (S.Matron.actualAge > 35) {
				r.push(`${His} age and experience make ${him} more effective.`);

				matronBonus += 25;
			} else if (!V.AgePenalty) {
				matronBonus += 25;
			}

			if (S.Matron.intelligence + S.Matron.intelligenceImplant > 15) {
				r.push(`${He}'s intelligent enough that ${he} is more effectively able to take care of ${V.nurseryName}${V.nurseryChildren ? ` and its children` : ``}.`);

				matronBonus += S.Matron.intelligence + S.Matron.intelligenceImplant;
			}

			if (V.nurseryChildren < V.nursery) {
				let seed = jsRandom(1, 10) + ((V.nursery - V.nurseryChildren) * (jsRandom(150, 170) + (matronBonus * 10)));
				cashX(seed, "nursery", S.Matron);

				r.push(`
Since ${he} doesn't have enough children to occupy all ${his} time, ${V.nurseryName} takes in citizens' children on a contract basis and ${he} cares for them too, earning ${cashFormat(seed)}.
`);
			}

			if (arcology.FSRepopulationFocus > 0 && V.nurseryChildren > 0) {
				r.push(`Society <span class='green'>loves</span> the way you are raising more children for ${arcology.name}. `);
				FutureSocieties.Change("Repopulationist", 2);
			}
			return r.join(' ');
		}
	}

	const matronEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");

	matronChanges();
	$(matronEffects).append(matronText());

	if (slaves) {
		const intro = App.UI.DOM.appendNewElement("p", frag, '', "indent");

		let r = [];

		r.push(`${slaves.length > 1 ? `There are ${slaves.length} slaves` : `There is one slave`} working in ${V.nurseryName}.</strong>`);

		if (arcology.FSRepopulationFocus > 0 && V.nurseryChildren > 0) {
			r.push(`Society <span class="green">approves</span> of your bringing more children into this world.`);
		} else if (arcology.FSGenderFundamentalist > 0) {
			r.push(`Society <span class="green">approves</span> of your assigning slaves to a traditionally feminine role.`);
		}

		$(intro).append(r.join(' '));
	}

	if (S.Matron) {
		/** @type {App.Entity.SlaveState} */
		const slave = S.Matron;

		V.i = V.slaveIndices[slave.ID];
		App.Utils.setLocalPronouns(slave);	// needed for "include"s

		if (V.showEWD !== 0) {
			const matronEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");

			if (V.seeImages && V.seeReportImages) {
				App.UI.DOM.appendNewElement("div", matronEntry, App.Art.SlaveArtElement(slave, 0, 0), ["imageRef", "tinyImg"]);
			}

			matronEntry.append(App.EndWeek.favoriteIcon(slave), " ");
			$(matronEntry).append(`<span class="slave-name">${SlaveFullName(slave)}</span> is serving as your Matron.`);
			$(matronEntry).append(App.SlaveAssignment.standardSlaveReport(slave, false));
		} else {
			App.SlaveAssignment.standardSlaveReport(slave, true);
		}
	}

	// FIXME: check these numbers over to make sure they make sense
	for (const slave of slaves) {
		V.i = V.slaveIndices[slave.ID];

		slave.devotion += devBonus;

		if (slave.devotion <= 20 && slave.trust >= -20) {
			slave.devotion -= 5;
			slave.trust -= 5;
		} else if (slave.devotion <= 10) {
			slave.devotion += 2;
		} else if (slave.devotion >= 80) {
			slave.devotion -= 2;
		}

		if (slave.trust < -20) {
			slave.trust += 3;
		} else if (slave.trust < -50) {
			slave.trust += 2;
		} else if (slave.trust < -30) {
			slave.trust += 1;
		}

		if (slave.health.condition < -80) {
			improveCondition(slave, 20);
		} else if (slave.health.condition < -40) {
			improveCondition(slave, 10);
		} else if (slave.health.condition < 0) {
			improveCondition(slave, 7);
		} else if (slave.health.condition < 90) {
			improveCondition(slave, 3);
		}

		// TODO: add more cases
		switch (V.nurseryDecoration) {
			case "Repopulationist":
				slave.rules.living = "luxurious";
				break;
			case "Degradationist":
				slave.rules.living = "spare";
				break;
			default:
				slave.rules.living = "normal";
				break;
		}

		App.Utils.setLocalPronouns(slave);	// needed for "include"s

		if (V.showEWD) {
			const {He} = getPronouns(slave);
			const slaveEntry = App.UI.DOM.appendNewElement("div", frag, '', "slave-report");

			if (V.seeImages && V.seeReportImages) {
				App.UI.DOM.appendNewElement("div", slaveEntry, App.Art.SlaveArtElement(slave, 0, 0), ["imageRef", "tinyImg"]);
			}

			slaveEntry.append(App.EndWeek.favoriteIcon(slave), " ");
			$(slaveEntry).append(`<span class="slave-name">${SlaveFullName(slave)}</span> `);

			if (slave.choosesOwnAssignment === 2) {
				$(slaveEntry).append(App.SlaveAssignment.choosesOwnJob(slave));
			} else {
				$(slaveEntry).append(`is working out of ${V.nurseryName}.`);
			}

			const nannyContent = App.UI.DOM.appendNewElement("div", slaveEntry, '', "indent");

			$(nannyContent).append(`${He} ${App.SlaveAssignment.nanny(slave, matronBonus)}`);	// FIXME: nanny() takes one argument

			$(slaveEntry).append(App.SlaveAssignment.standardSlaveReport(slave, false));
		} else {	// silently discard return values
			App.SlaveAssignment.nanny(slave, matronBonus);	// FIXME: nanny() takes one argument
			App.SlaveAssignment.standardSlaveReport(slave, true);
		}
	}

	if (V.nurseryDecoration !== "standard") {
		const decorationEffects = App.UI.DOM.appendNewElement("p", frag, '', "indent");

		$(decorationEffects).append(`${capFirstChar(V.nurseryName)}'s ${V.nurseryDecoration} atmosphere <span class="devotion inc">has a minor impact on your servants.</span>`);
	}

	return frag;
};