code:
App.Desc.family = (function() {
	/** From a list of slaves, return their names, comma-separated and appended with "and" if necessary
	 * @param {Array<App.Entity.SlaveState>} slaveList
	 * @returns {string}
	 */
	function slaveListToText(slaveList) {
		return slaveList.map(s => s.slaveName).reduce((res, ch, i, arr) => res + (i === arr.length - 1 ? ' and ' : ', ') + ch);
	}

	/** See if an ID refers to a valid, active slave.  This will return false for slaves that no longer exist or have not yet been created.
	 * @param {number} slaveID
	 * @returns {boolean}
	 */
	function validSlaveID(slaveID) {
		return slaveID > 0 && _.isObject(getSlave(slaveID));
	}

	/** From a slave ID, return text describing that slave (even if they aren't currently your slave) to use in place of their name
	 * @param {number} slaveID
	 * @returns {string}
	 */
	function knownSlave(slaveID) {
		if (validSlaveID(slaveID)) {
			return getSlave(slaveID).slaveName;
		} else if (slaveID in V.missingTable) {
			return "your former slave " + V.missingTable[slaveID].slaveName;
		} else {
			return "another slave";
		}
	}

	/** Splits an array of slaves by sex (nieces/nephews, aunts/uncles, brothers/sisters, etc)
	 * @param {Array<App.Entity.SlaveState>} slaves
	 * @returns {{m: Array<App.Entity.SlaveState>, f: Array<App.Entity.SlaveState>}}
	 */
	function splitBySex(slaves) {
		let r = {m: [], f: []};
		for (const s of slaves) {
			if (s.genes === "XX") {
				r.f.push(s);
			} else {
				r.m.push(s);
			}
		}
		return r;
	}

	/** Describe the members of a character's family.
	 * @param {App.Entity.SlaveState} character (pass V.PC to get the PC's special family summary)
	 * @returns {string}
	 */
	function familySummary(character) {
		if (character === V.PC) {
			return PCFamilySummary();
		} else {
			return slaveFamilySummary(character);
		}
	}

	/** Describe the members of a slave's family.
	 * @param {App.Entity.SlaveState} slave
	 * @returns {string}
	 */
	function slaveFamilySummary(slave) {
		let r = [];

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

		/* PC parentage */
		if (slave.ID === V.PC.mother && slave.ID === V.PC.father) {
			r.push(`${He} is <span class="lightgreen">both your mother and father;</span> ${he} impregnated ${himself} with you.`);
		} else if (slave.ID === V.PC.mother) {
			r.push(`${He} is <span class="lightgreen">your mother.</span>`);
		} else if (slave.ID === V.PC.father) {
			r.push(`${He} is <span class="lightgreen">your father.</span>`);
		}

		if (slave.father === -1 && slave.mother === -1) {
			r.push(`${He}'s <span class="lightgreen">your child;</span> you knocked yourself up and gave birth to ${him}.`);
		} else if (slave.father === slave.mother && (slave.father > 0 || (slave.father in V.missingTable && V.showMissingSlaves))) {
			r.push(`${He} was <span class="lightgreen">both fathered and mothered by ${knownSlave(slave.father)}.</span>`);
		}

		if (slave.father === -1 && slave.mother !== -1) {
			r.push(`${He}'s <span class="lightgreen">your child;</span> you knocked ${his} mother up.`);
		} else if ((slave.father > 0 || (slave.father in V.missingTable && V.showMissingSlaves)) && slave.father !== slave.mother) {
			r.push(`${He} was <span class="lightgreen">fathered by ${knownSlave(slave.father)}'s</span> virile dick.`);
		}

		if (slave.father !== -1 && slave.mother === -1) {
			r.push(`${He}'s <span class="lightgreen">your child;</span> you gave birth to ${him}.`);
		} else if ((slave.mother > 0 || (slave.mother in V.missingTable && V.showMissingSlaves)) && slave.father !== slave.mother) {
			r.push(`${He} was <span class="lightgreen">born from ${knownSlave(slave.mother)}'s</span> fertile womb.`);
		}

		let children = V.slaves.filter((s) => slave.ID === s.father);
		if (children.length > 2) {
			r.push(`${He} <span class="lightgreen">fathered ${slaveListToText(children)}.</span>`);
		} else if (children.length > 1) {
			r.push(`${He} <span class="lightgreen">fathered a pair of your slaves: ${slaveListToText(children)}.</span>`);
		} else if (children.length > 0) {
			r.push(`${He} <span class="lightgreen">fathered a single slave of yours: ${slaveListToText(children)}.</span>`);
		}

		children = V.slaves.filter((s) => slave.ID === s.mother);
		if (children.length > 2) {
			r.push(`${He} <span class="lightgreen">gave birth to ${slaveListToText(children)}.</span>`);
		} else if (children.length > 1) {
			r.push(`${He} <span class="lightgreen">gave birth to a pair of your slaves: ${slaveListToText(children)}.</span>`);
		} else if (children.length > 0) {
			r.push(`${He} <span class="lightgreen">gave birth to a single slave of yours: ${slaveListToText(children)}.</span>`);
		}

		function getParentIndices(slaveID) {
			if (slaveID === V.PC.ID) {
				return {mi: V.slaveIndices[V.PC.mother], fi: V.slaveIndices[V.PC.father]};
			} else {
				const target = getSlave(slaveID);
				if (target) {
					return {mi: V.slaveIndices[target.mother], fi: V.slaveIndices[target.father]};
				}
			}
			return {mi: undefined, fi: undefined};
		}

		if (V.showDistantRelatives) {
			/* grandparents */
			const mi = V.slaveIndices[slave.mother];
			const fi = V.slaveIndices[slave.father];
			const {mi: mmi, fi: fmi} = getParentIndices(slave.mother);
			const {mi: mfi, fi: ffi} = getParentIndices(slave.father);
			if ((jsDef(mi) || jsDef(fi)) && !jsDef(mmi) && !jsDef(fmi) && !jsDef(mfi) && !jsDef(ffi)) {
				if (jsDef(mi)) {
					if ((jsDef(fi)) && mi === fi) {
						if (V.PC.ID === V.slaves[mi].mother && V.PC.ID === V.slaves[fi].father) {
							r.push(`${He} is <span class="lightgreen">your grandchild.</span> You impregnated yourself with ${his} sole biological parent.`);
						} else if (V.PC.ID === V.slaves[mi].mother) {
							r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to ${his} sole biological parent.`);
						} else if (V.PC.ID === V.slaves[fi].father) {
							r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered ${his} sole biological parent.`);
						}
					} else if ((jsDef(fi)) && V.PC.ID === V.slaves[mi].mother && V.PC.ID === V.slaves[fi].mother) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to both of ${his} parents.`);
					} else if ((jsDef(fi)) && V.PC.ID === V.slaves[mi].father && V.PC.ID === V.slaves[fi].father) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered both of ${his} parents.`);
					} else if (V.PC.ID === V.slaves[mi].mother) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to ${his} mother.`);
					} else if (V.PC.ID === V.slaves[mi].father) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered ${his} mother.`);
					}
				} else if (jsDef(fi)) {
					if (V.PC.ID === V.slaves[fi].mother) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to ${his} father.`);
					} else if (V.PC.ID === V.slaves[fi].father) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered ${his} father.`);
					}
				}
			} else {
				if ((jsDef(mmi)) && (jsDef(ffi)) && mmi === ffi) {
					r.push(`${His} sole <span class="lightgreen">grandparent is ${V.slaves[mmi].slaveName}.</span>`);
				} else {
					if ((jsDef(mmi)) && (jsDef(mfi)) && mmi === mfi) {
						r.push(`${His} sole <span class="lightgreen">grandmother is ${V.slaves[mmi].slaveName}.</span>`);
					} else {
						if (jsDef(mmi)) {
							r.push(`${His} maternal <span class="lightgreen">grandmother is ${V.slaves[mmi].slaveName}.</span>`);
						}
						if (jsDef(mfi)) {
							r.push(`${His} paternal <span class="lightgreen">grandmother is ${V.slaves[mfi].slaveName}.</span>`);
						}
					}
					if ((jsDef(fmi)) && (jsDef(ffi)) && fmi === ffi) {
						r.push(`${His} sole <span class="lightgreen">grandfather is ${V.slaves[ffi].slaveName}.</span>`);
					} else {
						if (jsDef(fmi)) {
							r.push(`${His} maternal <span class="lightgreen">grandfather is ${V.slaves[fmi].slaveName}.</span>`);
						}
						if (ffi) {
							r.push(`${His} paternal <span class="lightgreen">grandfather is ${V.slaves[ffi].slaveName}.</span>`);
						}
					}
				}
			}

			/* PC grandparents - determines if the current slave is your grandparent */
			const pcMother = getSlave(V.PC.mother);
			const pcFather = getSlave(V.PC.father);
			if (jsDef(pcMother)) {
				if ((jsDef(pcFather)) && pcMother === pcFather) {
					if (slave.ID === pcMother.mother && slave.ID === pcFather.father) {
						r.push(`${He} is <span class="lightgreen">your sole grandparent.</span> ${He} impregnated ${himself} with your sole parent ${pcMother.slaveName} who in turn impregnated themselves with you.`);
					} else if (slave.ID === pcMother.mother) {
						r.push(`${He} is <span class="lightgreen">your sole grandmother.</span> ${He} gave birth to ${pcMother.slaveName} who in turn impregnated themselves with you.`);
					} else if (slave.ID === pcFather.father) {
						r.push(`${He} is <span class="lightgreen">your sole grandfather.</span> ${He} fathered ${pcFather.slaveName} who in turn impregnated themselves with you.`);
					}
				} else if ((jsDef(pcFather)) && slave.ID === pcMother.mother && slave.ID === pcFather.mother) {
					r.push(`${He} is <span class="lightgreen">your sole grandmother.</span> ${He} gave birth to both of your parents, ${pcMother.slaveName} and ${pcFather.slaveName}.`);
				} else if ((jsDef(pcFather)) && slave.ID === pcMother.father && slave.ID === pcFather.father) {
					r.push(`${He} is <span class="lightgreen">your sole grandfather.</span> ${He} fathered both of your parents, ${pcFather.slaveName} and ${pcMother.slaveName}.`);
				} else if (slave.ID === pcMother.mother) {
					r.push(`${He} is <span class="lightgreen">your maternal grandmother.</span>`);
				} else if (slave.ID === pcMother.father) {
					r.push(`${He} is <span class="lightgreen">your maternal grandfather.</span>`);
				}
			} else if (jsDef(pcFather)) {
				if (slave.ID === pcFather.mother) {
					r.push(`${He} is <span class="lightgreen">your paternal grandmother.</span>`);
				} else if (slave.ID === pcFather.father) {
					r.push(`${He} is <span class="lightgreen">your paternal grandfather.</span>`);
				}
			}

			/* grandchild - determines how many grandchildren the current slave has */
			children = V.slaves.filter((s) => isGrandparentP(s, slave));
			if (children.length > 0) {
				r.push(`${He} has`);
				if (children.length > 2) {
					r.push(`<span class="lightgreen">many grandchildren, ${slaveListToText(children)}, amongst your slaves.</span>`);
				} else if (children.length > 1) {
					r.push(`<span class="lightgreen">two grandchildren, ${slaveListToText(children)}, amongst your slaves.</span>`);
				} else {
					r.push(`a <span class="lightgreen">grandchild, ${slaveListToText(children)}, as your slave.</span>`);
				}
			}

			/* PC aunt and uncle - determines how many aunts and uncles you have */
			if (isAunt(V.PC, slave)) {
				const {m: uncles, f: aunts} = splitBySex(V.slaves.filter((s) => s.ID !== slave.ID && isAunt(V.PC, s)));

				r.push(`${He} is`);
				if (slave.genes === "XX") {
					if (aunts.length > 0) {
						r.push(`<span class="lightgreen">your aunt along with ${slaveListToText(aunts)}.</span>`);
					} else {
						r.push(`<span class="lightgreen">your aunt.</span>`);
					}
				} else {
					if (uncles.length > 0) {
						r.push(`<span class="lightgreen">your uncle along with ${slaveListToText(uncles)}.</span>`);
					} else {
						r.push(`<span class="lightgreen">your uncle.</span>`);
					}
				}
			}

			/* aunt and uncle - determines how many aunts and uncles a slave has*/
			const {m: uncles, f: aunts} = splitBySex(V.slaves.filter((s) => isAunt(slave, s)));

			if (aunts.length > 0) {
				r.push(`${He} has`);
				if (aunts.length > 2) {
					r.push(`<span class="lightgreen">many aunts, ${slaveListToText(aunts)}.</span>`);
				} else if (aunts.length > 1) {
					r.push(`<span class="lightgreen">two aunts, ${slaveListToText(aunts)}.</span>`);
				} else {
					r.push(`<span class="lightgreen">an aunt, ${slaveListToText(aunts)}.</span>`);
				}
			}
			if (uncles.length > 0) {
				r.push(`${He} has`);
				if (uncles.length > 2) {
					r.push(`<span class="lightgreen">many uncles, ${slaveListToText(uncles)}.</span>`);
				} else if (uncles.length > 1) {
					r.push(`<span class="lightgreen">two uncles, ${slaveListToText(uncles)}.</span>`);
				} else {
					r.push(`<span class="lightgreen">an uncle, ${slaveListToText(uncles)}.</span>`);
				}
			}

			/* PC niece and nephew - determines how many nieces and nephews you have*/
			if (isAunt(slave, V.PC)) {
				const {m: nephews, f: nieces} = splitBySex(V.slaves.filter((s) => s.ID !== slave.ID && isAunt(s, V.PC)));

				r.push(`${He} is`);
				if (slave.genes === "XX") {
					if (nieces.length > 0) {
						r.push(`<span class="lightgreen">your niece along with ${slaveListToText(nieces)}.</span>`);
					} else {
						r.push(`<span class="lightgreen">your niece.</span>`);
					}
				} else {
					if (nephews.length > 0) {
						r.push(`<span class="lightgreen">your nephew along with ${slaveListToText(nephews)}.</span>`);
					} else {
						r.push(`<span class="lightgreen">your nephew.</span>`);
					}
				}
			}

			/* niece and nephew - determines how many nieces and nephews a slave has*/
			const {m: nephews, f: nieces} = splitBySex(V.slaves.filter((s) => isAunt(s, slave)));

			if (nieces.length > 0) {
				r.push(`${He} has`);
				if (nieces.length > 2) {
					r.push(`<span class="lightgreen">many nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
				} else if (nieces.length > 1) {
					r.push(`<span class="lightgreen">two nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
				} else {
					r.push(`<span class="lightgreen">a niece, ${slaveListToText(nieces)}, who is your slave.</span>`);
				}
			}
			if (nephews.length > 0) {
				r.push(`${He} has`);
				if (nephews.length > 2) {
					r.push(`<span class="lightgreen">many nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
				} else if (nephews.length > 1) {
					r.push(`<span class="lightgreen">two nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
				} else {
					r.push(`<span class="lightgreen">a nephew, ${slaveListToText(nephews)}, who is your slave.</span>`);
				}
			}
		} /* end distant relatives toggle check */

		let	twins = [];
		let sisters = [];
		let brothers = [];
		let halfSisters = [];
		let halfBrothers = [];
		let cousins = [];

		for (const s of V.slaves) {
			let sisterCheck = areSisters(s, slave);
			if (sisterCheck === 1) {
				twins.push(s);
			}
			if (sisterCheck === 2) {
				(s.genes === "XX" ? sisters : brothers).push(s);
			}
			if (sisterCheck === 3) {
				(s.genes === "XX" ? halfSisters : halfBrothers).push(s);
			}
			if (V.showDistantRelatives) {
				if (areCousins(s, slave)) {
					cousins.push(s);
				}
			}
		}

		/* PC twin - determines how many twins you have */
		if (areSisters(slave, V.PC) === 1) {
			r.push(He);
			if (twins.length > 1) {
				r.push(`<span class="lightgreen">shared a cramped womb with you, ${slaveListToText(twins)}.</span>`);
			} else if (twins.length > 0) {
				r.push(`is <span class="lightgreen">your twin along with ${slaveListToText(twins)}.</span>`);
			} else {
				r.push(`is <span class="lightgreen">your twin.</span>`);
			}
			twins = []; // clear it so we don't output it a second time
		}

		/* PC sister - determines how many sisters you have*/
		if (areSisters(slave, V.PC) === 2 && slave.genes === "XX") {
			r.push(`${He} is`);
			if (sisters.length > 0) {
				r.push(`<span class="lightgreen">your ${sister} along with ${slaveListToText(sisters)}.</span>`);
			} else {
				r.push(`<span class="lightgreen">your ${sister}.</span>`);
			}
			sisters = []; // clear it so we don't output it a second time
		}

		/* PC brother - determines how many brothers you have*/
		if (areSisters(slave, V.PC) === 2 && slave.genes === "XY") {
			r.push(`${He} is`);
			if (brothers.length > 0) {
				r.push(`<span class="lightgreen">your ${sister} along with ${slaveListToText(brothers)}.</span>`);
			} else {
				r.push(`<span class="lightgreen">your ${sister}.</span>`);
			}
			brothers = []; // clear it so we don't output it a second time
		}

		/* PC half-sister - determines how many half-sisters you have*/
		if (areSisters(slave, V.PC) === 3 && slave.genes === "XX") {
			r.push(`${He} is`);
			if (halfSisters.length > 0) {
				r.push(`<span class="lightgreen">is your half-${sister} along with ${slaveListToText(halfSisters)}.</span>`);
			} else {
				r.push(`<span class="lightgreen">your half-${sister}.</span>`);
			}
			halfSisters = []; // clear it so we don't output it a second time
		}

		/* PC half-brother - determines how many half-brothers you have*/
		if (areSisters(slave, V.PC) === 3 && slave.genes === "XY") {
			r.push(`${He} is`);
			if (halfBrothers.length > 0) {
				r.push(`<span class="lightgreen">is your half-${sister} along with ${slaveListToText(halfBrothers)})>>.</span>`);
			} else {
				r.push(`<span class="lightgreen">your half-${sister}.</span>`);
			}
			halfBrothers = []; // clear it so we don't output it a second time
		}

		/* twins? - determines how many twins a slave has*/
		if (twins.length > 0) {
			r.push(`${He}`);
			if (twins.length > 2) {
				r.push(`<span class="lightgreen">shared a cramped womb with ${slaveListToText(twins)}.</span>`);
			} else if (twins.length > 1) {
				r.push(`is <span class="lightgreen">one of a set of triplets; ${slaveListToText(twins)}</span> complete the trio.`);
			} else {
				r.push(`is <span class="lightgreen">twins with ${twins[0].slaveName}.</span>`);
			}
		}

		/* sister - determines how many sisters a slave has*/
		if (sisters.length > 0) {
			const sister2 = getPronouns(sisters[0]).sister;
			if (sisters.length > 1) {
				r.push(`<span class="lightgreen">${slaveListToText(sisters)} are ${his} ${sister2}s.</span>`);
			} else {
				r.push(`<span class="lightgreen">${sisters[0].slaveName} is ${his} ${sister2}.</span>`);
			}
		}

		/* brother - determines how many brothers a slave has*/
		if (brothers.length > 0) {
			const sister2 = getPronouns(brothers[0]).sister;
			if (brothers.length > 1) {
				r.push(`<span class="lightgreen">${slaveListToText(brothers)} are ${his} ${sister2}s.</span>`);
			} else {
				r.push(`<span class="lightgreen">${brothers[0].slaveName} is ${his} ${sister2}.</span>`);
			}
		}

		/* half-sister - determines how many half-sisters a slave has*/
		if (halfSisters.length > 0) {
			const sister2 = getPronouns(halfSisters[0]).sister;
			if (halfSisters.length > 1) {
				r.push(`<span class="lightgreen">${slaveListToText(halfSisters)} are half-${sister2}s to ${him}.</span>`);
			} else {
				r.push(`<span class="lightgreen">${halfSisters[0].slaveName} is a half-${sister2} to ${him}.</span>`);
			}
		}

		/* half-brother - determines how many half-brothers a slave has*/
		if (halfBrothers.length > 0) {
			const sister2 = getPronouns(halfBrothers[0]).sister;
			if (halfBrothers.length > 1) {
				r.push(`<span class="lightgreen">${slaveListToText(halfBrothers)} are half-${sister2}s to ${him}.</span>`);
			} else if (halfBrothers.length > 0) {
				r.push(`<span class="lightgreen">${halfBrothers[0].slaveName} is a half-${sister2} to ${him}.</span>`);
			}
		}

		if (V.showDistantRelatives) {
			/* PC cousin - determines how many cousins you have*/
			if (areCousins(slave, V.PC)) {
				const PCcousins = V.slaves.filter((s) => s.ID !== slave.ID && areCousins(V.PC, s));
				r.push(`${He} is`);
				if (PCcousins.length > 0) {
					r.push(`<span class="lightgreen">your cousin along with ${slaveListToText(PCcousins)}.</span>`);
				} else {
					r.push(`<span class="lightgreen">your cousin.</span>`);
				}
			}

			/* cousin - determines how many cousins a slave has*/
			if (cousins.length > 1) {
				r.push(`<span class="lightgreen">${slaveListToText(cousins)} are cousins to ${him}.</span>`);
			} else if (cousins.length > 0) {
				r.push(`<span class="lightgreen">${cousins[0].slaveName} is a cousin to ${him}.</span>`);
			}
		}

		if (slave.clone) {
			r.push(`${He} is`);
			if (slave.cloneID === -1) {
				r.push(`your clone.`);
			} else {
				r.push(`a clone of ${slave.clone}.`);
			}
		}

		if (V.cheatMode) {
			r.push(`${He} has ${numberWithPlural(slave.sisters, "sister")} and ${numberWithPlural(slave.daughters, "daughter")}.`);
		}

		return r.join(" ");
	}

	/** Describe the members of the PC's family.
	 * @returns {string}
	 */
	function PCFamilySummary() {
		let r = [];

		r.push(`<br>Your family records show that:`);

		/* Player parents, lists both your parents, or just one. */
		let parents = [];
		if (V.showMissingSlaves) {
			if (V.PC.mother in V.missingTable) {
				parents.push(V.missingTable[V.PC.mother]);
			}
			if (V.PC.father in V.missingTable && (V.PC.father !== V.PC.mother)) {
				parents.push(V.missingTable[V.PC.father]);
			}
		}
		parents.concat(V.slaves.filter((s) => isParentP(V.PC, s)));

		if (parents.length > 1) {
			r.push(`<br>Your parents are <span class="lightgreen">${knownSlave(parents[0].ID)} and ${knownSlave(parents[1].ID)}.</span>`);
		} else if (parents.length > 0) {
			if (V.PC.father === V.PC.mother) {
				/* apparently we don't keep pronoun records in the missing parents table??? */
				const himself = jsDef(parents[0].pronoun) ? getPronouns(parents[0]).himself : "herself";
				r.push(`<br>Your parent is <span class="lightgreen">${knownSlave(parents[0].ID)},</span> who impregnated ${himself} with you.`);
			} else {
				r.push(`<br>You know one of your parents, <span class="lightgreen">${knownSlave(parents[0].ID)}.</span>`);
			}
		}

		/* Player aunts and uncles */
		if (V.showDistantRelatives) {
			const {m: uncles, f: aunts} = splitBySex(V.slaves.filter((s) => isAunt(V.PC, s)));

			if (aunts.length > 0) {
				r.push(`<br>You have`);
				if (aunts.length > 2) {
					r.push(`<span class="lightgreen">many aunts, ${slaveListToText(aunts)}.</span>`);
				} else if (aunts.length > 1) {
					r.push(`<span class="lightgreen">two aunts, ${slaveListToText(aunts)}.</span>`);
				} else {
					r.push(`<span class="lightgreen">an aunt, ${slaveListToText(aunts)}.</span>`);
				}
			}
			if (uncles.length > 0) {
				r.push(`<br>You have`);
				if (uncles.length > 2) {
					r.push(`<span class="lightgreen">many uncles, ${slaveListToText(uncles)}.</span>`);
				} else if (uncles.length > 1) {
					r.push(`<span class="lightgreen">two uncles, ${slaveListToText(uncles)}.</span>`);
				} else {
					r.push(`<span class="lightgreen">an uncle, ${slaveListToText(uncles)}.</span>`);
				}
			}
		}

		let	twins = [];
		let sisters = [];
		let brothers = [];
		let halfSisters = [];
		let halfBrothers = [];
		let cousins = [];

		for (const s of V.slaves) {
			let sisterCheck = areSisters(s, V.PC);
			if (sisterCheck === 1) {
				twins.push(s);
			}
			if (sisterCheck === 2) {
				(s.genes === "XX" ? sisters : brothers).push(s);
			}
			if (sisterCheck === 3) {
				(s.genes === "XX" ? halfSisters : halfBrothers).push(s);
			}
			if (V.showDistantRelatives) {
				if (areCousins(s, V.PC)) {
					cousins.push(s);
				}
			}
		}

		if (twins.length > 1) {
			r.push(`<br>You are <span class="lightgreen">twins with ${slaveListToText(twins)}.</span>`);
		} else if (twins.length > 0) {
			r.push(`<br>Your twin is <span class="lightgreen">${twins[0].slaveName}.</span>`);
		}

		if (sisters.length > 1) {
			r.push(`<br><span class="lightgreen">${slaveListToText(sisters)}</span> are your sisters.`);
		} else if (sisters.length > 0) {
			const {sister} = getPronouns(sisters[0]);
			r.push(`<br>Your ${sister} is <span class="lightgreen">${sisters[0].slaveName}.</span>`);
		}

		if (brothers.length > 1) {
			r.push(`<br><span class="lightgreen">${slaveListToText(brothers)}</span> are your brothers.`);
		} else if (brothers.length > 0) {
			const {sister} = getPronouns(brothers[0]);
			r.push(`<br>Your ${sister} is <span class="lightgreen">${brothers[0].slaveName}.</span>`);
		}

		if (halfSisters.length > 1) {
			r.push(`<br><span class="lightgreen">${slaveListToText(halfSisters)}</span> are your half-sisters.`);
		} else if (halfSisters.length > 0) {
			const {sister} = getPronouns(halfSisters[0]);
			r.push(`<br>You have one half-${sister}, <span class="lightgreen">${halfSisters[0].slaveName}.</span>`);
		}

		if (halfBrothers.length > 1) {
			r.push(`<br><span class="lightgreen">${slaveListToText(halfBrothers)}</span> are your half-brothers.`);
		} else if (halfBrothers.length > 0) {
			const {sister} = getPronouns(halfBrothers[0]);
			r.push(`<br>You have one half-${sister}, <span class="lightgreen">${halfBrothers[0].slaveName}.</span>`);
		}

		if (V.showDistantRelatives) {
			if (cousins.length > 1) {
				r.push(`<br><span class="lightgreen">${slaveListToText(cousins)}</span> are your cousins.`);
			} else if (cousins.length > 0) {
				r.push(`<br>You have one cousin, <span class="lightgreen">${cousins[0].slaveName}.</span>`);
			}
		}

		/* Player nieces and nephews */
		if (V.showDistantRelatives) {
			const {m: nephews, f: nieces} = splitBySex(V.slaves.filter((s) => isAunt(s, V.PC)));

			if (nieces.length > 0) {
				r.push(`<br>You have`);
				if (nieces.length > 2) {
					r.push(`<span class="lightgreen">many nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
				} else if (nieces.length > 1) {
					r.push(`<span class="lightgreen">two nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
				} else {
					r.push(`<span class="lightgreen">a niece, ${slaveListToText(nieces)}, who is your slave.</span>`);
				}
			}
			if (nephews.length > 0) {
				r.push(`<br>You have`);
				if (nephews.length > 2) {
					r.push(`<span class="lightgreen">many nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
				} else if (nephews.length > 1) {
					r.push(`<span class="lightgreen">two nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
				} else {
					r.push(`<span class="lightgreen">a nephew, ${slaveListToText(nephews)}, who is your slave.</span>`);
				}
			}
		}

		/* Player is Father, lists children you fathered */
		let children = V.slaves.filter((s) => s.father === V.PC.ID);
		if (children.length > 0) {
			r.push(`<br>You fathered ${num(children.length)} of your slaves, <span class="lightgreen">${slaveListToText(children)}.</span>`);
		}

		/* Player is Mother, lists birthed children */
		children = V.slaves.filter((s) => s.mother === V.PC.ID);
		if (children.length > 0) {
			r.push(`<br>You gave birth to ${num(children.length)} of your slaves, <span class="lightgreen">${slaveListToText(children)}.</span>`);
		}

		/* Player is grandparent */
		if (V.showDistantRelatives) {
			children = V.slaves.filter((s) => isGrandparentP(s, V.PC));
			if (children.length > 0) {
				r.push(`<br>You have ${num(children.length)} grandchildren as your slaves, <span class="lightgreen">${slaveListToText(children)}.</span>`);
			}
		}

		if (V.cheatMode) {
			r.push(`<br>You have ${numberWithPlural(V.PC.sisters, "sister")} and ${numberWithPlural(V.PC.daughters, "daughter")}.`);
		}

		return r.join(" ");
	}

	return familySummary;
})();


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
		organs();
		prosthetics();
		nursery();
		food();
		PC();

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

	function resetSlaveMarkets() {
		V.gingering = 0;
		delete V.slaveMarket;
		for (const school of ["TSS", "GRI", "SCP", "LDE", "TGA", "HA", "TFS", "TCR", "NUL"]) {
			V[school].schoolSale = 0;
		}
	}

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

	function slavePrep(s) {
		if (s.inflationMethod === 1 || s.inflationMethod === 2) {
			if (s.inflationType === "milk") {
				V.inflatedSlavesMilk++;
			} else if (s.inflationType === "cum") {
				V.inflatedSlavesCum++;
			}
		}
		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.sexualOpeness === 1) {
			V.penetrativeUseWeight += 1;
		}
	}

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

	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.HGEnergy = 0;
		V.HGCum = 0;
		V.HGSlaveSuccess = 0;
		V.HeadGirl = 0;
		V.Recruiter = 0;
		V.Madam = 0;
		V.unMadam = 0;
		V.madamCashBonus = 0;
		V.whorePriceAdjustment = {};
		V.DJ = 0;
		V.unDJ = 0;
		V.DJRepBonus = 0;
		V.Milkmaid = 0;
		V.Farmer = 0;
		V.Schoolteacher = 0;
		V.Wardeness = 0;
		V.Concubine = 0;
		V.Matron = 0;
		V.Nurse = 0;
		V.Bodyguard = 0;
		V.StudID = 0;
		V.StudCum = 0;
		V.fuckSlaves = 0;
		V.freeSexualEnergy = 0;
		V.publicServants = 0;
		V.cumSlaves = 0;
		V.averageDick = 0;
		V.slavesWithWorkingDicks = 0;
		V.slaveJobValues = {};
	}

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

