code:
/**
 * @param {ParentNode} renderContainer
 */
App.EndWeek.computeSexualServicesModel = function(renderContainer) {
	const arcology = V.arcologies[0];

	/* Sexual services demand per class */
	/* We can add milk etc. to this as well, though this is a good that can be traded beyond the arcology and also needs its own market much like the slave market. TODO: */
	/* In the default scenario these numbers indicate the amount of money each individual citizen of a particular class is looking to spend on sex (and milk) every week
	Depending on the conditions they may derive more or less 'utility' out of their credits spent
	i.e. a highly paternalist arcology with little choice for its lower class but Fuckdolls may still put money into them but not get the same satisfaction out of it*/
	/* Low rent increases demand/available money for sexual services, high rent decreases it */
	if (V.brothelBoost.selected > 0 && V.rep < V.brothelBoost.selected * 500 + 2000) {
		V.brothelBoost.eligible = Math.trunc((V.rep - 2000) / 500);
		if (V.brothelBoost.eligible < 0) {
			V.brothelBoost.eligible = 0;
		}
	} else {
		V.brothelBoost.eligible = V.brothelBoost.selected;
	}
	repX(forceNeg(50 * V.brothelBoost.eligible), "brothel");

	let lowerClassSexDemand = Math.trunc(V.lowerClass * V.whoreBudget.lowerClass) * 2;
	let lowerClassSexDemandRef = Math.max(lowerClassSexDemand, 1);
	let visitorsSexDemand = Math.trunc(V.visitors) * 40;
	let middleClassSexDemand = Math.trunc(V.middleClass * V.whoreBudget.middleClass + visitorsSexDemand * 0.5) * 2;
	let middleClassSexDemandRef = Math.max(middleClassSexDemand, 1);
	let upperClassSexDemand = Math.trunc(V.upperClass * V.whoreBudget.upperClass + visitorsSexDemand * 0.5) * 2;
	let upperClassSexDemandRef = Math.max(upperClassSexDemand, 1);
	let topClassSexDemand = Math.trunc(V.topClass * V.whoreBudget.topClass) * 2;
	let topClassSexDemandRef = Math.max(topClassSexDemand, 1);
	let arcadeSupply = {lowerClass: 0, middleClass: 0, upperClass: 0};
	let clubSupply = {lowerClass: 0, middleClass: 0};

	App.EndWeek.saVars.whorePriceAdjustment = {
		lowerClass: 0, middleClass: 0, upperClass: 0, topClass: 0
	};
	V.NPCMarketShare = {
		lowerClass: 0, middleClass: 0, upperClass: 0, topClass: 0
	};
	V.sexDemandResult = {
		lowerClass: 0, middleClass: 0, upperClass: 0, topClass: 0
	};
	App.EndWeek.saVars.slaveJobValues = slaveJobValues(lowerClassSexDemandRef, middleClassSexDemandRef, upperClassSexDemandRef, topClassSexDemandRef);
	const sjv = App.EndWeek.saVars.slaveJobValues;

	let lowerClassArcadeSexDemand = 0;
	let middleClassArcadeSexDemand = 0;
	let upperClassArcadeSexDemand = 0;
	let arcadeDemand = 0;
	let arcadeDemandDeg = 0;
	// Arcade Specific Demand for Degradationists to give it higher priority
	if (arcology.FSDegradationist !== "unset" && arcology.FSDegradationist > 0) {
		lowerClassArcadeSexDemand = Math.trunc(lowerClassSexDemand * arcology.FSDegradationist * 0.0015);
		middleClassArcadeSexDemand = Math.trunc(middleClassSexDemand * arcology.FSDegradationist * 0.0002);
		upperClassArcadeSexDemand = Math.trunc(upperClassSexDemand * arcology.FSDegradationist * 0.000025);
		arcadeDemandDeg = lowerClassArcadeSexDemand + middleClassArcadeSexDemand + upperClassArcadeSexDemand;
		if (arcology.FSDegradationistLaw === 1) {
			arcadeDemandDeg += V.ASlaves * 3;
		}
		if (sjv.arcade < arcadeDemandDeg) {
			if (arcadeDemandDeg > 20000 || arcology.FSDegradationist > 50) {
				const degradationistPenalty = ((arcadeDemandDeg - sjv.arcade) / arcadeDemandDeg);
				arcology.FSDegradationist -= Math.trunc(5 * degradationistPenalty);
				repX(forceNeg(100 * degradationistPenalty), "futureSocieties");
				V.arcadeDemandDegResult = degradationistPenalty > 0.5 ? 1 : 2;
			} else {
				V.arcadeDemandDegResult = 3;
			}
			arcadeSupply.lowerClass += Math.trunc(1.15 * sjv.arcade * (lowerClassArcadeSexDemand / arcadeDemandDeg));
			lowerClassSexDemand -= arcadeSupply.lowerClass;
			arcadeSupply.middleClass += Math.trunc(1.15 * sjv.arcade * (middleClassArcadeSexDemand / arcadeDemandDeg));
			middleClassSexDemand -= arcadeSupply.middleClass;
			arcadeSupply.upperClass += Math.trunc(1.15 * sjv.arcade * (upperClassArcadeSexDemand / arcadeDemandDeg));
			upperClassSexDemand -= arcadeSupply.upperClass; // There's a 15% satisfaction bonus from getting release in a societally approved way
		} else {
			if (sjv.arcade >= arcadeDemandDeg * 1.5) {
				arcology.FSDegradationist += 2;
				V.arcadeDemandDegResult = 4;
				repX(500, "futureSocieties");
			} else {
				V.arcadeDemandDegResult = 5;
			}
			arcadeSupply.lowerClass += Math.trunc(1.15 * lowerClassArcadeSexDemand);
			lowerClassSexDemand -= arcadeSupply.lowerClass;
			arcadeSupply.middleClass += Math.trunc(1.15 * middleClassArcadeSexDemand);
			middleClassSexDemand -= arcadeSupply.middleClass;
			arcadeSupply.upperClass += Math.trunc(1.15 * upperClassArcadeSexDemand);
			upperClassSexDemand -= arcadeSupply.upperClass;
		}
	}

	// Public slut sex supply. Top and upper class won't partake
	let clubDemand = lowerClassSexDemand + middleClassSexDemand;
	let lowerClassClubRatio = lowerClassSexDemand / clubDemand;
	let middleClassClubRatio = middleClassSexDemand / clubDemand;

	if (sjv.club * sjv.clubSP < clubDemand) {
		lowerClassSexDemand -= Math.trunc(sjv.club * sjv.clubSP * lowerClassClubRatio);
		middleClassSexDemand -= Math.trunc(sjv.club * sjv.clubSP * middleClassClubRatio);
	} else {
		lowerClassSexDemand = 0;
		middleClassSexDemand = 0;
	}

	clubSupply.lowerClass = Math.trunc(sjv.club * sjv.clubSP * lowerClassClubRatio);
	clubSupply.middleClass = Math.trunc(sjv.club * sjv.clubSP * middleClassClubRatio);

	// Brothel or street whore sex supply
	if (lowerClassSexDemand < sjv.brothel.lowerClass) {
		App.EndWeek.saVars.whorePriceAdjustment.lowerClass = Math.max(Math.pow(lowerClassSexDemand / (sjv.brothel.lowerClass + V.NPCSexSupply.lowerClass), 1.513), 0.3);
		lowerClassSexDemand = 0; // This accounts for people having too much choice and getting more picky how they spend their money
	} else {
		App.EndWeek.saVars.whorePriceAdjustment.lowerClass = Math.pow(lowerClassSexDemand / (sjv.brothel.lowerClass + V.NPCSexSupply.lowerClass), 0.5);
		lowerClassSexDemand -= sjv.brothel.lowerClass; // People are willing to pay more for a scarce good, but within reason
	}
	if (middleClassSexDemand < sjv.brothel.middleClass) {
		App.EndWeek.saVars.whorePriceAdjustment.middleClass = Math.max(Math.pow((middleClassSexDemand * 1.1) / (sjv.brothel.middleClass + V.NPCSexSupply.middleClass), 1.513), 0.33);
		middleClassSexDemand = 0;
	} else {
		App.EndWeek.saVars.whorePriceAdjustment.middleClass = Math.pow((middleClassSexDemand * 1.1) / (sjv.brothel.middleClass + V.NPCSexSupply.middleClass), 0.5);
		middleClassSexDemand -= sjv.brothel.middleClass;
	}
	if (upperClassSexDemand < sjv.brothel.upperClass) {
		App.EndWeek.saVars.whorePriceAdjustment.upperClass = Math.max(Math.pow((upperClassSexDemand * 1.21) / (sjv.brothel.upperClass + V.NPCSexSupply.upperClass), 1.513), 0.363);
		upperClassSexDemand = 0;
	} else {
		App.EndWeek.saVars.whorePriceAdjustment.upperClass = Math.pow((upperClassSexDemand * 1.21) / (sjv.brothel.upperClass + V.NPCSexSupply.upperClass), 0.5);
		upperClassSexDemand -= sjv.brothel.upperClass;
	}
	if (topClassSexDemand < sjv.brothel.topClass) {
		App.EndWeek.saVars.whorePriceAdjustment.topClass = Math.max(Math.pow((topClassSexDemand * 1.331) / (sjv.brothel.topClass + V.NPCSexSupply.topClass), 1.513), 0.3993);
		topClassSexDemand = 0;
	} else {
		App.EndWeek.saVars.whorePriceAdjustment.topClass = Math.pow((topClassSexDemand * 1.331) / (sjv.brothel.topClass + V.NPCSexSupply.topClass), 0.5);
		topClassSexDemand -= sjv.brothel.topClass;
	}

	// Price for sex in the arcade or at a glory hole
	if (arcology.FSPaternalist !== "unset" && arcology.FSPaternalist > 0) {
		arcadeDemand = Math.max((arcadeDemandDeg + lowerClassSexDemand) * (1 - arcology.FSPaternalist / 50), 0); // Paternalists sap demand for the arcade
	} else {
		arcadeDemand = arcadeDemandDeg + lowerClassSexDemand;
	}
	if (sjv.arcade + V.NPCSexSupply.lowerClass > 0) {
		V.arcadePrice = Math.clamp(Math.pow((arcadeDemand / (sjv.arcade + V.NPCSexSupply.lowerClass)), 0.5), 0.5, 3); // This calculates the price charged per fuck
	} else {
		V.arcadePrice = 0.5; // minimum price no matter what
	}

	// Arcade usage beyond degradationist demand
	if (sjv.arcade > arcadeDemandDeg) {
		sjv.arcade -= arcadeDemandDeg;
	} else {
		sjv.arcade = 0;
	}
	if (sjv.arcade > lowerClassSexDemand) {
		lowerClassSexDemand = 0;
	} else {
		lowerClassSexDemand -= sjv.arcade;
	}
	arcadeSupply.lowerClass += sjv.arcade;

	// NPC sex supply
	V.NPCSexSupply = NPCSexSupply(lowerClassSexDemand, lowerClassSexDemandRef, middleClassSexDemand, middleClassSexDemandRef, upperClassSexDemand, upperClassSexDemandRef, topClassSexDemand, topClassSexDemandRef);
	V.NPCMarketShare.lowerClass = Math.trunc((V.NPCSexSupply.lowerClass * 1000) / lowerClassSexDemandRef);
	V.NPCMarketShare.middleClass = Math.trunc((V.NPCSexSupply.middleClass * 1000) / middleClassSexDemandRef);
	V.NPCMarketShare.upperClass = Math.trunc((V.NPCSexSupply.upperClass * 1000) / upperClassSexDemandRef);
	V.NPCMarketShare.topClass = Math.trunc((V.NPCSexSupply.topClass * 1000) / topClassSexDemandRef);
	if (lowerClassSexDemand < V.NPCSexSupply.lowerClass) {
		lowerClassSexDemand = 0;
	} else {
		lowerClassSexDemand -= V.NPCSexSupply.lowerClass;
	}

	if (middleClassSexDemand < V.NPCSexSupply.middleClass) {
		middleClassSexDemand = 0;
	} else {
		middleClassSexDemand -= V.NPCSexSupply.middleClass;
	}

	if (upperClassSexDemand < V.NPCSexSupply.upperClass) {
		upperClassSexDemand = 0;
	} else {
		upperClassSexDemand -= V.NPCSexSupply.upperClass;
	}

	if (topClassSexDemand < V.NPCSexSupply.topClass) {
		topClassSexDemand = 0;
	} else {
		topClassSexDemand -= V.NPCSexSupply.topClass;
	}

	if (V.cheatMode === 1 || V.debugMode === 1) {
		_printDebugInfo(renderContainer);
	}

	// Sexual satisfaction effects
	V.sexDemandResult.lowerClass = Math.trunc(((V.NPCSexSupply.lowerClass + sjv.brothel.lowerClass + clubSupply.lowerClass + arcadeSupply.lowerClass) * 1000) / lowerClassSexDemandRef);
	V.sexDemandResult.middleClass = Math.trunc(((V.NPCSexSupply.middleClass + sjv.brothel.middleClass + clubSupply.middleClass + arcadeSupply.middleClass) * 1000) / middleClassSexDemandRef);
	V.sexDemandResult.upperClass = Math.trunc(((V.NPCSexSupply.upperClass + sjv.brothel.upperClass + arcadeSupply.upperClass) * 1000) / upperClassSexDemandRef);
	V.sexDemandResult.topClass = Math.trunc(((V.NPCSexSupply.topClass + sjv.brothel.topClass) * 1000) / topClassSexDemandRef);

	if (V.sexDemandResult.lowerClass < 400) { // You are providing < 40% of their desired amount of sex
		if (V.week <= 30) {
			V.classSatisfied.lowerClass = 0;
		} else {
			V.classSatisfied.lowerClass = -1;
		}
	} else if (V.sexDemandResult.lowerClass < 600) { // You are providing between 40 and 60% of their desired amount of sex
		if (V.week <= 40) {
			V.classSatisfied.lowerClass = 1;
		} else if (V.week <= 60) {
			V.classSatisfied.lowerClass = 0;
		} else {
			V.classSatisfied.lowerClass = -1;
		}
	} else if (V.sexDemandResult.lowerClass < 800) { // You are providing between 60 and 80% of their desired amount of sex
		if (V.week <= 50) {
			V.classSatisfied.lowerClass = 1;
		} else {
			V.classSatisfied.lowerClass = 0;
		}
	} else if (V.sexDemandResult.lowerClass === 1000) { // You are providing 100% or more of their desired amount of sex
		V.classSatisfied.lowerClass = 2;
	} else { // You are providing > 80% of their desired amount of sex
		V.classSatisfied.lowerClass = 1;
	}

	if (V.sexDemandResult.middleClass < 400) { // You are providing < 40% of their desired amount of sex
		if (V.week <= 30) {
			V.classSatisfied.middleClass = 0;
		} else {
			V.classSatisfied.middleClass = -1;
		}
	} else if (V.sexDemandResult.middleClass < 600) { // You are providing between 40 and 60% of their desired amount of sex
		if (V.week <= 40) {
			V.classSatisfied.middleClass = 1;
		} else if (V.week <= 60) {
			V.classSatisfied.middleClass = 0;
		} else {
			V.classSatisfied.middleClass = -1;
		}
	} else if (V.sexDemandResult.middleClass < 800) { // You are providing between 60 and 80% of their desired amount of sex
		if (V.week <= 50) {
			V.classSatisfied.middleClass = 1;
		} else {
			V.classSatisfied.middleClass = 0;
		}
	} else if (V.sexDemandResult.middleClass === 1000) { // You are providing 100% or more of their desired amount of sex
		V.classSatisfied.middleClass = 2;
	} else { // You are providing > 80% of their desired amount of sex
		V.classSatisfied.middleClass = 1;
	}

	if (V.sexDemandResult.upperClass < 400) { // You are providing < 40% of their desired amount of sex
		if (V.week <= 30) {
			V.classSatisfied.upperClass = 0;
		} else {
			V.classSatisfied.upperClass = -1;
		}
	} else if (V.sexDemandResult.upperClass < 600) { // You are providing between 40 and 60% of their desired amount of sex
		if (V.week <= 40) {
			V.classSatisfied.upperClass = 1;
		} else if (V.week <= 60) {
			V.classSatisfied.upperClass = 0;
		} else {
			V.classSatisfied.upperClass = -1;
		}
	} else if (V.sexDemandResult.upperClass < 800) { // You are providing between 60 and 80% of their desired amount of sex
		if (V.week <= 50) {
			V.classSatisfied.upperClass = 1;
		} else {
			V.classSatisfied.upperClass = 0;
		}
	} else if (V.sexDemandResult.upperClass === 1000) { // You are providing 100% or more of their desired amount of sex
		V.classSatisfied.upperClass = 2;
	} else { // You are providing > 80% of their desired amount of sex
		V.classSatisfied.upperClass = 1;
	}

	if (V.sexDemandResult.topClass < 400) { // You are providing < 40% of their desired amount of sex
		if (V.week <= 30) {
			V.classSatisfied.topClass = 0;
		} else {
			V.classSatisfied.topClass = -1;
		}
	} else if (V.sexDemandResult.topClass < 600) { // You are providing between 40 and 60% of their desired amount of sex
		if (V.week <= 40) {
			V.classSatisfied.topClass = 1;
		} else if (V.week <= 60) {
			V.classSatisfied.topClass = 0;
		} else {
			V.classSatisfied.topClass = -1;
		}
	} else if (V.sexDemandResult.topClass < 800) { // You are providing between 60 and 80% of their desired amount of sex
		if (V.week <= 50) {
			V.classSatisfied.topClass = 1;
		} else {
			V.classSatisfied.topClass = 0;
		}
	} else if (V.sexDemandResult.topClass === 1000) { // You are providing 100% or more of their desired amount of sex
		V.classSatisfied.topClass = 2;
	} else { // You are providing > 80% of their desired amount of sex
		V.classSatisfied.topClass = 1;
	}

	/**
	 * @param {ParentNode} c
	 */
	function _printDebugInfo(c) {
		App.UI.DOM.appendNewElement("div", c, "Slave services supply and demand this week:");

		const table = App.UI.DOM.appendNewElement("table", c, null, "finance");
		table.style.border = "1";
		const titleRow = App.UI.DOM.appendNewElement("tr", table);
		titleRow.style.textAlign = "center";
		const tcl = App.UI.DOM.appendNewElement("th", titleRow, "Client's class");
		tcl.style.textAlign = "right";
		App.UI.DOM.appendNewElement("th", titleRow, "Lower");
		App.UI.DOM.appendNewElement("th", titleRow, "Middle");
		App.UI.DOM.appendNewElement("th", titleRow, "Upper");
		App.UI.DOM.appendNewElement("th", titleRow, "Top");

		/**
		 *
		 * @param {string} caption
		 * @param {number} [lower]
		 * @param {number} [middle]
		 * @param {number} [upper]
		 * @param {number} [top]
		 */
		function numericRow(caption, lower, middle, upper, top) {
			const row = App.UI.DOM.appendNewElement("tr", table);
			row.align = "right";
			App.UI.DOM.appendNewElement("td", row, caption);
			App.UI.DOM.appendNewElement("td", row, lower == null ? "N/A" : commaNum(lower));
			App.UI.DOM.appendNewElement("td", row, middle == null ? "N/A" : commaNum(middle));
			App.UI.DOM.appendNewElement("td", row, upper == null ? "N/A" : commaNum(upper));
			App.UI.DOM.appendNewElement("td", row, top == null ? "N/A" : commaNum(top));
		}

		numericRow("Demand", lowerClassSexDemandRef, middleClassSexDemandRef, upperClassSexDemandRef, topClassSexDemandRef);
		numericRow("Brothel Supply", sjv.brothel.lowerClass, sjv.brothel.middleClass, sjv.brothel.upperClass, sjv.brothel.topClass);
		if (clubSupply.lowerClass || clubSupply.middleClass) {
			numericRow("Club Supply", clubSupply.lowerClass, clubSupply.middleClass);
		}
		if (arcadeSupply.lowerClass || arcadeSupply.middleClass || arcadeSupply.upperClass) {
			numericRow("Arcade Supply", arcadeSupply.lowerClass, arcadeSupply.middleClass, arcadeSupply.upperClass);
		}
		numericRow("NPC Supply", V.NPCSexSupply.lowerClass, V.NPCSexSupply.middleClass, V.NPCSexSupply.upperClass, V.NPCSexSupply.topClass);
		numericRow("Unsatisfied", lowerClassSexDemand, middleClassSexDemand, upperClassSexDemand, topClassSexDemand);
	}
};