repo_name: KnightBoulegard/fc

license: mit


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) {
			infoDiv.remove();
			infoDiv = null;
			setTimeout(LoadScreen.unlock(loadLockID), 0);
			loadLockID = -1;
		}
	}

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


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) { // 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;

		// 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) / 3) + bonus_modifiers > 40 / 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 += ` ${V.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 favourable 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 (V.Nurse !== 0) {
		const nurseSkill = setup.nurseCareers.includes(V.Nurse.career) ? 200 : V.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.Madam !== 0 && (slave.assignment === Job.BROTHEL || (slave.assignment === Job.WHORE && V.brothel > 0 && V.universalRulesFacilityWork === 1 && V.brothelSpots > 0))) {
		return true;
	} else if (V.DJ !== 0 && (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)) {
			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
			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.MILKED].includes(slave.assignment)) {
			if (slave.devotion > 20) {
				assignment += 2;
			} else {
				assignment += 5;
			}
			if (slave.balls > 0) {
				assignment += 1;
			}
		} else if ([Job.DAIRY].includes(slave.assignment)) {
			if (V.dairyRestraintsSetting > 1) {
				// assignment += 100; // Full industrial Dairy is exhausting
			} else if (V.dairyRestraintsSetting > 0) {
				assignment += 10; // Restraining while milking is a little stressful
			} else { // Being a free range cow is relatively relaxing
				if (slave.devotion > 20) {
					assignment += 2;
				} else {
					assignment += 5;
				}
				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.Wardeness !== 0 && slave.fetish !== "mindbroken") {
				if (V.Wardeness.fetish === "mindbroken") {
					if (H.tired > 80) {
						assignment -= 8;
					} else {
						assignment += 40;
					}
				} else if (V.Wardeness.sexualQuirk === "caring") {
					assignment += 5;
				} else if (V.Wardeness.sexualFlaw === "malicious" || V.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.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].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 (V.HGSlaveSuccess === 1) {
				H.tired -= 5;
			}
			if (V.personalAttention === PersonalAttention.SUPPORTHG) {
				H.tired -= 10;
			}
		}

		// H.tired = Math.clamp(H.tired, 0, 100); Disabled until hacky disabler is removed.
		if (H.tired < 0 || V.disableTiredness) {
			H.tired = 0;
		} else if (H.tired > 100) {
			H.tired = 100;
		}
	} else {
		// fuckdolls get a static tiredness drop due to drugs and suit control
		H.tired -= 30;
		if (H.tired <= 0 || V.disableTiredness) {
			H.tired = 1;
		}
	}
};