code:
App.EndWeek.slaveAssignmentReport = function() {
	const facilities = App.Entity.facilities;
	const arcology = V.arcologies[0];

	const initialEmployeesCount = App.Utils.countFacilityWorkers(); // will be used to show differences after all the assignment changes
	const initialPenthouseTotalEmployeesCount = _countPenthousePopulation();

	/* Initialize global SA variables */
	App.EndWeek.saVars = new App.EndWeek.SASharedVariables();

	/* Spa room */
	if (facilities.spa.established) {
		V.spaSpots = (facilities.spa.capacity - App.Entity.facilities.spa.employeesIDs().size) * 20;
		if (S.Attendant) {
			V.spaSpots = Math.trunc(V.spaSpots * (1 + (S.Attendant.skill.attendant / 400))); // A skilled attendant improves available space by 25%
		}
	}

	const skillsToTest = {
		whoring: "whore",
		entertainment: "entertain",
		vaginal: "vaginal",
		anal: "anal",
		oral: "oral"
	};

	const res = document.createDocumentFragment();

	/* perform reassignments before generating reports */
	for (const slave of V.slaves) {
		for (const sk in skillsToTest) {
			if (_.isNil(slave.skill[sk])) {
				_printSlaveError(`Reset bad ${skillsToTest[sk]} skill`, slave);
				slave.skill[sk] = 0;
			}
		}

		// fire unqualified special slaves
		_ensureEmployeeMeetsJobRequirements(slave);

		// first pass on choosesOwnJob is silent
		if (slave.choosesOwnAssignment === 1) {
			App.SlaveAssignment.choosesOwnJob(slave);
		}
	}

	App.EndWeek.computeSexualServicesModel(res);

	let slavesWithWorkingDicks = 0;
	for (const slave of V.slaves) {
		if ((V.seeDicks > 0) && canPenetrate(slave) && App.Utils.hasNonassignmentSex(slave)) {
			App.EndWeek.saVars.averageDick += slave.dick;
			slavesWithWorkingDicks++;
		}

		if (slave.lactation === 1) {
			slave.lactationDuration--;
		}

		switch (slave.assignment) {
			case Job.HEADGIRLSUITE:
				if (slave.devotion >= random(-30, 20)) {
					App.EndWeek.saVars.HGSlaveSuccess = true;
					App.EndWeek.saVars.HGEnergy++;
				}
				break;
			case Job.SUBORDINATE: {
				const map = App.EndWeek.saVars.subSlaveMap;
				const curSubs = map.get(slave.subTarget);
				if (curSubs) {
					curSubs.push(slave.ID);
				} else {
					map.set(slave.subTarget, [slave.ID]);
				}
				break;
			}
		}

		if (slave.bellyPain !== 0) {
			slave.bellyPain = 0;
		}

		/* preg speed and advance*/

		if (slave.preg > 0) {
			let pregSpeed = 1; // base speed is normal
			if (slave.pregControl === "slow gestation") {
				pregSpeed = 0.25;
			} else if (slave.pregControl === "speed up") {
				pregSpeed = 2;
			}

			if (slave.broodmother === 1 && slave.broodmotherOnHold !== 1) { /* broodmother advance block */
				if ((V.week / slave.broodmotherFetuses === Math.round(V.week / slave.broodmotherFetuses)) && slave.broodmotherFetuses < 1) {
					// one fetus in few week - selection and adding
					WombImpregnate(slave, 1, slave.pregSource, 0);
				} else {
					// one or more fetuses in one week
					WombImpregnate(slave, Math.floor(slave.broodmotherFetuses), slave.pregSource, 0); /* really 0, it's will be advanced right few lines down.*/
				}
				if (slave.ovaryAge >= 47) {
					slave.broodmotherOnHold = 1;
					slave.broodmotherCountDown = 37 - WombMinPreg(slave);
				}
			}

			WombProgress(slave, pregSpeed, 1); /* drugs can affect speed of gestation, but not a real time */

			slave.pregKnown = 1;
			slave.pregWeek++;
		}
		if (slave.pregWeek < 0) { // postpartum state
			slave.pregWeek++;
		}

		SetBellySize(slave); /* here will be also set through WombGetVolume .bellyPreg, .pregType, to current values. */

		/* end of preg speed and advance*/

		/* set up sexual need */
		if (slave.devotion >= -50) {
			if (slave.energy > 20) {
				if (slave.physicalAge < slave.pubertyAgeXY && slave.genes === "XY" && slave.energy <= 80) {
					slave.need = slave.energy / 3;
				} else if (slave.physicalAge < slave.pubertyAgeXX && slave.genes === "XX" && slave.energy <= 80) {
					slave.need = slave.energy / 3;
				} else if (slave.physicalAge < 50) {
					slave.need = slave.energy;
				} else {
					slave.need = slave.energy / 5;
				}
				if (slave.balls > 0 && slave.pubertyXY === 1 && slave.physicalAge <= (slave.pubertyAgeXY + 1) && (slave.physicalAge > slave.pubertyAgeXY) && slave.physicalAge < 18) {
					slave.need *= 1.25;
				}
				if ((slave.ovaries === 1 || slave.mpreg === 1) && slave.pubertyXX === 1 && slave.physicalAge <= (slave.pubertyAgeXX + 1) && (slave.physicalAge > slave.pubertyAgeXX) && slave.physicalAge < 18) {
					slave.need *= 1.25;
				}
				if (slave.diet === "fertility") {
					slave.need += 10;
				}
				if (slave.aphrodisiacs === -1) {
					slave.need *= 0.5;
				} else if (slave.aphrodisiacs === 1) {
					slave.need *= 1.5;
				} else if (slave.aphrodisiacs === 2) {
					slave.need *= 2;
				}
				poorHealthNeedReduction(slave);
				slave.need = Math.round(slave.need);
				slave.needCap = slave.need;
			}
		}

		if (slave.fetish === "mindbroken" && slave.relationship === -3) {
			if (slave.kindness > 0) {
				slave.kindness--;
			}
		}

		if (slave.assignment === Job.AGENT || slave.assignment === Job.AGENTPARTNER) {
			App.SlaveAssignment.agent(slave);
		}
	} // for (const slave of V.slaves)

	if (V.HeadGirlID !== 0) {
		App.EndWeek.saVars.HGEnergy++;
		const slave = slaveStateById(V.HeadGirlID);
		if (V.personalAttention.task === PersonalAttention.SUPPORTHG && V.PC.health.shortDamage < 30) {
			App.EndWeek.saVars.HGEnergy++;
			if (slave.trust > 95) {
				App.EndWeek.saVars.HGEnergy++;
			}
		}
		if (arcology.FSChineseRevivalistLaw === 1) {
			App.EndWeek.saVars.HGEnergy++;
		}
		if (slaveResting(slave)) {
			App.EndWeek.saVars.HGEnergy = 0;
		}
		if (canAchieveErection(slave)) {
			App.EndWeek.saVars.HGCum = resetHGCum(slave);
		}
	}

	// Stud gets off based on impregnations, so we need to check and see if they actually do anyone
	if (V.StudID) {
		const stud = S.Stud;
		App.EndWeek.saVars.StudCum = 2 + Math.trunc(((stud.balls / 5) + (stud.energy / 95) + (stud.health.condition / 95) + (stud.devotion / 95) + (V.reproductionFormula * 5) - (stud.health.tired / 25)) * restEffects(stud, 5));
		if (stud.drugs === "hyper testicle enhancement") {
			App.EndWeek.saVars.StudCum += 3;
		} else if (stud.drugs === "testicle enhancement") {
			App.EndWeek.saVars.StudCum += 1;
		}
		if (stud.diet === "cum production") {
			App.EndWeek.saVars.StudCum += 1;
		}
		let studCumLimit = App.EndWeek.saVars.StudCum;
		for (const slave of V.slaves) {
			if (studCumLimit === 0 || stud.need <= 0) {
				break;
			}
			if (canGetPregnant(slave) && canBreed(stud, slave) && slave.ID !== V.StudID) {
				stud.need -= 20;
				if (stud.fetish === "pregnancy") {
					stud.need -= 30;
				}
			}
		}
	}

	if (App.EndWeek.saVars.averageDick > 0) {
		App.EndWeek.saVars.averageDick = App.EndWeek.saVars.averageDick / slavesWithWorkingDicks;
	}
	App.EndWeek.saVars.freeSexualEnergy = V.PC.sexualEnergy - fuckSlavesLength();
	const penthouseSlaves = App.Entity.facilities.penthouse.employees().length;
	if (App.EndWeek.saVars.freeSexualEnergy > 0) {
		if (App.EndWeek.saVars.freeSexualEnergy > penthouseSlaves / 2) {
			App.EndWeek.saVars.freeSexualEnergy = 3;
		} else if (App.EndWeek.saVars.freeSexualEnergy > penthouseSlaves / 4) {
			App.EndWeek.saVars.freeSexualEnergy = 2;
		} else {
			App.EndWeek.saVars.freeSexualEnergy = 1;
		}
	}

	// initialize slave art
	if (V.seeImages && V.seeReportImages) {
		// agents and partners are not drawn; penthouse partners and the head girl's slave will be drawn via a different mechanism (since they are larger and right-aligned)
		const undrawnJobs = [Job.AGENT, Job.AGENTPARTNER, ...App.Entity.facilities.penthouse.jobsNames, Job.HEADGIRLSUITE];
		const drawnSlaveIDs = V.slaves.filter(s => !undrawnJobs.includes(s.assignment)).map(s => s.ID);
		// this batch renderer object will be accessible to all the facility reports
		App.EndWeek.saVars.slaveArt = new App.Art.SlaveArtBatch(drawnSlaveIDs, 0);
		res.append(App.EndWeek.saVars.slaveArt.writePreamble());
	}

	/**
	 * Accordion
	 * @version 0.7RC
	 * @author 000-250-006
	 *
	 * @param array _facListArr
	 *	Multidimensional temporary array
	 *	0: The DOM function for the facility's report
	 *	1: A facility object, or the title of the report if there is no facility object
	 *	2: If there is no facility object, a truthy value indicating whether the facility exists
	 *	3: If there is no facility object, the maximum capacity of the facility
	 *
	 * TODO: This is a proof of concept construct, if it works and cuts overhead, intended to create an object
	 *	for deeper use in multiple locations, including streamlining reports/facilities code to one widget
	 * TODO: Figure out if this would be better as an object rather than an array for overhead
	 *	StoryInit also?
	 */

	const facListArr = [
		[App.EndWeek.arcadeReport, App.Entity.facilities.arcade],
		[App.EndWeek.brothelReport, App.Entity.facilities.brothel],
		[App.EndWeek.cellblockReport, App.Entity.facilities.cellblock],
		[App.EndWeek.clinicReport, App.Entity.facilities.clinic],
		[App.EndWeek.clubReport, App.Entity.facilities.club],
		[App.EndWeek.dairyReport, App.Entity.facilities.dairy],
		[App.EndWeek.farmyardReport, App.Entity.facilities.farmyard],
		[App.EndWeek.schoolroomReport, App.Entity.facilities.schoolroom],
		[App.EndWeek.spaReport, App.Entity.facilities.spa],
		[App.EndWeek.servantsQuartersReport, App.Entity.facilities.servantsQuarters],
		[App.Facilities.Nursery.nurseryReport, App.Entity.facilities.nursery],
		[App.Facilities.Nursery.childrenReport, "Nursery Children", V.nursery, V.nurseryChildren],
		[App.EndWeek.incubatorReport, App.Entity.facilities.incubator],
		[App.EndWeek.masterSuiteReport, App.Entity.facilities.masterSuite],
		[App.EndWeek.penthouseReport, "The Penthouse"],
		[App.EndWeek.rulesAssistantReport, "Rules Assistant", V.rulesAssistantAuto], /** should be last — may reassign slaves **/
		[App.EndWeek.labReport, "Lab", V.researchLab.level]
	];

	function _getReportElementStats(ar) {
		if (typeof ar[1] === "string") {
			if (ar[1] === "The Penthouse") { // special case because we have to combine several facilities
				return {
					name: ar[1],
					established: 1,
					entriesNumberInitial: initialPenthouseTotalEmployeesCount,
					entriesNumber: _countPenthousePopulation(),
					manager: null,
					alwaysExists: 0,
				};
			} else {
				return {
					name: ar[1],
					established: ar[2],
					entriesNumberInitial: null,
					entriesNumber: ar[3],
					manager: null,
					alwaysExists: ar[3] === undefined ? 1 : 0,
				};
			}
		} else {
			return {
				name: capFirstChar(ar[1].name),
				established: ar[1].established,
				entriesNumberInitial: initialEmployeesCount[ar[1].desc.baseName],
				entriesNumber: ar[1].hostedSlaves,
				manager: ar[1].manager,
				alwaysExists: 0,
			};
		}
	}

	for (const facSubArr of facListArr) {
		// needs to be inside the loop after the report passage to get the employees number after re-assignments
		const stats = _getReportElementStats(facSubArr);

		if (stats.established) { // Do we have one of these facilities?
			const header = document.createDocumentFragment();
			App.UI.DOM.appendNewElement("span", header, `${stats.name} Report`, "title");

			if (!stats.alwaysExists) {
				const diffNum = stats.entriesNumber - stats.entriesNumberInitial;
				const diffText = diffNum === 0 ? "" : (diffNum > 0 ? ` (+${diffNum})` : ` (${diffNum})`);
				// Display the bar with information
				if (stats.entriesNumber > 0) {
					App.UI.DOM.appendNewElement("span", header,
						`${stats.entriesNumber}${diffText} slave${stats.entriesNumber !== 1 ? "s" : ""} ${
							stats.manager && stats.manager.currentEmployee
								? `and ${capFirstChar(stats.manager.desc.position)}` : ""
						} in ${stats.name}`, ["info", "green"]);
				} else if (stats.manager && stats.manager.currentEmployee) {
					App.UI.DOM.appendNewElement("span", header,
						`${diffText} Only ${capFirstChar(stats.manager.desc.position)} in ${stats.name}`,
						["info", "orange"]);
				} else {
					App.UI.DOM.appendNewElement("span", header, `${diffText} ${stats.name} is empty`,
						["info", "gray"]);
				}
			}

			// Is there anyone inside the facility?
			if (stats.entriesNumber > 0 || (stats.manager && stats.manager.currentEmployee) || stats.alwaysExists) {
				// @ts-ignore - the first element of the subarray is always callable but TS isn't smart enough to figure that out
				const reportContent = App.UI.DOM.makeElement("div", facSubArr[0]());
				res.append(App.UI.DOM.accordion(header, reportContent, V.useAccordion > 0));
			} else {
				res.append(App.UI.DOM.accordion(header));
			}
		}
	}

	/* Clean up global SA variables */
	App.EndWeek.saVars = null;
	delete V.flSex; // FIXME: remove, once this is passed as a parameter to saRules

	return res;

	function _countPenthousePopulation() {
		const fs = App.Entity.facilities;
		return fs.penthouse.employeesIDs().size + fs.headGirlSuite.totalEmployeesCount + fs.armory.totalEmployeesCount;
	}

	function _printSlaveError(warning, slave) {
		const warningLine = App.UI.DOM.appendNewElement("div", res);
		App.UI.DOM.appendNewElement("span", warningLine, warning + `for ${slave.slaveName}.`, "yellow");
		warningLine.appendChild(document.createTextNode(" Report this as a bug if it reoccurs."));
	}

	/**
	 * Check key employees. Fire those who do not satisfy their job requirements
	 * @param {App.Entity.SlaveState} slave
	 */
	function _ensureEmployeeMeetsJobRequirements(slave) {
		switch (slave.assignment) {
			case Job.HEADGIRL:
				if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.HeadGirlID = 0;
				} else if (!canTalk(slave)) {
					_printSlaveUnassignedNote(slave, "can't give slaves verbal orders");
					V.HeadGirlID = 0;
				} else if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.HeadGirlID = 0;
				} else if (!canHold(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer able to handle your slaves");
					V.HeadGirlID = 0;
				} else if (!canSee(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.HeadGirlID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.HeadGirlID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your Head Girl any longer`);
					V.HeadGirlID = 0;
				} else if (slave.devotion <= 20) {
					_printSlaveUnassignedNote(slave, "is no longer even accepting of you");
					V.HeadGirlID = 0;
				}
				if (V.HeadGirlID === 0) {
					removeJob(slave, Job.HEADGIRL);
				}
				break;
			case Job.RECRUITER:
				V.RecruiterID = slave.ID;
				if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.RecruiterID = 0;
				} else if (!canTalk(slave)) {
					_printSlaveUnassignedNote(slave, "can't verbally entice marks");
					V.RecruiterID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your recruiter any longer`);
					V.RecruiterID = 0;
				} else if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.RecruiterID = 0;
				} else if (!canSee(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.RecruiterID = 0;
				} else if (!canHear(S.Recruiter)) {
					_printSlaveUnassignedNote(slave, "an no longer hear");
					V.RecruiterID = 0;
				}
				if (V.RecruiterID === 0) {
					removeJob(slave, Job.RECRUITER);
				}
				break;
			case Job.MADAM:
				if (!canTalk(slave)) {
					_printSlaveUnassignedNote(slave, "can't give whores verbal orders");
					V.MadamID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your Madam any longer`);
					V.MadamID = 0;
				} else if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.MadamID = 0;
				} else if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.MadamID = 0;
				} else if (!canSee(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.MadamID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.MadamID = 0;
				} else if (!canHold(slave)) {
					_printSlaveUnassignedNote(slave, `can no longer handle ${getPronouns(slave).his} underlings`);
					V.MadamID = 0;
				}
				if (V.MadamID === 0) {
					removeJob(slave, Job.MADAM);
				}
				break;
			case Job.DJ:
				if (!canTalk(slave)) {
					_printSlaveUnassignedNote(slave, "can't speak");
					V.djID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your DJ any longer`);
					V.djID = 0;
				} else if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.djID = 0;
				} else if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.djID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.djID = 0;
				}
				if (V.djID === 0) {
					removeJob(slave, Job.DJ);
				}
				break;
			case Job.MILKMAID:
				if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.MilkmaidID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your Milkmaid any longer`);
					V.MilkmaidID = 0;
				} else if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.MilkmaidID = 0;
				} else if (!canHold(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer handle nor milk your slaves");
					V.MilkmaidID = 0;
				} else if (!canSee(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.MilkmaidID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.MilkmaidID = 0;
				}
				if (V.MilkmaidID === 0) {
					removeJob(slave, Job.MILKMAID);
				}
				break;
			case Job.FARMER:
				if (S.Farmer.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.FarmerID = 0;
				} else if (S.Farmer.preg > 37 && S.Farmer.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your Farmer any longer`);
					V.FarmerID = 0;
				} else if (!canWalk(S.Farmer)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.FarmerID = 0;
				} else if (!canHold(S.Farmer)) {
					_printSlaveUnassignedNote(slave, "can no longer grip things");
					V.FarmerID = 0;
				} else if (!canSee(S.Farmer)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.FarmerID = 0;
				} else if (!canHear(S.Farmer)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.FarmerID = 0;
				}
				if (V.FarmerID === 0) {
					removeJob(slave, Job.FARMER);
				}
				break;
			case Job.STEWARD:
				if (!canTalk(slave)) {
					_printSlaveUnassignedNote(slave, "can't give servants verbal orders");
					V.StewardessID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your Stewardess any longer`);
					V.StewardessID = 0;
				} else if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.StewardessID = 0;
				} else if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.StewardessID = 0;
				} else if (!canHold(slave)) {
					_printSlaveUnassignedNote(slave, `can no longer handle ${getPronouns(slave).his} underlings nor effectively clean`);
					V.StewardessID = 0;
				} else if (!canSee(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.StewardessID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.StewardessID = 0;
				}
				if (V.StewardessID === 0) {
					removeJob(slave, Job.STEWARD);
				}
				break;
			case Job.TEACHER:
				if (!canTalk(slave)) {
					_printSlaveUnassignedNote(slave, "can't give verbal instruction");
					V.SchoolteacherID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your Schoolteacher any longer`);
					V.SchoolteacherID = 0;
				} else if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.SchoolteacherID = 0;
				} else if (!canSee(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.SchoolteacherID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.SchoolteacherID = 0;
				}
				if (V.SchoolteacherID === 0) {
					removeJob(slave, Job.TEACHER);
				}
				break;
			case Job.WARDEN:
				if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.WardenessID = 0;
				} else if (!canHold(slave)) {
					_printSlaveUnassignedNote(slave, `can no longer handle ${getPronouns(slave).his} charges`);
					V.WardenessID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your Wardeness any longer`);
					V.WardenessID = 0;
				} else if (!canSee(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.WardenessID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.WardenessID = 0;
				}
				if (V.WardenessID === 0) {
					removeJob(slave, Job.WARDEN);
				}
				break;
			case Job.ATTENDANT:
				if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.AttendantID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your Attendant any longer`);
					V.AttendantID = 0;
				} else if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.AttendantID = 0;
				} else if (!canHold(slave)) {
					_printSlaveUnassignedNote(slave, `can no longer support ${getPronouns(slave).his} charges`);
					V.AttendantID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.AttendantID = 0;
				}
				if (V.AttendantID === 0) {
					removeJob(slave, Job.ATTENDANT);
				}
				break;
			case Job.MATRON:
				if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.MatronID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your Matron any longer`);
					V.MatronID = 0;
				} else if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.MatronID = 0;
				} else if (!canHold(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hold infants");
					V.MatronID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.MatronID = 0;
				} else if (!canSee(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.MatronID = 0;
				}
				if (V.MatronID === 0) {
					removeJob(slave, Job.MATRON);
				}
				break;
			case Job.NURSE:
				if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.NurseID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your Nurse any longer`);
					V.NurseID = 0;
				} else if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.NurseID = 0;
				} else if (!canHold(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hold onto patients");
					V.NurseID = 0;
				} else if (!canSee(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.NurseID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.NurseID = 0;
				}
				if (V.NurseID === 0) {
					removeJob(slave, Job.NURSE);
				}
				break;
			case Job.BODYGUARD:
				if (slave.fetish === "mindbroken") {
					_printSlaveUnassignedNote(slave, "is mindbroken");
					V.BodyguardID = 0;
				} else if (!canWalk(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer independently mobile");
					V.BodyguardID = 0;
				} else if (!canHold(slave)) {
					_printSlaveUnassignedNote(slave, "is no longer able to hold a weapon");
					V.BodyguardID = 0;
				} else if (slave.preg > 37 && slave.broodmother === 2) {
					_printSlaveUnassignedNote(slave, "spends so much time giving birth and laboring that", `${getPronouns(slave).he} cannot effectively serve as your bodyguard any longer`);
					V.BodyguardID = 0;
				} else if (!canSee(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer see");
					V.BodyguardID = 0;
				} else if (!canHear(slave)) {
					_printSlaveUnassignedNote(slave, "can no longer hear");
					V.BodyguardID = 0;
				}
				if (V.BodyguardID === 0) {
					removeJob(slave, Job.BODYGUARD);
				}
				break;
			case Job.SUBORDINATE:
				if (slave.subTarget === -1) {
					V.StudID = slave.ID;
					if (slave.balls === 0) {
						_printSlaveUnassignedNote(slave, "no longer has sperm", null, "@Stud");
						V.StudID = 0;
					} else if (slave.ballType === "sterile") {
						_printSlaveUnassignedNote(slave, "no longer produces potent sperm", null, "@Stud");
						V.StudID = 0;
					} else if (slave.pubertyXY !== 1) {
						_printSlaveUnassignedNote(slave, "no longer produces mature sperm", null, "@Stud");
						V.StudID = 0;
					} else if (slave.vasectomy === 1) {
						_printSlaveUnassignedNote(slave, "shoots blanks due to a vasectomy", null, "@Stud");
						V.StudID = 0;
					} else if (V.universalRulesImpregnation !== "Stud") {
						_printSlaveUnassignedNote(slave, "is", "no longer needed as a Stud", "@Stud");
					}
					if (V.StudID === 0) {
						slave.subTarget = 0;
					}
				}
				break;
			case Job.AGENT: {
				const arc = V.arcologies.find((a) => a.leaderID === slave.ID);
				if (!arc) {
					_printSlaveUnassignedNote(slave, "is not assigned to an arcology");
					removeJob(slave, Job.AGENT);
				} else if (arc.government !== "your agent") {
					_printSlaveUnassignedNote(slave, "is assigned to an arcology that is not lead by an agent");
					removeJob(slave, Job.AGENT);
				}
				break;
			}
		}

		if (slave.ID === V.LurcherID) {
			if (!canWalk(slave)) {
				_printSlaveUnassignedNote(slave, "is no longer able to run", null, Job.LURCHER);
				V.LurcherID = 0;
			} else if (!canHold(slave)) {
				_printSlaveUnassignedNote(slave, "is no longer able to catch the hares", null, Job.LURCHER);
				V.LurcherID = 0;
			} else if (!canHear(slave) && !canSee(slave)) {
				_printSlaveUnassignedNote(slave, "is no longer able to track the hares", null, Job.LURCHER);
				V.LurcherID = 0;
			} else if (slave.bellyPreg >= 60000) {
				_printSlaveUnassignedNote(slave, "is too pregnant to run", null, Job.LURCHER);
				V.LurcherID = 0;
			}
		}

		if (V.pit && V.pit.fighterIDs.includes(slave.ID)) {
			if (!canWalk(slave)) {
				_printSlaveUnassignedNote(slave, "is no longer independently mobile",
					`and cannot fight any more. ${getPronouns(slave).He} has been removed from ${App.Entity.facilities.pit.name} roster`);
				removeJob(slave, Job.PIT, true);
			} else if (!canHold(slave)) {
				_printSlaveUnassignedNote(slave, "is no longer able to strike",
					`and cannot fight any more. ${getPronouns(slave).he} has been removed from ${App.Entity.facilities.pit.name} roster`);
				removeJob(slave, Job.PIT, true);
			}
		}
	}

	/**
	 *
	 * @param {App.Entity.SlaveState} slave
	 * @param {string} condition
	 * @param {string} [outcome]
	 * @param {string} [assignment]
	 */
	function _printSlaveUnassignedNote(slave, condition, outcome, assignment) {
		const cantServeNotes = new Map([
			[Job.HEADGIRL, "cannot serve as your Head Girl any more"],
			[Job.RECRUITER, "and cannot serve as your recruiter any more"],
			[Job.MADAM, "cannot serve as your Madam any more"],
			[Job.DJ, "cannot serve as your DJ any more"],
			[Job.MILKMAID, "cannot serve as your Milkmaid any more"],
			[Job.FARMER, "cannot serve as your Farmer any more"],
			[Job.STEWARD, "cannot serve as your Stewardess any more"],
			[Job.TEACHER, "cannot serve as your Schoolteacher any more"],
			[Job.WARDEN, "cannot serve as your Wardeness any more"],
			[Job.ATTENDANT, "cannot serve as your Attendant any more"],
			[Job.BODYGUARD, " cannot serve as your Bodyguard any more"],
			["@Stud", "cannot serve as a Stud any more"],
			[Job.NURSE, "cannot serve as your Nurse any more"],
			[Job.MATRON, "cannot serve as your Matron any more"],
			[Job.LURCHER, "cannot course as a lurcher"],
			[Job.AGENT, "cannot serve as an Agent any more"]
		]);

		const warningLine = App.UI.DOM.appendNewElement("div", res);
		App.UI.DOM.appendNewElement("span", warningLine, slave.slaveName, 'slave-name');
		warningLine.appendChild(document.createTextNode(' ' + condition + ' '));
		App.UI.DOM.appendNewElement("span", warningLine, outcome ? outcome : `and ${cantServeNotes.get(assignment || slave.assignment)}`, "yellow");
		warningLine.appendChild(document.createTextNode("."));
	}
};

repo_name: Pecanus/fc

license: mit


code:
/**
 * Generates (and returns if not silent) a standard slave report
 * This is the part after the slave's job in most facilities.
 * @param {FC.ReportSlave} slave
 * @param {boolean} silent
 * @returns {DocumentFragment|null}
 */
App.SlaveAssignment.standardSlaveReport = function(slave, silent = false) {
	const clothes = App.SlaveAssignment.choosesOwnClothes(slave);
	const individualReport = App.SlaveAssignment.individualSlaveReport(slave);
	const devotion = App.SlaveAssignment.devotion(slave);

	if (!silent) {
		const container = document.createDocumentFragment();
		App.Events.addNode(container, [clothes, ...individualReport], "div", "indent");
		App.Events.addNode(container, [devotion], "div", "indent");
		return container;
	}
};

/**
 * Generates the main part of the standard slave report for an individual slave.
 * This is the section that's identical for all slaves regardless of facility.
 * @param {FC.ReportSlave} slave
 * @returns {Array<DocumentFragment|string>}
 */
App.SlaveAssignment.individualSlaveReport = function(slave) {
	return [
		App.SlaveAssignment.rules(slave),
		App.SlaveAssignment.diet(slave),
		App.SlaveAssignment.longTermEffects(slave),
		App.SlaveAssignment.drugs(slave),
		App.SlaveAssignment.relationships(slave),
		App.SlaveAssignment.rivalries(slave),
	];
};

/**
 * Render slave assignment report art
 * @param {ParentNode} node
 * @param {App.Entity.SlaveState} slave
 */
App.SlaveAssignment.appendSlaveArt = function(node, slave) {
	if (V.seeImages && V.seeReportImages) {
		App.UI.DOM.appendNewElement("div", node, App.EndWeek.saVars.slaveArt.render(slave), ["imageRef", "tinyImg"]);
	}
};

/**
 * Render favorite and reminder links
 * @param {ParentNode} node
 * @param {App.Entity.SlaveState} slave
 */
App.SlaveAssignment.appendSlaveLinks = function(node, slave) {
	node.append(
		App.UI.favoriteToggle(slave), " ",
		App.Reminders.slaveLink(slave.ID), " "
	);
};


code:
/*  Events are organized into several files and folders								*/
/*	genericPlotEvents.tw															*/
/*	PESS.tw: Player Event, Single Slave												*/
/*	PETS.tw: Player Event, Two Slaves												*/
/*	RECI.tw: Random Event, Check In													*/
/*	REFI.tw: Random Event, Fetish Interest											*/
/*	REFS.tw: Random Event, Future Societies											*/
/*	RESS.tw: Random Event, Single Slave												*/
/*	RESSTR.tw: Random Event, Single Slave (Test Realm, for debugging events)		*/
/*	RETS.tw: Random Event, Two Slaves												*/
/*																					*/
/* Events can also be in a dedicated *.tw file, formatted as follows:				*/
/*	jeXXXXX.tw: Justice Event														*/
/*	pXXXXXX.tw: Player event														*/
/*	peXXXXX.tw: Player Event focused on a slave										*/
/*	reXXXXX.tw: Random Event														*/
/*	resXXXX.tw: Random Event, School												*/
/*	seXXXXX.tw: Slave Event, focuses on slaves coming or going						*/
/*	securityForceXXXXX.tw: Special (Security) Force event							*/

path: src/events/About Events.txt


code:
App.Events.jeCommon = function() {
	return `${capFirstChar(V.assistant.name)} breaks in on your sleep with an urgent message. You push a slave off you and sit up to take it. As the owner of the arcology, you perform some functions that would traditionally be the province of a government. In this anarcho-liberal polity, it's still necessary for people making deals to have someone to appeal to when disputes arise. Part of your agreement with your tenants is that you will perform this duty on deals between two tenants. The message is about just such a disagreement; they always seem to happen in the middle of the night, and they're always urgent.`;
};


code:
App.Events.JESlaveDisputeBreedingDeal = class JESlaveDisputeBreedingDeal extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.justiceEvents.includes("breeding deal"),
		];
	}

	get weight() {
		return V.justiceEvents.length > 2 ? 2 : 1;
	}

	execute(node) {
		let r = [];
		const index = V.justiceEvents.indexOf("breeding deal");
		V.justiceEvents.splice(index, 1);
		const contractCost = 40000;
		const slave = GenerateNewSlave("XX", {
			minAge: V.fertilityAge + 3, maxAge: 42, ageOverridesPedoMode: 1, disableDisability: 1
		});
		slave.origin = "$He was raised to be a mother.";
		slave.career = "a breeder";
		slave.devotion = random(10, 25);
		slave.trust = slave.devotion;
		setHealth(slave, jsRandom(80, 90), 0, 0, 0, jsRandom(10, 30));
		slave.anus = 0;
		slave.vagina = 3;
		slave.skill.anal = 0;
		slave.skill.oral = 0;
		slave.skill.whoring = 0;
		slave.skill.vaginal = 0;
		slave.skill.entertainment = 0;
		slave.bellySag = 10;
		slave.bellySagPreg = 10;
		slave.counter.birthsTotal = 3;
		slave.hips = 2;
		slave.boobs = random(4, 6) * 100;
		if (V.seePreg === 1) {
			slave.belly = 18000;
		}
		const {he, his, girl} = getPronouns(slave);

		App.Events.drawEventArt(node, slave);
		App.UI.DOM.appendNewElement("p", node, App.Events.jeCommon());
		r.push(`A small-time slave breeder is accusing a customer of reneging on their agreement. For the last nine months, one of his best breeders has been busy growing his client's future slave and now`);
		if (V.seePreg === 1) {
			r.push(`that ${he}'s ready to give birth,`);
			slave.belly = 0;
			slave.pregWeek = -3;
		} else {
			r.push(`that it's born,`);
		}
		r.push(`he's refusing to transfer the funds, placing the entire operation in jeopardy.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`The father${(V.seePreg === 1) ? "-to-be" : ""} claims that the child is not his and as such, the contract has not been fulfilled. Despite offers from the breeder to perform a paternity test, he adamantly insists on using his private, and rather expensive, physician to run the test; a cost high enough to put them out of business anyway.`);

		App.Events.addParagraph(node, r);

		const choices = [];
		choices.push(new App.Events.Result(`Privately inform both parties you'll settle this in favor of the most generous`, bribe,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the accuser`, accuser,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the breeder`, breeder,));
		choices.push(new App.Events.Result(`Compromise on the compensation and offer to buy out the deal`, buy, `This will cost ${cashFormat(contractCost)} and give you the slave`));
		App.Events.addResponses(node, choices);

		function bribe() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You privately inform both parties you'll settle this in favor of the most generous. You instantly receive two notices of escrow payments contingent on the case going the payer's way. You select the bigger of the two, a clear choice, and decide the matter before returning to bed in a good mood. However, the next day it becomes apparent that although he isn't stupid enough to make a public accusation of corruption, the loser is proclaiming that he is not pleased with your administration of justice.`);
			repX(-100, "event");
			cashX(random(150, 200) * 10, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function accuser() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You settle the dispute in favor of the wealthy accuser. While he is a little disappointed that he didn't get the slave he wanted, he speaks positively in public about how you helped protect his investments from potential mismanagement. Slave trading to and from your arcology is somewhat lessened however, since the breeder lets it be known that trading in your arcology is a risk.`);
			V.arcologies[0].prosperity -= 5;
			repX(2500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}
		function breeder() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You settle the dispute in favor of the slave breeder, and against the prominent accuser, by declaring that the standard paternity test will suffice.`);
			if (V.seePreg === 1) {
				r.push(`As if on queue, the ${girl}'s water breaks and soaks ${his} pants. The call ends to the sight of ${his} crotch bulging as ${his} child is born into ${his} clothing.`);
			}
			r.push(`While he is satisfied with his future slave, he speaks openly in public about how you were so quick to use cheap services to settle the claim instead of listening to his requests. The breeder, however, passes a good word around the industry that slavers trading with your arcology can expect to be protected from abusive claims.`);
			V.arcologies[0].prosperity += 5;
			repX(-500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}
		function buy() {
			const frag = new DocumentFragment();
			let r = [];
			cashX(forceNeg(contractCost), "slaveTransfer");
			r.push(`You offer to buy out the deal, paying the breeder and taking the slave yourself, and passing the child off to the buyer. The citizen gets what he wants and speaks kindly in public about how you helped smooth over a rather rough dispute. The breeder sends a positive note around the industry to the effect that slavers trading with your arcology can expect to be aided in times of need; though the loss of a star mother always stings.`);
			V.arcologies[0].prosperity += 3;
			repX(300, "event");
			App.Events.addParagraph(frag, r);
			frag.append(App.UI.newSlaveIntro(slave));
			return frag;
		}
	}
};


code:
App.Events.JESlaveDisputeIndentureDeal = class JESlaveDisputeIndentureDeal extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.justiceEvents.includes("indenture deal"),
		];
	}

	get weight() {
		return V.justiceEvents.length > 2 ? 2 : 1;
	}

	execute(node) {
		let r = [];
		const index = V.justiceEvents.indexOf("indenture deal");
		V.justiceEvents.splice(index, 1);

		const contractCost = 7500;
		const slave = GenerateNewSlave(null, {minAge: 24, maxAge: 42, disableDisability: 1});
		setHealth(slave, jsRandom(-20, 20));
		slave.anus = 2;
		if (slave.vagina > -1) {
			slave.vagina = 2;
		}
		slave.skill.vaginal = 15;
		slave.skill.oral = 15;
		slave.skill.anal = 15;
		slave.skill.whoring = 0;
		slave.skill.entertainment = 15;
		slave.boobs += 600;
		slave.boobsImplant = 600;
		slave.boobsImplantType = "normal";
		slave.butt += 1;
		slave.buttImplant = 1;
		slave.buttImplantType = "normal";
		slave.lips += 10;
		slave.lipsImplant = 10;
		slave.piercing.lips.weight = 1;
		slave.piercing.tongue.weight = 1;
		slave.piercing.ear.weight = 1;
		slave.piercing.nose.weight = 1;
		slave.piercing.eyebrow.weight = 1;
		slave.piercing.navel.weight = 1;
		slave.piercing.nipple.weight = 1;
		slave.piercing.genitals.weight = 1;
		slave.stampTat = either("flowers", "tribal patterns");
		const {
			He,
			he, him, his, girl
		} = getPronouns(slave);

		App.Events.drawEventArt(node, slave);
		App.UI.DOM.appendNewElement("p", node, App.Events.jeCommon());
		r.push(`A slutty-looking ${girl} appears, bearing a split lip and a black eye, accusing a slave trader of tricking ${him}. ${He} sends you a lengthy contract of indentured servitude. Nothing seems out of order, though indentured servants are becoming less common, since slave labor is usually cheaper and less limited. The angry accuser claims that the trader told ${him} that ${he} wouldn't be required to have sex while indentured. The promise doesn't seem to be in writing, but the ${girl} bitterly insists that it was made. "And now," ${he} almost shrieks, "he's making me be a whore. I got assfucked five times yesterday. Five!"`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`The trader indignantly denies ever making any such commitment, and points out, correctly, that ${he} has no proof. He protests that he only made the indentured servitude deal as a favor to ${him}, and is angry that ${he}'s repaying his courtesy in not insisting on enslavement by this ingratitude. "I see here in the record that ${he} was indeed used anally five times yesterday," he observes acidly. "But that's ${his} job."`);

		App.Events.addParagraph(node, r);

		const choices = [];
		choices.push(new App.Events.Result(`Privately inform both parties you'll settle this in favor of the most generous`, bribe,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the indentured whore`, whore,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the indenture holder`, holder,));
		choices.push(new App.Events.Result(`Buy out the contract and ${his} indenture`, buyAndIndent, `This will cost ${cashFormat(contractCost)} and give you the servant as such`));
		choices.push(new App.Events.Result(`Buy out the contract and enslave ${him}`, enslave, `This will cost ${cashFormat(contractCost)} and give you the servant as a slave`));
		App.Events.addResponses(node, choices);

		function bribe() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You privately inform both parties you'll settle this in favor of the most generous. You instantly receive a single notice of escrow payment contingent on the case going the payer's way. You select the bigger of the two and decide the matter before returning to bed in a good mood. However, the next day it becomes apparent that although ${he} isn't stupid enough to make a public accusation, the whore has been whispering to ${his} peers that you helped the trader cheat ${him} into prostitution. Few citizens care, but there is a faint scent of corruption.`);
			repX(-50, "event");
			cashX(random(150, 200)*10, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function whore() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You settle the dispute in favor of the indentured whore, adding a requirement to the indentured servitude that ${he} not be required to fuck against ${his} will. The story of the brave prostitute and the conniving trader is told and retold, impressing the more credulous citizens. It also raises doubts among the wealthier, more business-minded residents about whether you can be depended on to promote their interests.`);
			V.arcologies[0].prosperity -= 5;
			repX(2500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function holder() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You settle the dispute in favor of the owner of the indenture. No change in the contract is necessary, since it already says what it should: that he controls ${him} for the required period. That's all. The story of your strictness in business disputes impresses some of the more commercially powerful citizens of the arcology, but is hissed by the stupider, more romantic residents, who see only a brave whore being beaten down by a conniving slave trader.`);
			V.arcologies[0].prosperity += 5;
			repX(-500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function buyAndIndent() {
			const frag = new DocumentFragment();
			let r = [];
			slave.devotion = random(10, 15);
			slave.trust = slave.devotion+4;
			slave.oldDevotion = slave.devotion;
			slave.indenture = random(52, 78);
			slave.indentureRestrictions = 2;
			slave.origin = "You took over $his indenture after $he launched a legal complaint against an abusive master.";
			cashX(forceNeg(contractCost), "slaveTransfer");
			r.push(`You offer to simply buy out the indenture contract, thereby acquiring ${him}, to which both parties readily agree. This decision is viewed as incredibly generous by both your arcology's romantically-minded and financially-inclined citizens. For their part, your new servant is hopeful that you will be more considerate of ${his} health, while the former holder is just happy to have ${him} off his hands.`);
			V.arcologies[0].prosperity += 3;
			repX(1500, "event");
			frag.append(App.UI.newSlaveIntro(slave));
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function enslave() {
			const frag = new DocumentFragment();
			let r = [];
			slave.origin = "$He was enslaved after you manipulated $his deal for indentured servitude.";
			slave.devotion = random(-10, -15);
			slave.trust = slave.devotion+4;
			slave.oldDevotion = slave.devotion;
			cashX(forceNeg(contractCost), "slaveTransfer");
			r.push(`You quietly contact the trader and suggest an alternative method of settling the dispute. He is surprised, but agrees readily, chuckling at how the "recalcitrant bitch" is going to be dealt with. To ${his} horror, ${he} finds that your near-total power over deals made in your arcology has been employed to saddle ${him} with additional debts that, under ${his} indentured servitude, ${he} cannot hope to repay. It is then the work of ten minutes to demand payment, and when ${he} cannot pay, demand ${his} body for enslavement. The story of your cunning impresses the slave traders, but is booed by fairer-minded citizens.`);
			V.arcologies[0].prosperity += 5;
			repX(-100, "event");
			frag.append(App.UI.newSlaveIntro(slave));
			App.Events.addParagraph(frag, r);
			return frag;
		}
	}
};


code:
App.Events.JESlaveDisputeMajorityDeal = class JESlaveDisputeMajorityDeal extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.justiceEvents.includes("majority deal"),
		];
	}

	get weight() {
		return V.justiceEvents.length > 2 ? 2 : 1;
	}

	execute(node) {
		let r = [];
		const index = V.justiceEvents.indexOf("majority deal");
		V.justiceEvents.splice(index, 1);
		const contractCost = 20000;
		const slave = GenerateNewSlave(null, {minAge: V.minimumSlaveAge, maxAge: 18, disableDisability: 1});
		slave.origin = "$He was raised to be a slave, since $he was mistakenly thought to be from good slave stock.";
		slave.career = "a slave";
		slave.devotion = random(10, 15);
		slave.trust = slave.devotion;
		slave.oldDevotion = slave.devotion;
		setHealth(slave, jsRandom(80, 90), 0, 0, 0, jsRandom(10, 30));
		if (slave.dick === 0) {
			slave.vagina = 0;
			slave.ovaries = 1;
		} else if (slave.balls === 0) {
			slave.balls = 1;
		}
		slave.anus = 0;
		slave.skill.anal = 0;
		slave.skill.oral = 0;
		slave.skill.whoring = 0;
		slave.skill.vaginal = 0;
		slave.skill.entertainment = 0;

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

		App.Events.drawEventArt(node, slave);
		App.UI.DOM.appendNewElement("p", node, App.Events.jeCommon());
		r.push(`A prominent citizen is accusing a slave school of lying to him about the pedigree of a ${girl} about to reach ${his} majority. ${He}'ll be enslaved once ${he}'s of age, and he owns the rights to ${him}. He produces many messages from the school about ${his} progress; they all reference ${his} excellent bloodline. The slave's genes were sequenced recently for an unrelated treatment, and it appears ${he}'s not the child of the slaves the school stated ${he} was. He angrily demands compensation for the effort he's put into planning for ${him}.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`The school's representative is apologetic, but firm. The school readily admits an error, but he protests that they weren't aware of the confusion, either. They've offered to buy ${him} back, with interest, but reject what they call an exorbitant demand for compensation. They produce the original pedigree, protesting that it shows that they were lied to, too. The slave does resemble the supposed parents closely; only an unusually invasive check would have disclosed the fraud.`);

		App.Events.addParagraph(node, r);

		const choices = [];
		choices.push(new App.Events.Result(`Privately inform both parties you'll settle this in favor of the most generous`, bribe,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the accuser`, accuser,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the trainer`, trainer,));
		choices.push(new App.Events.Result(`Compromise on the compensation and offer to buy out the deal`, buy, `This will cost ${cashFormat(contractCost)} and give you the slave`));
		App.Events.addResponses(node, choices);

		function bribe() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You privately inform both parties you'll settle this in favor of the most generous. You instantly receive two notices of escrow payments contingent on the case going the payer's way. You select the bigger of the two and decide the matter before returning to bed in a good mood. However, the next day it becomes apparent that although he isn't stupid enough to make a public accusation of corruption, the loser is proclaiming that he is not pleased with your administration of justice.`);
			repX(-100, "event");
			cashX(random(150, 200)*10, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function accuser() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You settle the dispute in favor of the prominent accuser. He dabbles in slave breeding himself, and was looking forward to using the slave in question for breeding stock; like many breeders he cares deeply about his stable, and speaks positively in public about how you helped an innocent breeder protect his prize bloodlines. Slave trading to and from your arcology is somewhat lessened however, since the school lets it be known that trading in your arcology is a risk.`);
			V.arcologies[0].prosperity -= 5;
			repX(2500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function trainer() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You settle the dispute in favor of the school, and against the prominent accuser. He dabbles in slave breeding himself, and was looking forward to using the slave in question for breeding stock; like many breeders he cares deeply about his stable, and speaks furiously in public about how you denied an innocent breeder justice against those swindling slave schools. The school, however, passes a good word around the industry that schools trading with your arcology can expect to be protected from frivolous claims.`);
			V.arcologies[0].prosperity += 5;
			repX(-500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function buy() {
			const frag = new DocumentFragment();
			let r = [];
			cashX(forceNeg(contractCost), "slaveTransfer");
			r.push(`You offer to buy out the deal, paying the school and taking the slave yourself, and compromising on the demanded compensation. The citizen was looking forward to using the slave in question for breeding stock; like many breeders he cares deeply about his stable and is mollified by the moderate payment, and speaks kindly in public about how you helped an innocent breeder protect his prize bloodlines. The school sends a positive note around the industry to the effect that schools trading with your arcology can expect to have excessive claims sensibly reduced.`);
			V.arcologies[0].prosperity += 3;
			repX(1500, "event");
			frag.append(App.UI.newSlaveIntro(slave));
			App.Events.addParagraph(frag, r);
			return frag;
		}
	}
};


code:
App.Events.JESlaveDisputeSlaveDeal = class JESlaveDisputeSlaveDeal extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.justiceEvents.includes("slave deal"),
		];
	}

	get weight() {
		return V.justiceEvents.length > 2 ? 2 : 1;
	}

	execute(node) {
		let r = [];
		const index = V.justiceEvents.indexOf("slave deal");
		V.justiceEvents.splice(index, 1);
		const contractCost = 5000;
		const slave = GenerateNewSlave("XX", {
			minAge: 24, maxAge: 42, ageOverridesPedoMode: 1, disableDisability: 1
		});
		slave.origin = "$He sold $himself into slavery to buy medical care for $his daughter.";
		slave.devotion = random(25, 30);
		slave.trust = slave.devotion - 20;
		slave.oldDevotion = slave.devotion;
		setHealth(slave, jsRandom(0, 20));
		slave.piercing.ear.weight = 1;
		slave.vagina = random(1, 2);
		slave.ovaries = 1;
		slave.counter.birthsTotal = 1;
		slave.shouldersTat = either("flowers", "tribal patterns");
		slave.stampTat = either("flowers", "tribal patterns");
		const {
			He,
			he, his, him, himself, woman
		} = getPronouns(slave);

		App.Events.drawEventArt(node, slave);
		App.UI.DOM.appendNewElement("p", node, App.Events.jeCommon());

		r.push(`An older ${woman} who has signed an enslavement contract with a slave trader is accusing her of not living up to the terms. The contract requires that the trader pay the medical costs of the ${woman}'s daughter in return for the ${woman}'s voluntary enslavement. The ${woman} claims that the payments have not been made and the trader is still insisting on enslavement.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`The trader states that the daughter was thought to only have a minor condition, but has proven to be suffering from a serious cancer. She protests that she will lose a great deal of money, and that there's no way she would have made the deal if the ${woman} had been honest with her about how bad ${his} daughter's condition was. The ${woman} responds that ${he} didn't know.`);

		App.Events.addParagraph(node, r);

		const choices = [];
		choices.push(new App.Events.Result(`Privately inform both parties you'll settle this in favor of the most generous`, bribe,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the older ${woman}`, older,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the slave trader`, trader,));
		choices.push(new App.Events.Result(`Offer to buy out the contract`, buy, `This will cost ${cashFormat(contractCost)} and give you the slave`));
		App.Events.addResponses(node, choices);

		function bribe() {
			const frag = new DocumentFragment();
			r = [];
			r.push(`You privately inform both parties you'll settle this in favor of the most generous. You instantly receive a single notice of escrow payment contingent on the case going the payer's way. You select the bigger of the two and decide the matter before returning to bed in a good mood. However, the next day it becomes apparent that although ${he} isn't stupid enough to make a public accusation of corruption, the older ${woman} made use of ${his} few remaining hours of freedom to slander your administration of justice.`);
			repX(-100, "event");
			cashX(random(150, 200) * 10, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function older() {
			const frag = new DocumentFragment();
			r = [];
			r.push(`You settle the dispute in favor of the slave-to-be. ${He} is resigned, knowing that ${he}'s now owned by a woman who almost certainly hates ${him}, but ${his} daughter's treatments are assured. The story gets around quickly, capturing the hearts of more romantic citizens. The angry slave trader leaves the arcology, reducing prosperity.`);
			V.arcologies[0].prosperity -= 5;
			repX(2500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function trader() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You settle the dispute in favor of the slave trader. The story of the mother's enslavement, along with the prompt death of the daughter due to inadequate treatment, gets around the Free Cities, appalling more romantic citizens. The trader lets it be known amongst her peers that you do not brook uppity behavior from poor bitches, and that slave traders can expect to do well in your arcology, increasing prosperity.`);
			V.arcologies[0].prosperity += 5;
			repX(-500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function buy() {
			const frag = new DocumentFragment();
			let r = [];
			cashX(forceNeg(contractCost), "slaveTransfer");
			V.arcologies[0].prosperity += 5;
			repX(2500, "event");
			r.push(`You offer to simply buy out the contract, taking the slave for yourself, letting the slave trader out of her side of the deal, and providing for the daughter's medical care. The trader lets it be known amongst her peers that you will make things right no matter the cost to yourself, increasing prosperity. The story of the mother willing to be enslaved gets around quickly, capturing the hearts of more romantic citizens. The mother, meanwhile, presents ${himself} for enslavement, very grateful that you've saved ${his} daughter's life.`);
			frag.append(App.UI.newSlaveIntro(slave));
			App.Events.addParagraph(frag, r);
			return frag;
		}
	}
};


code:
App.Events.JESlaveDisputeSlaveTraining = class JESlaveDisputeSlaveTraining extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.justiceEvents.includes("slave training"),
			() => V.seeExtreme !== 0,
			() => V.seeDicks !== 0
		];
	}

	get weight() {
		return V.justiceEvents.length > 2 ? 2 : 1;
	}

	execute(node) {
		let r = [];
		const index = V.justiceEvents.indexOf("slave training");
		V.justiceEvents.splice(index, 1);

		const contractCost = 10000;
		const slave = GenerateNewSlave("XY", {disableDisability: 1});
		slave.origin = "You bought out a deal involving $him training to be an expert gelded sex slave.";
		slave.devotion = random(30, 40);
		slave.trust = slave.devotion;
		slave.oldDevotion = slave.devotion;
		setHealth(slave, jsRandom(60, 80), 0, 0, 0, jsRandom(10, 30));
		slave.balls = 0;
		slave.anus = 2;
		slave.skill.anal = 35;
		slave.skill.oral = 35;
		slave.skill.whoring = 35;
		slave.skill.entertainment = 35;
		slave.piercing.nipple.weight = 1;
		slave.piercing.genitals.weight = 1;
		slave.piercing.dick.weight = 1;
		slave.piercing.anus.weight = 1;
		slave.piercing.lips.weight = 1;
		slave.piercing.tongue.weight = 1;
		slave.piercing.ear.weight = 1;
		slave.piercing.nose.weight = 1;
		slave.piercing.eyebrow.weight = 1;
		slave.piercing.navel.weight = 1;
		slave.boobsTat = either("advertisements", "degradation", "rude words");
		slave.buttTat = either("advertisements", "degradation", "rude words");
		slave.vaginaTat = either("advertisements", "degradation", "rude words");
		slave.dickTat = either("advertisements", "degradation", "rude words");
		slave.lipsTat = either("advertisements", "degradation", "rude words");
		slave.anusTat = either("advertisements", "degradation", "rude words");
		slave.shouldersTat = either("advertisements", "degradation", "rude words");
		slave.armsTat = either("advertisements", "degradation", "rude words");
		slave.legsTat = either("advertisements", "degradation", "rude words");
		slave.stampTat = either("advertisements", "degradation", "rude words");
		const {he, him} = getPronouns(slave);

		App.Events.drawEventArt(node, slave);
		App.UI.DOM.appendNewElement("p", node, App.Events.jeCommon());
		r.push(`One of your prominent tenants is accusing another of failing to train a slave for him according to the terms of a slave training contract. He highlights a part of the contract that requires that the slave be expert in "all common sexual skills." He self-righteously declares that the delivered slave has no vaginal skills to speak of, that he doesn't want ${him} as a result, and requests that you release him from the contract.`);
		App.Events.addParagraph(node, r);
		r = [];

		r.push(`The trainer replies with some aspersion that the accuser is technically correct: the slave has no vaginal skills at all. This is, however, due to the fact that the slave has no vagina. He claims that the accuser verbally requested a gelded slave, though there's nothing about that either way in the contract. He protests that he did his best to train an expert gelding, and offers many lengthy videos to prove that he did.`);

		App.Events.addParagraph(node, r);

		const choices = [];
		choices.push(new App.Events.Result(`Privately inform both parties you'll settle this in favor of the most generous`, bribe,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the accuser`, accuser,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the breeder`, trainer,));
		choices.push(new App.Events.Result(`Offer to buy out the deal`, buy, `This will cost ${cashFormat(contractCost)} and give you the slave`));
		App.Events.addResponses(node, choices);

		function bribe() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You privately inform both parties you'll settle this in favor of the most generous. You instantly receive two notices of escrow payments contingent on the case going the payer's way. You select the bigger of the two and decide the matter before returning to bed in a good mood. However, the next day it becomes apparent that although he isn't stupid enough to make a public accusation of corruption, the loser is proclaiming that he is not pleased with your administration of justice.`);
			repX(-100, "event");
			cashX(random(150, 200)*10, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function accuser() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You settle the dispute in favor of the wealthy accuser. He lets you know privately that he recently had a business deal go bad, so he's in a tough cash situation right now; he's so grateful for your assistance in this embarrassing situation that he talks effusively for days to anyone who will listen about your good administration of the arcology. Unfortunately, the furious trainer has packed up his equipment and his gelding and left for another arcology, somewhat reducing prosperity.`);
			V.arcologies[0].prosperity -= 5;
			repX(2500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function trainer() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You settle the dispute in favor of the slave trainer. It transpires that the wealthy accuser was no longer wealthy at all, and was looking to get out of the deal; he's furious, and spends a long day spewing invectives against you to anyone who will listen before decamping back to the old world. The trainer, on the other hand, lets it be known that you support businessmen, who can trust you to look after their interests, increasing prosperity.`);
			V.arcologies[0].prosperity += 5;
			repX(-500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function buy() {
			const frag = new DocumentFragment();
			let r = [];
			cashX(forceNeg(contractCost), "slaveTransfer");
			r.push(`You offer to simply buy out the deal, paying the trainer and taking the slave yourself, and letting the buyer out of the payment. The trainer lets it be known that you support businessmen, who can trust you to ensure they don't come out second best, increasing prosperity. The buyer lets you know privately that he recently had a business deal go bad, so he's in a tough cash situation right now; he's so grateful for your assistance in this embarrassing situation that he talks effusively for days to anyone who will listen about your discreet administration of the arcology. The slave, meanwhile, arrives at your penthouse, rather hopeful that ${he}'s going to a good master.`);
			V.arcologies[0].prosperity += 5;
			repX(2500, "event");
			App.Events.addParagraph(frag, r);
			frag.append(App.UI.newSlaveIntro(slave));
			return frag;
		}
	}
};


code:
App.Events.JESlaveVirginityDeal = class JESlaveVirginityDeal extends App.Events.BaseEvent {
	eventPrerequisites() {
		return [
			() => V.justiceEvents.includes("virginity deal"),
		];
	}

	get weight() {
		return V.justiceEvents.length > 2 ? 2 : 1;
	}

	execute(node) {
		let r = [];
		const index = V.justiceEvents.indexOf("virginity deal");
		V.justiceEvents.splice(index, 1);

		const contractCost = 10000;
		const slave = GenerateNewSlave(null, {maxAge: 22, disableDisability: 1});
		slave.origin = "You bought out a deal for $his sale after the seller took $his virginity and the buyer no longer wanted $him.";
		slave.counter.publicUse += 10;
		slave.devotion = random(25, 30);
		slave.trust = slave.devotion-20;
		slave.oldDevotion = slave.devotion;
		setHealth(slave, jsRandom(0, 20));
		slave.anus = 2;
		if (slave.dick === 0) {
			slave.vagina = 2;
			slave.ovaries = 1;
			if (isFertile(slave) && V.seePreg === 1) {
				knockMeUp(slave, 100, 2, -2);
			}
		}
		const {he, him} = getPronouns(slave);

		App.Events.drawEventArt(node, slave);
		App.UI.DOM.appendNewElement("p", node, App.Events.jeCommon());
		r.push(`A wealthy slaveowner, clearly nursing a ferocious hangover, is accusing a less prominent citizen of refusing to honor the terms of a sale they signed in the early hours of the morning. Already shaking your head, you pull up the security logs with his permission. You verify that yes, indeed, they're visible at a loud party hosted by the wealthy slaveowner, talking over a tablet for a long time before shaking hands and signing.`);
		App.Events.addParagraph(node, r);
		r = [];
		r.push(`The putative buyer protests that though the terms of sale don't show it, their conversation before the sale focused on the slave's virginity. The logs show that this, too, is true. And then, he rages, the slaveowner got even drunker, and brought the slave up to join the party, encouraging other guests to gangbang ${him}. The logs show this too; the slave is definitely not a virgin any longer. The would-be buyer says he understands that he should have gotten the part about the virginity in writing and guaranteed up until he got his hands on ${him}, but requests that you honor the spirit of the deal by letting him out of a contract to buy a now-ruined slave.`);

		App.Events.addParagraph(node, r);

		const choices = [];
		choices.push(new App.Events.Result(`Privately inform both parties you'll settle this in favor of the most generous`, bribe,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the prospective buyer`, buyer,));
		choices.push(new App.Events.Result(`Settle the dispute in favor of the prominent slaveowner`, owner,));
		choices.push(new App.Events.Result(`Offer to buy out the contract`, buy, `This will cost ${cashFormat(contractCost)} and give you the slave`));
		App.Events.addResponses(node, choices);

		function bribe() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You privately inform both parties you'll settle this in favor of the most generous. You instantly receive two notices of escrow payment contingent on the case going the payer's way. You select the bigger of the two and decide the matter before returning to bed in a good mood. However, the next day it becomes apparent that although he isn't stupid enough to make a public accusation of corruption, the buyer is furious at paying virgin prices for a defiled slave, and is privately slandering your administration of justice.`);
			repX(-100, "event");
			cashX(random(150, 200)*10, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function buyer() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`What's most important is the justice of the outcome. You settle the dispute in favor of the buyer, who would otherwise be forced to buy something he did not mean to pay for. He lets it be known far and wide that you are willing to stand up for what's right, no matter what and no matter who, improving your reputation. The angry seller, now afflicted with a devalued slave in addition to a bad headache, lets his group of friends know that social superiors have no advantage at justice here. They become more reticent about deal-making in your arcology, damaging its prosperity.`);
			V.arcologies[0].prosperity -= 5;
			repX(2500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function owner() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`A deal is a deal; buyer beware. You settle the dispute in favor of the slaveowner. He lets it be known amongst his peers that you do not let social inferiors insist on justice against their betters. Citizens of quality become more willing to consider deal-making in your arcology, increasing prosperity. On the other hand, the angry buyer shows himself to be not a person to treat lightly, either; he maintains a malicious whispering campaign to the effect that your administration of justice is fatally biased.`);
			V.arcologies[0].prosperity += 5;
			repX(-500, "event");
			App.Events.addParagraph(frag, r);
			return frag;
		}

		function buy() {
			const frag = new DocumentFragment();
			let r = [];
			r.push(`You offer to simply buy out the contract, taking the slave for yourself. This lets the buyer out of buying ${him}, and the slaveowner gets his money; but it soon becomes apparent that what both of them were really looking for is an opportunity to put one over on the other. Neither is pleased to be denied a petty victory, but they both have the sense to keep their mouths shut. The poor slave, meanwhile, appears in the penthouse entryway, hopeful that ${he}'s been lucky enough to end up in a less abusive situation.`);
			App.Events.addParagraph(frag, r);
			frag.append(App.UI.newSlaveIntro(slave));
			return frag;
		}
	}
};