/**
 * @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) {
				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:
/**
 * @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 window.Job.WHORE:
			trackedCategory = "slaveAssignmentWhore";
			break;
		case window.Job.MADAM:
			trackedCategory = "slaveAssignmentMadam";
			break;
		case window.Job.BROTHEL:
			trackedCategory = "slaveAssignmentBrothel";
			break;
		case window.Job.PUBLIC:
			trackedCategory = "slaveAssignmentPublic";
			break;
		case window.Job.DJ:
			trackedCategory = "slaveAssignmentDj";
			break;
		case window.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:
/**
 * @param {App.Entity.SlaveState} slave
 */
App.SlaveAssignment.agent = function(slave) {
	const gigantomastiaMod = slave.geneticQuirks.gigantomastia === 2 ? (slave.geneticQuirks.macromastia === 2 ? 3 : 2) : 1;

	if (slave.boobsImplantType === "string") {
		slave.boobsImplant += 50;
		slave.boobs += 50;
		if (slave.boobs > 50000) {
			slave.boobs -= 100;
			slave.boobsImplant -= 100;
			if (slave.geneMods.NCS === 1) {
				slave.boobs -= 100;
				slave.boobsImplant -= 100;
			}
		}
	}

	if (slave.geneMods.NCS === 1) { /* NCS is blocking boob expansion. */
		if (slave.boobsImplant > 1000) {
			if ((slave.boobs - slave.boobsImplant < 1000) && (random(1, 100) > 60)) {
				slave.boobs += 50;
			}
		} else if (slave.boobsImplant > 600) {
			if ((slave.boobs - slave.boobsImplant < 500) && (random(1, 100) > 60)) {
				slave.boobs += 50;
			}
		} else if (slave.boobsImplant > 0) {
			if ((slave.boobs - slave.boobsImplant < 300) && (random(1, 100) > 60)) {
				slave.boobs += 50;
			}
		}
	}
	if (slave.geneticQuirks.macromastia === 2 && slave.geneticQuirks.gigantomastia === 2) {
		if (slave.boobs < 100000 && slave.weight >= -95) {
			slave.boobs += 30;
		}
	} else if (slave.geneticQuirks.gigantomastia === 2) {
		if (slave.boobs < 25000 && slave.weight >= -95) {
			slave.boobs += 20;
		}
	} else if (slave.geneticQuirks.macromastia === 2) {
		if (slave.boobs < 5000 && slave.weight >= -95) {
			slave.boobs += 10;
		}
	}
	if (slave.buttImplantType === "string") {
		slave.buttImplant += 0.25;
		slave.butt += 0.25;
		if ((slave.butt > 10)) {
			slave.butt -= 1, slave.buttImplant -= 1;
			if (slave.geneMods.NCS === 1) {
				slave.butt -= 1, slave.buttImplant -= 1;
			}
		}
	}
	if (slave.geneticQuirks.rearLipedema === 2 && slave.butt < 20) {
		slave.butt += 0.1;
	}

	if (slave.genes === "XX") {
		if (slave.ovaries === 1 || slave.mpreg === 1) {
			if (slave.balls > 0 && slave.ballType !== "sterile") {
				if (slave.hormoneBalance > 20) {
					slave.hormoneBalance -= 1;
				} else if (slave.hormoneBalance < 20) {
					slave.hormoneBalance += 1;
				}
			} else {
				if (slave.hormoneBalance > 60) {
					slave.hormoneBalance -= 1;
				} else if (slave.hormoneBalance < 60) {
					slave.hormoneBalance += 1;
				}
			}
		} else {
			if (slave.balls > 0 && slave.ballType !== "sterile") {
				if (slave.hormoneBalance > -20) {
					slave.hormoneBalance -= 1;
				} else if (slave.hormoneBalance < -20) {
					slave.hormoneBalance += 1;
				}
			} else {
				if (slave.hormoneBalance > 20) {
					slave.hormoneBalance -= 1;
				} else if (slave.hormoneBalance < 20) {
					slave.hormoneBalance += 1;
				}
			}
		}
	} else if (slave.genes === "XY") {
		if (slave.ovaries === 1 || slave.mpreg === 1) {
			if (slave.balls > 0 && slave.ballType !== "sterile") {
				if (slave.hormoneBalance > 20) {
					slave.hormoneBalance -= 1;
				} else if (slave.hormoneBalance < 20) {
					slave.hormoneBalance += 1;
				}
			} else {
				if (slave.hormoneBalance > 40) {
					slave.hormoneBalance -= 1;
				} else if (slave.hormoneBalance < 40) {
					slave.hormoneBalance += 1;
				}
			}
		} else {
			if (slave.balls > 0 && slave.ballType !== "sterile") {
				if (slave.hormoneBalance > -40) {
					slave.hormoneBalance -= 1;
				} else if (slave.hormoneBalance < -40) {
					slave.hormoneBalance += 1;
				}
			} else {
				if (slave.hormoneBalance > 20) {
					slave.hormoneBalance -= 1;
				} else if (slave.hormoneBalance < 20) {
					slave.hormoneBalance += 1;
				}
			}
		}
	}

	/* puberty - not announced for allowing surprise pregnancy */
	if (slave.ovaries === 1 || slave.mpreg === 1) {
		if (slave.pubertyXX === 0) {
			if (slave.physicalAge >= slave.pubertyAgeXX) {
				slave.pubertyXX = 1;
				if (slave.geneticQuirks.gigantomastia === 3 && random(1, 100) < slave.hormoneBalance) {
					slave.geneticQuirks.gigantomastia = 2;
				}
				if (slave.geneticQuirks.macromastia === 3 && random(1, 100) < slave.hormoneBalance) {
					slave.geneticQuirks.macromastia = 2;
				}
			}
		}
	}
	if (slave.balls > 0 && slave.ballType !== "sterile") {
		if (slave.pubertyXY === 0) {
			if (slave.physicalAge >= slave.pubertyAgeXY) {
				slave.pubertyXY = 1;
			}
		}
	}

	if (slave.inflation > 0) {
		slave.inflation = 0, slave.inflationType = "none", slave.inflationMethod = 0, slave.milkSource = 0;
	}

	if (slave.preg > 0) { // EFFECTS OF PREGNANCY
		if (slave.preg === slave.pregData.normalBirth / 8) { /* !!! Very bad condition logic - with pregnancy control drugs can be not triggered. Or may be trigged by broodmother several times. Need to be reworked. !!! */
			if (slave.pregSource === -1) {
				V.PC.counter.slavesKnockedUp++;
			} else if (slave.pregSource > 0) {
				const babyDaddy = findFather(slave.pregSource);
				if (babyDaddy) {
					const adjust = babyDaddy.counter.slavesKnockedUp++;
					adjustFatherProperty(babyDaddy, "slavesKnockedUp", adjust);
				}
			}
		}
		if (slave.preg >= slave.pregData.normalBirth / 4) {
			if (slave.geneticQuirks.gigantomastia === 3 && random(1, 200) < slave.hormoneBalance) {
				slave.geneticQuirks.gigantomastia = 2;
			}
			if (slave.geneticQuirks.macromastia === 3 && random(1, 200) < slave.hormoneBalance) {
				slave.geneticQuirks.macromastia = 2;
			}
			let boobTarget = 0;
			if (slave.geneMods.NCS === 1) {
				/* Sort-of No-op, NCS prevents boob growth */
				boobTarget = 0;
			} else if (slave.physicalAge >= 18) {
				if (slave.pregType >= 50) {
					boobTarget = 10000;
				} else if (slave.pregType >= 30) {
					boobTarget = 5000;
				} else if (slave.pregType >= 10) {
					boobTarget = 2000;
				} else {
					boobTarget = 1000;
				}
			} else if (slave.physicalAge >= 13) {
				if (slave.pregType >= 50) {
					boobTarget = 5000;
				} else if (slave.pregType >= 30) {
					boobTarget = 3200;
				} else if (slave.pregType >= 10) {
					boobTarget = 1800;
				} else {
					boobTarget = 800;
				}
			} else if (slave.physicalAge >= 8) {
				if (slave.pregType >= 50) {
					boobTarget = 1800;
				} else if (slave.pregType >= 30) {
					boobTarget = 1400;
				} else if (slave.pregType >= 10) {
					boobTarget = 1000;
				} else {
					boobTarget = 600;
				}
			} else {
				if (slave.pregType >= 50) {
					boobTarget = 1000;
				} else if (slave.pregType >= 30) {
					boobTarget = 800;
				} else if (slave.pregType >= 10) {
					boobTarget = 600;
				} else {
					boobTarget = 400;
				}
			}
			boobTarget *= gigantomastiaMod;
			if (slave.pregType >= 30) {
				if (slave.weight <= 65) {
					slave.weight += 1;
				}
				if ((slave.geneMods.NCS === 0) && (random(1, 100) > 60)) {
					if ((slave.boobs - slave.boobsImplant) < boobTarget) {
						slave.boobs += 200;
						if (slave.boobShape !== "saggy" && slave.preg > slave.pregData.normalBirth / 1.25 && (slave.breastMesh !== 1)) {
							slave.boobShape = "saggy";
						}
					}
					if (slave.hips < 2) {
						slave.hips += 1;
					}
					if (slave.butt < 14) {
						slave.butt += 1;
					}
				}
			} else if ((slave.geneMods.NCS === 0) && (slave.pregType >= 10)) {
				if (random(1, 100) > 80 && ((slave.boobs - slave.boobsImplant) < boobTarget)) {
					slave.boobs += 100;
					if (slave.boobShape !== "saggy" && (slave.breastMesh !== 1)) {
						if (slave.preg > random(slave.pregData.normalBirth / 1.25, slave.pregData.normalBirth * 2)) {
							slave.boobShape = "saggy";
						}
					}
				}
			} else if (((slave.geneMods.NCS === 0) && ((slave.boobs - slave.boobsImplant) < boobTarget))) {
				if (random(1, 100) > 80) {
					slave.boobs += 50;
					if (slave.boobShape !== "saggy" && slave.preg > random(slave.pregData.normalBirth / 1.25, slave.pregData.normalBirth * 2.5) && (slave.breastMesh !== 1)) {
						slave.boobShape = "saggy";
					}
				}
			}
			if (slave.geneMods.NCS === 1) {
				/* No-op, we don't grow hips on NCS */
			} else if (slave.preg > slave.pregData.normalBirth / 1.25 && slave.physicalAge >= 18 && slave.hips === 1 && slave.hipsImplant === 0 && random(1, 100) > 90) {
				slave.hips += 1;
			} else if (slave.preg > slave.pregData.normalBirth / 1.42 && slave.physicalAge >= 18 && slave.hips === 0 && slave.hipsImplant === 0 && random(1, 100) > 70) {
				slave.hips += 1;
			}
			if (slave.bellyPreg >= 1500) {
				if (setup.fakeBellies.includes(slave.bellyAccessory)) {
					slave.bellyAccessory = "none";
				}
				if ((slave.preg > slave.pregData.normalBirth / 2) && (slave.lactation === 0) && slave.health.condition >= -20 && slave.weight > -30) {
					if (slave.preg > random(slave.pregData.normalBirth / 2.22, slave.pregData.normalBirth / 1.33)) {
						slave.lactation = 1;
					}
				}
				if (slave.lactation === 1) {
					slave.lactationDuration = 2;
				}
			}
		} // closes .preg >= 10
	} // END PREG EFFECTS

	if (slave.belly >= 1000000) {
		if (slave.bellySag < 50) {
			slave.bellySag += 1;
			if (slave.preg > 0) {
				slave.bellySagPreg += 1;
			}
		} else if (slave.preg > 0 && slave.bellySagPreg < 20) {
			slave.bellySagPreg += 1;
		}
		if (slave.pregControl === "speed up") {
			slave.bellySag += 5, slave.bellySagPreg += 5;
		}
		if (slave.geneMods.rapidCellGrowth === 1) {
			slave.bellySag += 3;
			if (slave.preg > 0) {
				slave.bellySagPreg += 3;
			}
		}
	} else if (slave.belly >= 750000) {
		if (slave.bellySag < 30) {
			slave.bellySag += 0.7;
			if (slave.preg > 0) {
				slave.bellySagPreg += 0.7;
			}
		} else if (slave.preg > 0 && slave.bellySagPreg < 30) {
			slave.bellySagPreg += 0.7;
		}
		if (slave.pregControl === "speed up") {
			slave.bellySag += 2, slave.bellySagPreg += 2;
		}
		if (slave.geneMods.rapidCellGrowth === 1) {
			slave.bellySag += 1;
			if (slave.preg > 0) {
				slave.bellySagPreg += 1;
			}
		}
	} else if (slave.belly >= 600000) {
		if (slave.bellySag < 20) {
			slave.bellySag += 0.5;
			if (slave.preg > 0) {
				slave.bellySagPreg += 0.5;
			}
		} else if (slave.preg > 0 && slave.bellySagPreg < 20) {
			slave.bellySagPreg += 0.5;
		}
		if (slave.pregControl === "speed up") {
			slave.bellySag += 1;
			slave.bellySagPreg += 1;
		}
		if (slave.geneMods.rapidCellGrowth === 1) {
			slave.bellySag += 1;
			if (slave.preg > 0) {
				slave.bellySagPreg += 1;
			}
		}
	} else if (slave.belly >= 450000) {
		if (slave.bellySag < 15) {
			slave.bellySag += 0.4;
			if (slave.preg > 0) {
				slave.bellySagPreg += 0.4;
			}
		} else if (slave.preg > 0 && slave.bellySagPreg < 15) {
			slave.bellySagPreg += 0.4;
		}
		if (slave.pregControl === "speed up") {
			slave.bellySag += 0.6, slave.bellySagPreg += 0.6;
		}
		if (slave.geneMods.rapidCellGrowth === 1) {
			slave.bellySag += 0.5;
			if (slave.preg > 0) {
				slave.bellySagPreg += 0.5;
			}
		}
	} else if (slave.belly >= 300000) {
		if (slave.bellySag < 10) {
			slave.bellySag += 0.3;
			if (slave.preg > 0) {
				slave.bellySagPreg += 0.3;
			}
		} else if (slave.preg > 0 && slave.bellySagPreg < 10) {
			slave.bellySagPreg += 0.3;
		}
		if (slave.pregControl === "speed up") {
			slave.bellySag += 0.5, slave.bellySagPreg += 0.5;
		}
		if (slave.geneMods.rapidCellGrowth === 1) {
			slave.bellySag += 0.5;
			if (slave.preg > 0) {
				slave.bellySagPreg += 0.5;
			}
		}
	} else if (slave.belly >= 100000) {
		if (slave.bellySag < 10) {
			slave.bellySag += 0.2;
			if (slave.preg > 0) {
				slave.bellySagPreg += 0.2;
			}
		} else if (slave.preg > 0 && slave.bellySagPreg < 10) {
			slave.bellySagPreg += 0.2;
		}
		if (slave.pregControl === "speed up") {
			slave.bellySag += 0.3, slave.bellySagPreg += 0.3;
		}
		if (slave.geneMods.rapidCellGrowth === 1) {
			slave.bellySag += 0.3;
			if (slave.preg > 0) {
				slave.bellySagPreg += 0.3;
			}
		}
	} else if ((slave.bellyPreg >= 10000) || (slave.bellyImplant >= 10000)) {
		if (slave.bellySag < 5) {
			slave.bellySag += 0.1;
			if (slave.preg > 0) {
				slave.bellySagPreg += 0.1;
			}
		} else if (slave.preg > 0 && slave.bellySagPreg < 5) {
			slave.bellySagPreg += 0.1;
		}
		if (slave.pregControl === "speed up") {
			slave.bellySag += 0.2, slave.bellySagPreg += 0.2;
		}
		if (slave.geneMods.rapidCellGrowth === 1) {
			slave.bellySag += 0.2;
			if (slave.preg > 0) {
				slave.bellySagPreg += 0.2;
			}
		}
	}
	if (slave.bellySagPreg > slave.bellySag) {
		slave.bellySagPreg = slave.bellySag;
	}

	if (slave.bellySag > 0 && slave.belly < 1500 && slave.geneMods.rapidCellGrowth !== 1) {
		if (slave.muscles > 95) {
			if (random(1, 100) > 1) {
				if (slave.bellySagPreg > 0) {
					slave.bellySag -= 0.5;
					slave.bellySagPreg -= 0.5;
					if (slave.bellySag < 0) {
						slave.bellySag = 0;
						slave.bellySagPreg = 0;
					}
				} else {
					slave.bellySag -= 0.5;
					if (slave.bellySag < 0) {
						slave.bellySag = 0;
					}
				}
			}
		} else if (slave.muscles >= 30) {
			if (random(1, 100) > 20) {
				if (slave.bellySagPreg > 0) {
					slave.bellySag -= 0.4;
					slave.bellySagPreg -= 0.4;
					if (slave.bellySag < 0) {
						slave.bellySag = 0;
						slave.bellySagPreg = 0;
					}
				} else {
					slave.bellySag -= 0.4;
					if (slave.bellySag < 0) {
						slave.bellySag = 0;
					}
				}
			}
		} else if (slave.muscles >= 5) {
			if (random(1, 100) > 40) {
				if (slave.bellySagPreg > 0) {
					slave.bellySag -= 0.3;
					slave.bellySagPreg -= 0.3;
					if (slave.bellySag < 0) {
						slave.bellySag = 0;
						slave.bellySagPreg = 0;
					}
				} else {
					slave.bellySag -= 0.3;
					if (slave.bellySag < 0) {
						slave.bellySag = 0;
					}
				}
			}
		} else {
			if (random(1, 100) > 60) {
				if (slave.bellySagPreg > 0) {
					slave.bellySag -= 0.2;
					slave.bellySagPreg -= 0.2;
					if (slave.bellySag < 0) {
						slave.bellySag = 0;
						slave.bellySagPreg = 0;
					}
				} else {
					slave.bellySag -= 0.2;
					if (slave.bellySag < 0) {
						slave.bellySag = 0;
					}
				}
			}
		}
	}

	if ((slave.preg > slave.pregData.minLiveBirth) && (slave.broodmother === 0) && (random(1, 100) < 90)) {
		slave.counter.birthsTotal += WombBirthReady(slave, slave.pregData.minLiveBirth), WombBirth(slave, slave.pregData.minLiveBirth), WombFlush(slave);
		if (slave.geneticQuirks.fertility + slave.geneticQuirks.hyperFertility >= 4) {
			slave.pregWeek = -2;
		} else if (slave.geneticQuirks.hyperFertility > 1) {
			slave.pregWeek = -3;
		} else {
			slave.pregWeek = -4;
		}
		if (slave.birthsTat > -1) {
			slave.birthsTat++;
		}
	} else if ((slave.preg > slave.pregData.normalBirth) && (slave.broodmother === 0)) {
		slave.counter.birthsTotal += WombBirthReady(slave, slave.pregData.minLiveBirth), WombBirth(slave, slave.pregData.minLiveBirth), WombFlush(slave);
		if (slave.geneticQuirks.fertility + slave.geneticQuirks.hyperFertility >= 4) {
			slave.pregWeek = -2;
		} else if (slave.geneticQuirks.hyperFertility > 1) {
			slave.pregWeek = -3;
		} else {
			slave.pregWeek = -4;
		}
		if (slave.birthsTat > -1) {
			slave.birthsTat++;
		}
	} else if ((slave.preg > 37) && (slave.broodmother > 0)) {
		if (slave.broodmother > 0) {
			slave.counter.birthsTotal += WombBirthReady(slave, 37), WombBirth(slave, 37), slave.preg = WombMaxPreg(slave);
		}
		if (slave.birthsTat > -1) {
			slave.birthsTat++;
		}
	}

	SetBellySize(slave); // Actually it's now better to set belly size without checking of any conditions. Just to be sure. Should correct forgotten variables too.

	if (slave.lactation === 1) {
		if (slave.fetish !== "boobs") {
			if (slave.lactationDuration === 0) {
				slave.boobs -= slave.boobsMilk;
				slave.boobsMilk = 0;
				slave.lactation = 0;
			} else if (slave.lactationDuration === 1) {
				slave.boobsMilk += 10 * slave.lactationAdaptation;
				slave.boobs += slave.boobsMilk;
			} else {
				slave.lactationDuration--;
			}
		} else {
			slave.lactationDuration = 2;
		}
	} else if (slave.lactation === 2) {
		slave.lactationDuration = 2;
	} else if (slave.fetish === "boobs" && slave.boobs - slave.boobsImplant >= 2000) {
		slave.induceLactation += 2;
		if (slave.lactationDuration >= 20) {
			slave.induceLactation = 0;
			slave.lactationDuration = 2;
			slave.lactation = 1;
		}
	}

	if (slave.induceLactation > 0) {
		slave.induceLactation--;
	}

	if (slave.geneticQuirks.gigantomastia === 3 && random(70 - slave.physicalAge, 300) < slave.hormoneBalance) {
		slave.geneticQuirks.gigantomastia = 2;
	}
	if (slave.geneticQuirks.macromastia === 3 && random(70 - slave.physicalAge, 300) < slave.hormoneBalance) {
		slave.geneticQuirks.macromastia = 2;
	}

	if ((slave.hStyle !== "shaved" && slave.bald !== 1 && slave.haircuts === 0) && (slave.hLength < 150)) {
		slave.hLength += 1;
	}

	slave.health.illness = 0;
};


code:
App.SlaveAssignment.beYourHeadGirl = (function() {
	"use strict";

	let r;

	// eslint-disable-next-line no-unused-vars
	let he, him, his, hers, himself, girl, loli, He, His, wife, wives;

	let fetishChange;
	let arcology;

	return saBeYourHeadGirl;

	/**
	 * @param {App.Entity.SlaveState} slave
	 * @returns {string}
	 */
	function saBeYourHeadGirl(slave) {
		r = [];
		fetishChange = fetishChangeChance(slave);
		arcology = V.arcologies[0];

		({
			// eslint-disable-next-line no-unused-vars
			he, him, his, hers, himself, girl, He, His, loli, wife, wives
		} = getPronouns(slave));

		updateHGState(slave);
		jobPreface(slave);
		theHGLife(slave);
		if (V.personalAttention === "HG") {
			playerHelpsHG(slave);
		}
		if (V.HGFormality === 0) {
			HGFormality(slave);
		}
		jobEffects(slave);
		if (slave.prestige === 0) {
			prestigeGain(slave);
		}
		cleanupVars(slave);

		return r.join(" ");
	}

	/**
	 * @param {App.Entity.SlaveState} slave
	 *
	 */
	function updateHGState(slave) {
		V.HGTimeInGrade += 1;
		if (V.HGSuite === 1) {
			slave.rules.living = "luxurious";
		}
		tired(slave);
	}

	/**
	 * @param {App.Entity.SlaveState} slave
	 * */
	function jobPreface(slave) {
		if (arcology.FSEgyptianRevivalistLaw === 0) {
			r.push(`helps manage your other slaves. ${He} helps them when they try and fail, and punishes them when they fail to try.`);
		} else {
			r.push(`serves as your Consort. Though ${he} is still your slave, ${his} status is scarcely below that of a citizen. ${He} contributes to your reputation just like a Concubine, and ${he} is conscious of the trust you place in ${him}.`);
			slave.devotion += 1;
			slave.trust += 1;
			App.SlaveAssignment.pleaseYou(slave);
			if (slave.relationship > 4) {
				if (slave.relationshipTarget === V.Concubine.ID) {
					if (areRelated(V.Concubine, slave)) {
						const concubinePronouns = getPronouns(V.Concubine);
						if (V.Concubine.mother === slave.ID || V.Concubine.father === slave.ID) {
							r.push(`Your Concubine is your Consort's ${concubinePronouns.daughter}-${concubinePronouns.wife}. Truly, ${arcology.name} looks up to you <span class="green">as children to a father.</span>`);
							repX(1000, "headGirl", slave);
						} else if (slave.mother === V.Concubine.ID) {
							r.push(`Your Concubine is your Consort's mother-${concubinePronouns.wife}. Truly, ${arcology.name} looks up to you <span class="green">as children to a father.</span>`);
							repX(1000, "headGirl", slave);
						} else if (slave.father === V.Concubine.ID) {
							r.push(`Your Concubine is your Consort's father-${concubinePronouns.wife}. Truly, ${arcology.name} looks up to you <span class="green">as children to a father.</span>`);
							repX(1000, "headGirl", slave);
						} else {
							switch (areSisters(slave, V.Concubine)) {
								case 1:
									r.push(`Your Concubine is your Consort's twin-${concubinePronouns.wife}. Truly, ${arcology.name} looks up to you <span class="green">as children to a father.</span>`);
									repX(1000, "headGirl", slave);
									break;
								case 2:
									r.push(`Your Concubine is your Consort's ${concubinePronouns.sister}-${concubinePronouns.wife}. Truly, ${arcology.name} looks up to you <span class="green">as children to a father.</span>`);
									repX(1000, "headGirl", slave);
									break;
								case 3:
									r.push(`Your Concubine is your Consort's half-${concubinePronouns.sister}-${concubinePronouns.wife}. Truly, ${arcology.name} looks up to you <span class="green">as children to a father.</span>`);
									repX(1000, "headGirl", slave);
									break;
								default:
									r.push(`<span style="bold">Shit went wrong! Post this in a bug report!</span> This is <span class="red">NOT as it should be.</span>`);
									repX(500, "headGirl", slave);
							}
						}
					}
				} else {
					if (totalRelatives(slave) > 0) {
						let relation = getSlave(slave.relationshipTarget);
						const relationPronouns = getPronouns(relation);
						if (relation.mother === slave.ID || relation.father === slave.ID) {
							r.push(`Your Consort has a ${relationPronouns.daughter}-${relationPronouns.wife}. This is <span class="green">as it should be.</span>`);
							repX(500, "headGirl", slave);
						} else if (slave.mother === relation.ID) {
							r.push(`Your Consort has a mother-${relationPronouns.wife}. This is <span class="green">as it should be.</span>`);
							repX(500, "headGirl", slave);
						} else if (slave.father === relation.ID) {
							r.push(`Your Consort has a father-${relationPronouns.wife}. This is <span class="green">as it should be.</span>`);
							repX(500, "headGirl", slave);
						} else {
							switch (areSisters(slave, relation)) {
								case 1:
									r.push(`Your Consort has a twin-${relationPronouns.wife}. This is <span class="green">as it should be.</span>`);
									repX(500, "headGirl", slave);
									break;
								case 2:
									r.push(`Your Consort has a ${relationPronouns.sister}-${relationPronouns.wife}. This is <span class="green">as it should be.</span>`);
									repX(500, "headGirl", slave);
									break;
								case 3:
									r.push(`Your Consort has a half-${relationPronouns.sister}-${relationPronouns.wife}. This is <span class="green">as it should be.</span>`);
									repX(500, "headGirl", slave);
									break;
							}
						}
					}
				}
			}
		}
		if (V.HGEnergy === 0) {
			r.push(`${He} was <span class="red">too exhausted</span> to make any real progress with your slaves this week, however.`);
		}
	}

	/**
	 * @param {App.Entity.SlaveState} slave
	 * */
	function theHGLife(slave) {
		if (V.HGTimeInGrade > 12) {
			if (V.HGSuite === 1) {
				r.push(`Being continually trusted with this position increases ${his} devotion to you, and encourages ${him} to trust you in turn; ${he}'s also grateful for ${his} nice suite, which makes ${him} one of the best provided for slaves in the Free Cities.`);
				slave.devotion += 4;
				slave.trust += 4;
			} else if (slave.rules.living === "luxurious") {
				r.push(`Being continually trusted with this position <span class="hotpink">increases ${his} devotion to you</span> and encourages ${him} to <span class="mediumaquamarine">trust you in turn.</span>`);
				slave.devotion += 4;
				slave.trust += 4;
			} else {
				r.push(`Being continually trusted with this position slightly increases ${his} devotion to you, though ${he} harbors some doubts because ${he} isn't allowed a room of ${his} own to set ${him} apart from the other slaves.`);
				slave.devotion += 1;
			}
		} else {
			if (V.HGSuite === 1) {
				r.push(`${He}'s <span class="mediumaquamarine">grateful</span> for ${his} nice suite, which makes ${him} one of the best provided for slaves in the Free Cities.`);
				slave.trust += 4;
			} else if (slave.rules.living !== "luxurious" && slave.devotion <= 50) {
				r.push(`Given ${his} lofty position, ${he} harbors some doubts in ${his} value to you since ${he} isn't allowed a room of ${his} own to set ${him} apart from the other slaves.`);
				slave.devotion -= 2;
			}
		}
		if (slave.rules.living !== "luxurious") {
			r.push(`${His} duties are <span class="red">physically and mentally taxing,</span> especially with nothing more than a`);
			if (slave.rules.living === "normal") {
				r.push(`bed`);
			} else {
				r.push(`cot`);
			}
			r.push(`waiting for ${him} in the slave dormitory.`);
		}
	}

	/**
	 * @param {App.Entity.SlaveState} slave
	 *
	 */
	function playerHelpsHG(slave) {
		r.push(`You're cooperating with ${him} this week, working with ${V.assistant.name} to free up some of ${his} time so ${he} can target more slaves in need of individual attention.`);
		if (slave.trust > 95) {
			r.push(`${He} is so trusting of you that ${he} can act as your own right hand, allowing ${him} to oversee your slaves with remarkable efficiency.`);
		} else {
			r.push(`This arrangement <span class="mediumaquamarine">builds trust</span> between you.`);
			slave.trust += 2;
		}
		if (slave.health.tired > 30) {
			r.push(`It also takes a load off ${his} tired shoulders.`);
		}
	}

	/**
	 * @param {App.Entity.SlaveState} slave
	 *
	 */
	function HGFormality(slave) {
		if (slave.trust > 95) {
			r.push(`Every so often, when you're alone, ${he} calls you ${properTitle()}. ${He} treats your permission to do this as a sacred thing, and <span class="hotpink">loves you for it.</span>`);
			slave.devotion += 1;
		} else {
			r.push(`Your permission to be informal in private <span class="mediumorchid">confuses ${him}</span> a little, since ${he} isn't perfectly confident enough to be comfortable with the idea.`);
			slave.devotion -= 1;
		}
	}

	/**
	 * @param {App.Entity.SlaveState} slave
	 *
	 */
	function jobEffects(slave) {
		if (slave.fetishKnown === 1) {
			if (slave.fetish === "dom") {
				if (slave.fetishKnown === 1 && slave.fetishStrength <= 95) {
					r.push(`Having all the slaves look up to and obey ${him} advances ${his} <span class="lightcoral">dominant tendencies.</span>`);
					slave.fetishStrength += 4;
				}
			} else if (fetishChange > jsRandom(0, 100)) {
				r.push(`Having all the slaves look up to and obey ${him} affects ${his} sexuality, turning ${him} into a <span class="lightcoral">bit of a dominatrix.</span>`);
				slave.fetish = "dom";
				slave.fetishStrength = 20;
				slave.fetishKnown = 1;
			} else if (slave.fetishStrength <= jsRandom(20, 60)) {
				r.push(`The sheer variety of sexual situations ${he} sees and participates in <span class="pink">broaden ${his} sexual interests</span> and incline ${him} to take a dominant sexual role.`);
				slave.fetishStrength -= 4;
			}
		} else {
			if (slave.fetish === "dom") {
				r.push(`Having all the slaves look up to and obey ${him} clearly excites ${him}; <span class="lightcoral">${he}'s a natural dom!</span>`);
			} else if (fetishChange > jsRandom(0, 100)) {
				r.push(`Having all the slaves look up to and obey ${him} affects ${his} sexuality, turning ${him} into a <span class="lightcoral">bit of a dominatrix.</span>`);
				slave.fetish = "dom";
				slave.fetishStrength = 20;
				slave.fetishKnown = 1;
			}
		}

		if (slave.rules.lactation === "induce") {
			r.push(`${He} works mammary stimulation into ${his} slave training regimen in an effort to bring in ${his} milk for you.`);
			slave.induceLactation += 3;
			r.push(`${induceLactation(slave)}`);
			if (slave.lactation === 1) {
				slave.rules.lactation = "maintain";
			}
		} else if (slave.rules.lactation === "maintain") {
			r.push(`Proper nursing and milking technique is a strong aspect of ${his} slave training regimen, both to keep ${his} milk flowing and to prevent the mounting pressure from distracting from ${his} work.`);
			slave.lactationDuration = 2;
			slave.boobs -= slave.boobsMilk;
			slave.boobsMilk = 0;
		}

		if (slave.dick > 0 && V.universalRulesImpregnation === "HG" && canPenetrate(slave)) {
			r.push(`${He} finds ${his} duty to impregnate slaves at will sexually satisfying.`);
			slave.need = 0;
		} else if (V.slaves.length > 5) {
			r.push(`Seldom a day goes by without ${him} finding an outlet among your slaves for ${his} sexual desires.`);
			slave.need = 0;
		}
	}

	/**
	 * @param {App.Entity.SlaveState} slave
	 *
	 */
	function prestigeGain(slave) {
		if (V.HGTimeInGrade + ((slave.intelligence + slave.intelligenceImplant) / 10) + (slave.devotion / 10) + (slave.trust / 10) > 50) {
			r.push(`${slave.slaveName} has rendered such long and competent service as your Head Girl that many of your citizens have come to rely on ${his} word as an extension of yours, trusting that if ${he} does something, it's because you trust ${him} to. ${He} has become prestigious on ${his} own merits, a remarkable achievement for a slave!`);
			slave.prestige += 1;
			slave.prestigeDesc = `Many citizens respect ${his} long and able service as your Head Girl.`;
		}
	}

	/**
	 * @param {App.Entity.SlaveState} slave
	 *
	 */
	function cleanupVars(slave) {
		if (!setup.HGCareers.includes(slave.career) && slave.skill.headGirl < V.masteredXP) {
			slave.skill.headGirl += jsRandom(1, Math.ceil((slave.intelligence + slave.intelligenceImplant) / 15) + 8);
		}
		slave.health.tired = Math.clamp(slave.health.tired, 0, 1000);
	}
})();