code:
/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string} Slave's eyes
 */
App.Desc.eyes = function(slave) {
	"use strict";
	const V = State.variables;
	let r = ``;
	/* eslint-disable */
	let pronouns = getPronouns(slave);
	let he = pronouns.pronoun;
	let him = pronouns.object;
	let his = pronouns.possessive;
	let hers = pronouns.possessivePronoun;
	let himself = pronouns.objectReflexive;
	let boy = pronouns.noun;
	let He = capFirstChar(he);
	let His = capFirstChar(his);
	/* eslint-enable */

	if (slave.eyes <= -2) {
		const HC = hasVisibleHeterochromia(slave) ? 1 : 0;
		if (slave.eyes === -2) {
			r += `${His} eyes are dull`;
			if (V.saleDescription && V.PC.medicine >= 50 || V.PC.slaving >= 50) {
				r += `, unfocused`;
				if (HC) {
					r += `, heterochromatic,`;
				}
				r += ` and clearly nonfunctional`;
			} else {
				if (HC) {
					r += `, heterochromatic,`;
				}
				r += ` and unfocused`;
			}
		} else if (slave.eyes === -3) {
			r += `${He} has ${slave.eyeColor} colored glass eyes`;
		} else {
			r += `${His} gaze is empty`;
		}
		r += `, `;
		if (slave.intelligence > 95) {
			r += `but ${his} facial expressions reveal ${he} is incisive, quick, cunning; `;
			if (slave.intelligence + slave.intelligenceImplant >= 130) {
				r += `with ${his} education, ${he} is so far <span class="deepskyblue">beyond brilliant</span> that ${he} is nearly peerless. `;
			} else if (slave.intelligenceImplant >= 15) {
				r += `${he} is both <span class="deepskyblue">brilliant</span> and `;
				if (slave.intelligenceImplant >= 30) {
					r += `well `;
				}
				r += `educated. `;
			} else {
				r += `${he} is so <span class="deepskyblue">brilliant</span> that ${his} `;
				if (slave.intelligenceImplant > 0) {
					r += `meager`;
				} else {
					r += `lack of`;
				}
				r += ` education is unimportant. `;
			}
		} else if (slave.intelligence > 50) {
			if (slave.intelligence + slave.intelligenceImplant > 95) {
				r += `but ${his} facial expressions reveal ${he} is incisive, quick, cunning; with ${his} education, ${he} can be considered <span class="deepskyblue">brilliant.</span>`;
			} else if (slave.intelligenceImplant >= 15) {
				r += `but ${his} face is alive with intelligence; ${he} is both <span class="deepskyblue">highly intelligent</span> and `;
				if (slave.intelligenceImplant >= 30) {
					r += `well `;
				}
				r += `educated. `;
			} else {
				r += `but ${his} face is alive with intelligence; ${he} is so <span class="deepskyblue">highly intelligent</span> that ${his} `;
				if (slave.intelligenceImplant > 0) {
					r += `meager`;
				} else {
					r += `lack of`;
				}
				r += ` education is unimportant. `;
			}
		} else if (slave.intelligence > 15) {
			if (slave.intelligence + slave.intelligenceImplant > 50) {
				r += `but ${his} face is alive with intelligence; with ${his} education, ${he} can be considered <span class="deepskyblue">highly intelligent.</span>`;
			} else if (slave.intelligenceImplant >= 15) {
				r += `but ${his} facial expressions reveal ${his} cleverness; ${he} is of <span class="deepskyblue">above average intelligence</span> and`;
				if (slave.intelligenceImplant >= 30) {
					r += `well `;
				}
				r += `educated. `;
			} else {
				r += `but ${his} facial expressions reveal ${his} cleverness; ${he} is of <span class="deepskyblue">above average intelligence</span> despite being undereducated. `;
			}
		} else if (slave.intelligence >= -15) {
			if (slave.intelligence + slave.intelligenceImplant > 15) {
				r += `but ${his} facial expressions reveal ${his} cleverness; with ${his} education, ${he} can be considered of <span class="deepskyblue">above average intelligence.</span>`;
			} else if (slave.intelligenceImplant >= 15) {
				r += `but ${his} facial expressions reveal ${his} alertness; ${he} is of average intelligence due to being `;
				if (slave.intelligenceImplant >= 30) {
					r += `well `;
				}
				r += `educated. `;
			} else {
				r += `but ${his} facial expressions reveal ${his} alertness; ${he} is of average intelligence and is undereducated. `;
			}
		} else if (slave.intelligence >= -50) {
			if (slave.intelligence + slave.intelligenceImplant >= -15) {
				r += `but ${his} facial expressions reveal ${his} alertness; with ${his} education, ${he} can be considered of average intelligence. `;
			} else if (slave.intelligenceImplant >= 15) {
				r += `but ${his} facial expressions reveal ${he} is rather dim; ${he} is of <span class="orangered">below average intelligence</span> despite having been `;
				if (slave.intelligenceImplant >= 30) {
					r += `thoroughly `;
				}
				r += `educated. `;
			} else {
				r += `but ${his} facial expressions reveal ${he} is rather dim; ${he} is of <span class="orangered">below average intelligence</span> and is poorly educated. `;
			}
		} else if (slave.intelligence >= -95) {
			if (slave.intelligence + slave.intelligenceImplant >= -50) {
				r += `but ${his} facial expressions reveal ${he} is rather dim; even with ${his} education, ${he} can only be considered of <span class="orangered">below average intelligence.</span>`;
			} else if (slave.intelligenceImplant >= 15) {
				r += `but ${his} facial expressions reveal ${he} is as dull as ${his} eyes; ${he} is <span class="orangered">quite stupid</span> despite having `;
				if (slave.intelligenceImplant >= 30) {
					r += `an advanced`;
				} else {
					r += `some`;
				}
				r += ` education. `;
			} else {
				r += `but ${his} facial expressions reveal ${he} is as dull as ${his} eyes; ${he} is <span class="orangered">quite stupid</span> and ignorant. `;
			}
		} else {
			r += `though you doubt it would be much different if (V.{he}) could see; `;
			if (slave.intelligence + slave.intelligenceImplant >= -95) {
				r += `even with ${his} education, ${he} is still <span class="orangered">really stupid.</span>`;
			} else if (slave.intelligenceImplant > 0) {
				r += `${he} is <span class="orangered">a moron,</span> yet somehow still remembers the basics of an education. `;
			} else {
				r += `${he} is <span class="orangered">a moron,</span> and ignorant to boot. `;
			}
		}
	} else {
		if (slave.intelligence > 95) {
			r += `${His} ${slave.eyeColor}-eyed gaze is incisive, quick, cunning; `;
			if (slave.intelligence + slave.intelligenceImplant >= 130) {
				r += `with ${his} education, ${he} is so far <span class="deepskyblue">beyond brilliant</span> that ${he} is nearly peerless. `;
			} else if (slave.intelligenceImplant >= 15) {
				r += `${he} is both <span class="deepskyblue">brilliant</span> and `;
				if (slave.intelligenceImplant >= 30) {
					r += `well `;
				}
				r += `educated. `;
			} else {
				r += `${he} is so <span class="deepskyblue">brilliant</span> that ${his} `;
				if (slave.intelligenceImplant > 0) {
					r += `meager`;
				} else {
					r += `lack of`;
				}
				r += ` education is unimportant. `;
			}
		} else if (slave.intelligence > 50) {
			if (slave.intelligence + slave.intelligenceImplant > 95) {
				r += `${His} ${slave.eyeColor}-eyed gaze is incisive, quick, cunning; with ${his} education, ${he} can be considered <span class="deepskyblue">brilliant.</span>`;
			} else if (slave.intelligenceImplant >= 15) {
				r += `${His} ${slave.eyeColor} eyes are alive with intelligence; ${he} is both <span class="deepskyblue">highly intelligent</span> and `;
				if (slave.intelligenceImplant >= 30) {
					r += `well `;
				}
				r += `educated. `;
			} else {
				r += `${His} ${slave.eyeColor} eyes are alive with intelligence; ${he} is so <span class="deepskyblue">highly intelligent</span> that ${his} `;
				if (slave.intelligenceImplant > 0) {
					r += `meager`;
				} else {
					r += `lack of`;
				}
				r += ` education is unimportant. `;
			}
		} else if (slave.intelligence > 15) {
			r += `${His} ${slave.eyeColor} eyes are `;
			if (slave.intelligence + slave.intelligenceImplant > 50) {
				r += `alive with intelligence; with ${his} education, ${he} can be considered <span class="deepskyblue">highly intelligent.</span>`;
			} else if (slave.intelligenceImplant >= 15) {
				r += `clever; ${he} is of <span class="deepskyblue">above average intelligence</span> and `;
				if (slave.intelligenceImplant >= 30) {
					r += `well `;
				}
				r += `educated. `;
			} else {
				r += `clever; ${he} is of <span class="deepskyblue">above average intelligence</span> despite being undereducated. `;
			}
		} else if (slave.intelligence >= -15) {
			r += `${His} ${slave.eyeColor} eyes are `;
			if (slave.intelligence + slave.intelligenceImplant > 15) {
				r += `clever; with ${his} education, ${he} can be considered of <span class="deepskyblue">above average intelligence.</span>`;
			} else if (slave.intelligenceImplant >= 15) {
				r += `alert; ${he} is of average intelligence due to being `;
				if (slave.intelligenceImplant >= 30) {
					r += `well `;
				}
				r += `educated. `;
			} else {
				r += `alert; ${he} is of average intelligence and is undereducated. `;
			}
		} else if (slave.intelligence >= -50) {
			r += `${His} ${slave.eyeColor} eyes are `;
			if (slave.intelligence + slave.intelligenceImplant >= -15) {
				r += `alert; with ${his} education, ${he} can be considered of average intelligence. `;
			} else if (slave.intelligenceImplant >= 15) {
				r += `dim; ${he} is of <span class="orangered">below average intelligence</span> despite having been `;
				if (slave.intelligenceImplant >= 30) {
					r += `thoroughly `;
				}
				r += `educated. `;
			} else {
				r += `dim; ${he} is of <span class="orangered">below average intelligence</span> and is poorly educated. `;
			}
		} else if (slave.intelligence >= -95) {
			r += `${His} ${slave.eyeColor} eyes are `;
			if (slave.intelligence + slave.intelligenceImplant >= -50) {
				r += `dim; even with ${his} education, ${he} can only be considered of <span class="orangered">below average intelligence.</span>`;
			} else if (slave.intelligenceImplant >= 15) {
				r += `dull; ${he} is <span class="orangered">quite stupid</span> despite having `;
				if (slave.intelligenceImplant >= 30) {
					r += `an advanced`;
				} else {
					r += `some`;
				}
				r += ` education. `;
			} else {
				r += `dull; ${he} is <span class="orangered">quite stupid</span> and ignorant. `;
			}
		} else {
			r += `${His} ${slave.eyeColor}-eyed gaze betrays near-total insensibility; `;
			if (slave.intelligence + slave.intelligenceImplant >= -95) {
				r += `even with ${his} education, ${he} is still <span class="orangered">really stupid.</span>`;
			} else if (slave.intelligenceImplant > 0) {
				r += `${he} is <span class="orangered">a moron,</span> yet somehow still remembers the basics of an education. `;
			} else {
				r += `${he} is <span class="orangered">a moron,</span> and ignorant to boot. `;
			}
		}
	}
	return r;
};

/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string} Slave's eye color
 */
App.Desc.eyeColor = function(slave) {
	"use strict";
	let r;

	if (slave.eyes === -4) {
		r = "empty";
	} else if (hasVisibleHeterochromia(slave)) {
		r = `heterochromatic ${slave.eyeColor} and ${slave.geneticQuirks.heterochromia}`;
	} else {
		r = `${slave.eyeColor}`;
	}
	return r;
};

/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string} Slave's age and health
 */
App.Desc.ageAndHealth = function(slave) {
	"use strict";
	const V = State.variables;
	let r = ``;
	let woman;
	/* eslint-disable */
	let pronouns = getPronouns(slave);
	let he = pronouns.pronoun;
	let him = pronouns.object;
	let his = pronouns.possessive;
	let hers = pronouns.possessivePronoun;
	let himself = pronouns.objectReflexive;
	let boy = pronouns.noun;
	let He = capFirstChar(he);
	let His = capFirstChar(his);
	/* eslint-enable */
	let age;
	let birthday = "";
	if (V.seeAge !== 0) {
		if (slave.birthWeek === 51) {
			birthday = `; ${his} birthday is next week`;
		} else {
			birthday = `; ${his} birthday is in ${52-slave.birthWeek} weeks`;
		}
	}

	woman = (boy === "girl" ? "woman" : "man");

	if (!slave.fuckdoll) {
		if (slave.health < -90) {
			r += `${He} is nearly unresponsive. ${He}'s obviously <span class="red">dangerously sick,</span>`;
		} else if (slave.health < -50) {
			r += `${He} seems <span class="red">very sick,</span>`;
		} else if (slave.health < -20) {
			r += `${He} seems <span class="red">ill,</span>`;
		} else if (slave.health <= 20) {
			r += `${He} seems reasonably <span class="yellow">healthy,</span>`;
		} else if (slave.health <= 50) {
			r += `${He} shines with <span class="green">good health,</span>`;
		} else {
			r += `${He} almost gleams; ${he}'s in the absolute <span class="green">best of health,</span>`;
		}
		age = slave.actualAge + 1;
		r += ` and ${he}'s `;
		if (slave.birthWeek >= 52 && V.seeAge) {
			r += `going to turn ${age} this week,`;
		} else if (slave.actualAge < 3) {
			r += `an infant, only `;
			if (V.showAgeDetail) {
				if (!slave.actualAge) {
					r += `${0 + V.week-slave.weekAcquired} weeks old${birthday}.`;
				} else if (slave.actualAge) {
					r += `${num(slave.actualAge)} year old${birthday}.`;
				} else {
					r += `${num(slave.actualAge)} years old${birthday}.`;
				}
			} else {
				if (!slave.actualAge) {
					r += `${0 + V.week-slave.weekAcquired} weeks old.`;
				} else if (slave.actualAge) {
					r += `${num(slave.actualAge)} year old.`;
				} else {
					r += `${num(slave.actualAge)} years old.`;
				}
			}
		} else if (slave.actualAge < 5) {
			r += `a toddler, `;
			if (V.showAgeDetail) {
				r += `${num(slave.actualAge)} years old${birthday}.`;
			} else {
				r += `only ${num(slave.actualAge)} years old.`;
			}
		} else if (slave.actualAge < 13) {
			r += `a little $girl, `;
			if (V.showAgeDetail) {
				r += `${num(slave.actualAge)} years old${birthday}.`;
			} else {
				r += `only ${num(slave.actualAge)} years old.`;
			}
		} else if (slave.actualAge < 16) {
			r += `almost a child, `;
			if (V.showAgeDetail) {
				r += `${num(slave.actualAge)} years old${birthday}.`;
			} else {
				r += `less than 17 years old.`;
			}
		} else if (slave.actualAge < 17) {
			r += `young and fresh at ${num(slave.actualAge)}${birthday}.`;
		} else if (slave.actualAge < 18) {
			r += `young, fresh, and nearly 18`;
			if (V.showAgeDetail && V.seeAge !== 0) {
				if (slave.birthWeek === 51) {
					r += `; ${his} birthday is next week`;
					if (V.seeAge) {
						r += ` and people are already beginning to eye ${him}`;
					}
				}
			}
			r += `.`;
		} else if (slave.actualAge < 19) {
			if (!slave.birthWeek && V.seeAge) {
				r += `just turned ${num(slave.actualAge)} this week, which many citizens find especially appealing.`;
			} else if (slave.birthWeek < 4 && V.seeAge) {
				r += `only turned ${num(slave.actualAge)} this month.`;
			} else {
				r += `${num(slave.actualAge)} years old${birthday}.`;
			}
		} else if (slave.actualAge < 20) {
			r += `in ${his} final year as a teenager at age 19${birthday}.`;
		} else if (slave.actualAge < 26) {
			r += `a young ${woman}, `;
			if (V.showAgeDetail) {
				r += `${num(slave.actualAge)} years old${birthday}.`;
			} else {
				r += `in ${his} early twenties.`;
			}
		} else if (slave.actualAge < 30) {
			r += `a younger ${woman}, `;
			if (V.showAgeDetail) {
				r += `${num(slave.actualAge)} years old${birthday}.`;
			} else {
				r += `in ${his} late twenties.`;
			}
		} else if (slave.actualAge < 36) {
			if (V.showAgeDetail) {
				r += `${num(slave.actualAge)} years old${birthday}.`;
			} else {
				r += `in ${his} early thirties.`;
			}
		} else if (slave.actualAge < 40) {
			r += `middle-aged for a slave, `;
			if (V.showAgeDetail) {
				r += `at ${num(slave.actualAge)} years old${birthday}.`;
			} else {
				r += `in ${his} late thirties.`;
			}
		} else {
			r += `old for a slave, `;
			if (V.showAgeDetail) {
				r += `at ${num(slave.actualAge)} years old${birthday}.`;
			} else {
				if (slave.actualAge < 50) {
					r += `in ${his} forties.`;
				} else if (slave.actualAge < 60) {
					r += `in ${his} fifties.`;
				} else if (slave.actualAge < 70) {
					r += `extremely old for a slave, in ${his} 60s.`;
				} else if (slave.actualAge < 80) {
					r += `extremely old for a slave, in ${his} ${num(70)}s.`;
				} else if (slave.actualAge < 90) {
					r += `extremely old for a slave, in ${his} r += ${num(80)}s.`;
				} else if (slave.actualAge < 100) {
					r += `extremely old for a slave, in ${his} r += ${num(90)}s.`;
				} else if (slave.actualAge >= 100) {
					r += `ancient by any measure, over a century old.`;
				}
			}
			if (slave.actualAge !== slave.physicalAge) {
				r += ` However, ${he} has the body of a ${num(slave.physicalAge)}-year-old; `;
				if (slave.physicalAge < 18 && slave.actualAge >= 18) {
					r += `a stark contrast given ${his} maturity.`;
				} else if (slave.physicalAge < 18 && slave.actualAge < 18) {
					r += `a noticeable difference thanks to ${his} immaturity.`;
				} else if (slave.physicalAge <= slave.actualAge - 20 || slave.physicalAge >= slave.actualAge + 20) {
					r += `a shocking difference from ${his} actual age.`;
				} else if (slave.physicalAge <= slave.actualAge - 10 || slave.physicalAge >= slave.actualAge + 10) {
					r += `a noticeable difference from ${his} actual age.`;
				} else if (slave.physicalAge <= slave.actualAge - 5 || slave.physicalAge >= slave.actualAge + 5) {
					r += `a barely noticeable difference from ${his} actual age.`;
				} else {
					r += `though it is hard to tell the difference from ${his} actual age.`;
				}
			}
			/*
			 ** This section replaces the age/therapy texts, giving more details for the NCS condition.
			 */
			if (slave.geneMods.NCS) {
				let bodyNCS;
				if (slave.vagina < 0 && slave.dick <= 0) {
					bodyNCS = "childlike";
				} else if (slave.vagina < 0 && slave.dick > 0) {
					bodyNCS = "shota";
				} else if (slave.vagina > 0 && slave.dick <= 0) {
					bodyNCS = "loli";
				} else {
					bodyNCS = "loli/shota";
				}
				r += ` ${He} appears to be slave.visualAge years old and ${he} `;
				if (slave.visualAge <= 8) {
					r += `has induced <span class="orange">NCS</span> and will always have a ${bodyNCS} body, no matter how long ${he} lives.`;
				} else if (slave.visualAge < 13) {
					r += `has induced <span class="orange">NCS</span> and will have a ${bodyNCS} body for the rest of ${his} life.`;
				} else if (slave.visualAge < 20) {
					r += `still has a teen body for now, but with ${his} <span class="orange">NCS,</span> ${he} will eventually regress in age to look like a little $girl again.`;
				} else {
					r += `still has the body of an adult, but ${his} <span class="orange">NCS</span> has `;
					if (slave.physicalAge - slave.visualAge <= 5) {
						r += `not really begun to youthen ${his} appearance yet.`;
					} else if (slave.physicalAge - slave.visualAge <= 10) {
						r += `clearly been at work on ${him}, making ${him} appear younger.`;
					} else if (slave.physicalAge - slave.visualAge <= 20) {
						r += `obviously helped take more than a decade off of ${his} age.`;
					} else {
						r += `intensely youthened ${him}.`;
					}
				}
			} else if (slave.physicalAge !== slave.visualAge) {
				if (slave.visualAge <= slave.physicalAge - 20 || slave.visualAge >= slave.physicalAge + 20) {
					r += ` ${He} has undergone radical age therapy that makes ${him} look `;
				} else if (slave.visualAge <= slave.physicalAge - 10 || slave.visualAge >= slave.physicalAge + 10) {
					r += ` ${He} has undergone drastic age therapy that makes ${him} look `;
				} else if (slave.visualAge <= slave.physicalAge - 5 || slave.visualAge >= slave.physicalAge + 5) {
					r += ` ${He} has undergone noticeable age therapy that makes ${him} look `;
				} else {
					r += ` For various reasons, ${he} looks `;
				}
				if (slave.physicalAge > slave.visualAge) {
					if (slave.physicalAge < slave.visualAge + 5) {
						r += `a slightly younger ${slave.visualAge}.`;
					} else if (slave.visualAge < 20) {
						r += `like ${he}'s barely an adult.`;
					} else if (slave.visualAge < 25) {
						r += `barely into ${his} early twenties.`;
					} else if (slave.visualAge < 30) {
						r += `like ${he}'s still in ${his} twenties.`;
					} else if (slave.visualAge < 35) {
						r += `barely thirty.`;
					} else if (slave.visualAge < 40) {
						r += `still in ${his} thirties.`;
					} else if (slave.visualAge < 45) {
						r += `barely forty.`;
					} else if (slave.visualAge < 50) {
						r += `still in ${his} forties.`;
					} else if (slave.visualAge < 55) {
						r += `barely fifty.`;
					} else if (slave.visualAge < 60) {
						r += `still in ${his} fifties.`;
					} else if (slave.visualAge < 65) {
						r += `barely sixty.`;
					} else if (slave.visualAge < 70) {
						r += `still in ${his} sixties.`;
					} else if (slave.visualAge < 75) {
						r += `barely seventy.`;
					} else if (slave.visualAge < 80) {
						r += `still in ${his} seventies.`;
					} else {
						r += `a younger ${slave.visualAge}.`;
					}
				} else {
					if (slave.physicalAge > slave.visualAge - 5) {
						r += `a slightly older ${slave.visualAge}.`;
					} else if (slave.visualAge < 20) {
						r += `like a fresh adult.`;
					} else if (slave.visualAge < 25) {
						r += `just over twenty.`;
					} else if (slave.visualAge < 30) {
						r += `nearly thirty.`;
					} else if (slave.visualAge < 35) {
						r += `just over thirty.`;
					} else if (slave.visualAge < 40) {
						r += `nearly forty.`;
					} else if (slave.visualAge < 45) {
						r += `just over forty.`;
					} else if (slave.visualAge < 50) {
						r += `nearly fifty.`;
					} else if (slave.visualAge < 55) {
						r += `just over fifty.`;
					} else if (slave.visualAge < 60) {
						r += `nearly sixty.`;
					} else if (slave.visualAge < 65) {
						r += `just over sixty.`;
					} else if (slave.visualAge < 70) {
						r += `nearly seventy.`;
					} else if (slave.visualAge < 75) {
						r += `just over seventy.`;
					} else if (slave.visualAge < 80) {
						r += `nearly eighty.`;
					} else {
						r += `an ancient ${slave.visualAge}.`;
					}
				}
			}
		}
	} else {
		r += ` The Fuckdoll gives no external indication of ${his} health or age, but upon query ${his} systems reports that ${he} is`;
		if (slave.health < -90) {
			r += `<span class="red">dangerously sick</span>`;
		} else if (slave.health < -50) {
			r += `<span class="red">very sick</span>`;
		} else if (slave.health < -20) {
			r += `<span class="red">ill</span>`;
		} else if (slave.health <= 20) {
			r += `<span class="yellow">healthy</span>`;
		} else if (slave.health <= 50) {
			r += `<span class="green">very health</span>`;
		} else {
			r += `<span class="green">extremely healthy</span>`;
		}
		r += ` and ${slave.physicalAge} years old.`;
	}
	return r;
};

/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string} Slave's brand
 */
App.Desc.brand = function(slave) {
	"use strict";
	let r = ``;
	let bellyAccessory;
	/* eslint-disable */
	let pronouns = getPronouns(slave);
	let he = pronouns.pronoun;
	let him = pronouns.object;
	let his = pronouns.possessive;
	let hers = pronouns.possessivePronoun;
	let himself = pronouns.objectReflexive;
	let boy = pronouns.noun;
	let He = capFirstChar(he);
	let His = capFirstChar(his);
	/* eslint-enable */

	if (slave.brand) {
		bellyAccessory = slave.bellyAccessory;
		if (setup.fakeBellies.includes(bellyAccessory) && slave.brandLocation === "belly") {
			r += `${His} fake belly has ${slave.brand} branded on it. `;
		} else {
			r += `${He} has ${slave.brand} branded into the flesh of ${his} ${slave.brandLocation}. `;
		}
		return r;
	}
};

/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string} Description of slave's amputation, if present
 */
App.Desc.amputee = function(slave) {
	"use strict";
	let r = ``;
	/* eslint-disable */
	let pronouns = getPronouns(slave);
	let he = pronouns.pronoun;
	let him = pronouns.object;
	let his = pronouns.possessive;
	let hers = pronouns.possessivePronoun;
	let himself = pronouns.objectReflexive;
	let boy = pronouns.noun;
	let He = capFirstChar(he);
	let His = capFirstChar(his);
	/* eslint-enable */

	if (slave.amp) {
		if (slave.amp === -1) {
			r += `${slave.slaveName} is a <span class="pink">quadruple amputee,</span> but ${he}'s equipped with a set of modern prosthetic limbs that allow ${him} a fairly normal life. `;
		} else if (slave.amp === -2) {
			r += `${slave.slaveName} is a <span class="pink">quadruple amputee,</span> but ${he}'s equipped with P-Limbs customized for sex. ${His} fingertips vibrate, ${his} finger joints are masked to prevent pinching, and ${his} hands can dispense lube. `;
		} else if (slave.amp === -3) {
			r += `${slave.slaveName} is a <span class="pink">quadruple amputee,</span> but ${he}'s equipped with P-Limbs customized to look natural. They are covered in a material that closely mimics living ${slave.skin} skin, and their servos are noise dampened. `;
		} else if (slave.amp === -4) {
			r += `${slave.slaveName} is a <span class="pink">quadruple amputee,</span> but ${he}'s equipped with P-Limbs customized for combat. They're hardened, strengthened, and more responsive, and they conceal taser knuckles and extensible forearm blades. `;
		} else if (slave.amp === -5) {
			r += `${slave.slaveName} is a <span class="pink">quadruple amputee,</span> but ${he}'s equipped with advanced cybernetic P-Limbs. The ultimate fusion of combat effectiveness and instruments of pleasure, they're capable of performing multiple functions. They can enhance sex through ${his} vibrating hands and increase ${his} combat skills with hardened, yet flexible artificial muscles. They have an advanced artificial skin that can send electrical impulses that can cause stimulation or extreme pain. `;
		} else if (slave.amp > 0) {
			r += `${slave.slaveName} is a <span class="pink">quadruple amputee,</span> making ${him} a convenient torso-only sex toy. `;
		} else {
			r += `The most obvious thing about ${slave.slaveName} is that ${he} is a <span class="pink">quadruple amputee:</span> ${he} has neither arms nor legs. `;
		}
		return r;
	}
};

repo_name: powerfful/fc


code:
window.LivingRule = Object.freeze({LUXURIOUS: 'luxurious', NORMAL: 'normal', SPARE: 'spare'});
window.Job = Object.freeze({
	DAIRY: 'work in the dairy',
	MILKMAID: 'be the Milkmaid',
	MASTER_SUITE: 'serve in the master suite',
	CONCUBINE: 'be your Concubine',
	BABY_FACTORY: 'labor in the production line',
	BROTHEL: 'work in the brothel',
	MADAM: 'be the Madam',
	ARCADE: 'be confined in the arcade',
	SERVANT: 'work as a servant',
	SERVER: 'be a servant',
	STEWARD: 'be the Stewardess',
	CLUB: 'serve in the club',
	DJ: 'be the DJ',
	JAIL: 'be confined in the cellblock',
	WARDEN: 'be the Wardeness',
	CLINIC: 'get treatment in the clinic',
	NURSE: 'be the Nurse',
	HGTOY: 'live with your Head Girl',
	SCHOOL: 'learn in the schoolroom',
	TEACHER: 'be the Schoolteacher',
	SPA: 'rest in the spa',
	ATTEND: 'be the Attendant',
	NANNY: 'work as a nanny',
	MATRON: 'be the Matron',
	FARMYARD: 'work as a farmhand',
	FARMER: 'be the Farmer',
	REST: 'rest'
});
window.PersonalAttention = Object.freeze({
	TRADE: 'trading',
	WAR: 'warfare',
	SLAVING: 'slaving',
	ENGINEERING: 'engineering',
	MEDICINE: 'medicine',
	MAID: 'upkeep',
	HACKING: 'hacking'
});

window.calculateCosts = (function() {
	return {
		predict: predictCost,
		bill: getCost,
	};

	function predictCost() {
		let totalCosts = (
			getBrothelCosts() +
	getBrothelAdsCosts() +
	getArcadeCosts() +
	getClubCosts() +
	getClubAdsCosts() +
	getDairyCosts() +
	getIncubatorCosts() +
	getServantsQuartersCosts() +
	getMasterSuiteCosts() +
	getNurseryCosts() +
	getFarmyardCosts() +
	getSecurityExpansionCost() +
	getLifestyleCosts() +
	getFSCosts() +
	getCitizenOrphanageCosts() +
	getPrivateOrphanageCosts() +
	getPeacekeeperCosts() +
	getMercenariesCosts() +
	getMenialRetirementCosts() +
	getRecruiterCosts() +
	getSchoolCosts() +
	getPolicyCosts() +
	getProstheticsCosts() +
	getPCTrainingCosts() +
	getPCCosts() +
	predictTotalSlaveCosts()
		);

		// these two apply a multiplicative effect to all costs so far.
		totalCosts = getEnvironmentCosts(totalCosts);
		totalCosts = getPCMultiplierCosts(totalCosts);

		// in the old order these were applied after multiplication. Not sure if deliberate, but I'm leaving it for now.
		totalCosts += getSFCosts() + getWeatherCosts();
		/*
		// clean up
		if (totalCosts > 0) {
			totalCosts = 0;
		} else {
			totalCosts = Math.ceil(totalCosts);
		}
		*/
		return totalCosts;
	}

	function getCost() {
		const oldCash = State.variables.cash;
		cashX(forceNeg(getBrothelCosts()), "brothel");
		cashX(forceNeg(getBrothelAdsCosts()), "brothelAds");
		cashX(forceNeg(getArcadeCosts()), "arcade");
		cashX(forceNeg(getClubCosts()), "club");
		cashX(forceNeg(getClubAdsCosts()), "brothelAds");
		cashX(forceNeg(getDairyCosts()), "dairy");
		cashX(forceNeg(getIncubatorCosts()), "incubator");
		cashX(forceNeg(getServantsQuartersCosts()), "servantsQuarters");
		cashX(forceNeg(getMasterSuiteCosts()), "masterSuite");
		cashX(forceNeg(getNurseryCosts()), "nursery");
		cashX(forceNeg(getFarmyardCosts()), "farmyard");
		cashX(forceNeg(getSecurityExpansionCost()), "securityExpansion");
		cashX(forceNeg(getLifestyleCosts()), "personalLivingExpenses");
		cashX(forceNeg(getFSCosts()), "futureSocieties");
		cashX(forceNeg(getCitizenOrphanageCosts()), "citizenOrphanage");
		cashX(forceNeg(getPrivateOrphanageCosts()), "privateOrphanage");
		cashX(forceNeg(getPeacekeeperCosts()), "peacekeepers");
		cashX(forceNeg(getMercenariesCosts()), "mercenaries");
		cashX(forceNeg(getMenialRetirementCosts()), "menialRetirement");
		cashX(forceNeg(getRecruiterCosts()), "recruiter");
		cashX(forceNeg(getSchoolCosts()), "schoolBacking");
		cashX(forceNeg(getPolicyCosts()), "policies");
		cashX(forceNeg(getProstheticsCosts()), "lab");
		cashX(forceNeg(getPCTrainingCosts()), "PCtraining");
		cashX(forceNeg(getPCCosts()), "PCmedical");
		getTotalSlaveCosts();

		// these two apply a multiplicative effect to all costs so far.
		// Calculate what the deduced expenses would be, then subtract
		let costSoFar = (oldCash - State.variables.cash); // How much we have spent by this point; expected to be positive.
		cashX(costSoFar - getEnvironmentCosts(costSoFar), "environment"); // getEnv takes total costs and makes it worse. Figure out how much worse and record it

		costSoFar = (oldCash - State.variables.cash);
		cashX(costSoFar - getPCMultiplierCosts(costSoFar), "PCskills");

		// in the old order these were applied after multiplication. Not sure if deliberate, but I'm leaving it for now.
		cashX(forceNeg(getSFCosts()), "specialForces");
		cashX(forceNeg(getWeatherCosts()), "weather");
		return (oldCash - State.variables.cash);
	}

	// slave expenses
	function predictTotalSlaveCosts() {
		let loopCosts = 0;
		for (const slave of State.variables.slaves) {
			loopCosts += getSlaveCost(slave);
			loopCosts += getSlaveMinorCosts(slave);
		}
		return loopCosts;
	}

	function getTotalSlaveCosts() {
		let slaveCost = 0;
		let slaveCostMinor = 0;
		for (const slave of State.variables.slaves) {
			slaveCost = getSlaveCost(slave);
			cashX(forceNeg(slaveCost), "slaveUpkeep", slave);
			slaveCostMinor = getSlaveMinorCosts(slave);
			cashX(Math.abs(slaveCostMinor), "houseServant", slave);
		}
	// nothing to return, cashX already billed.
	}

	// facility expenses
	function getBrothelCosts() {
		const V = State.variables;
		return (1 + 0.1 * V.brothelUpgradeDrugs) * (V.brothel * V.facilityCost);
	}

	function getBrothelAdsCosts() {
		return (State.variables.brothel > 0) ? State.variables.brothelAdsSpending : 0;
	}

	function getArcadeCosts() {
		const V = State.variables;
		return (0.05 + 0.02 * V.arcadeUpgradeInjectors + 0.05 * V.arcadeUpgradeCollectors + 0.02 * V.arcadeUpgradeHealth) * (V.arcade + V.facilityCost);
	}

	function getClubCosts() {
		const V = State.variables;
		const initCosts = (V.club * V.facilityCost) + (0.2 * V.clubUpgradePDAs * V.club * V.facilityCost);
		return (V.club > 0) ? initCosts + V.clubAdsSpending : initCosts;
	}

	function getClubAdsCosts() {
		return (State.variables.club > 0) ? State.variables.clubAdsSpending : 0;
	}

	function getDairyCosts() {
		const V = State.variables;
		const facDairyMultiplier = V.facilityCost * V.dairy;
		let costs = facDairyMultiplier + (0.2 * V.dairyFeedersUpgrade + 0.1 * V.dairyPregUpgrade) * facDairyMultiplier + (0.2 * V.dairyStimulatorsUpgrade * V.facilityCost);
		if (V.dairy > 0) {
			costs += ((V.bioreactorsXY + V.bioreactorsXX + V.bioreactorsHerm + V.bioreactorsBarren) * 100);
		}
		return costs;
	}

	function getIncubatorCosts() {
		const V = State.variables;
		const facIncMultiplier = V.facilityCost * V.incubator;
		let costs = (facIncMultiplier * 10);
		costs += (0.2 * V.incubatorUpgradeWeight + 0.2 * V.incubatorUpgradeMuscles +
			0.2 * V.incubatorUpgradeReproduction + 0.2 * V.incubatorUpgradeGrowthStims +
			0.5 * V.incubatorUpgradeSpeed) * facIncMultiplier;
		if (V.incubator > 0) {
			costs += ((V.incubatorWeightSetting + V.incubatorMusclesSetting + V.incubatorReproductionSetting + V.incubatorGrowthStimsSetting) * 500);
		}
		return costs;
	}

	function getServantsQuartersCosts() {
		const V = State.variables;
		return (0.2 * V.servantsQuartersUpgradeMonitoring * V.servantsQuarters * V.facilityCost);
	}

	function getMasterSuiteCosts() {
		let costs = 0;
		if (State.variables.masterSuitePregnancySlaveLuxuries === 1) {
			costs += 500;
		}
		if (State.variables.masterSuitePregnancyFertilitySupplements === 1) {
			costs += 1000;
		}
		return costs;
	}

	function getNurseryCosts() {
		return (State.variables.nursery * State.variables.facilityCost);
	}

	function getFarmyardCosts() {
		return (State.variables.farmyard * State.variables.facilityCost);
	}

	// security expansion
	function getSecurityExpansionCost() {
		const V = State.variables;
		let secExpCost = 0;
		let soldierMod = 0;
		if (V.secExp === 1) {
			if (V.edictsUpkeep > 0) {
				secExpCost += V.edictsUpkeep;
			}
			if (V.SFSupportUpkeep > 0) {
				secExpCost += V.SFSupportUpkeep;
			}
			if (V.propHub > 0) {
				secExpCost += V.propHubUpkeep;
			}
			if (V.secHQ > 0) {
				secExpCost += V.secHQUpkeep + 20 * V.secMenials;
			}
			if (V.secBarracks > 0) {
				secExpCost += V.secBarracksUpkeep;
			}
			if (V.riotCenter > 0) {
				secExpCost += V.riotUpkeep;
			}
			if (V.soldierWages === 0) {
				soldierMod = 1;
			} else if (V.soldierWages === 1) {
				soldierMod = 1.5;
			} else {
				soldierMod = 2;
			}
			const militiaUnits = V.militiaUnits.length, slaveUnits = V.slaveUnits.length, mercUnits = V.mercUnits.length; // predefined for optimization
			if (V.militiaUnits !== null) {
				for (let i = 0; i < militiaUnits; i++) {
					if (V.militiaUnits[i] !== null) {
						secExpCost += V.militiaUnits[i].troops * V.soldierUpkeep * soldierMod;
					}
				}
			}
			if (V.slaveUnits !== null) {
				for (let i = 0; i < slaveUnits; i++) {
					if (V.slaveUnits[i] !== null) {
						secExpCost += V.slaveUnits[i].troops * V.soldierUpkeep * 0.5 * soldierMod;
					}
				}
			}
			if (V.mercUnits !== null) {
				for (let i = 0; i < mercUnits; i++) {
					if (V.mercUnits[i] !== null) {
						secExpCost += V.mercUnits[i].troops * V.soldierUpkeep * 1.5 * soldierMod;
					}
				}
			}
		}
		return secExpCost;
	}

	// general arcology costs

	function getLifestyleCosts() {
		return (State.variables.girls * (250 + (50000 / State.variables.localEcon)));
	}

	function getFSCosts() {
		let costs = State.variables.FSSpending;
		if (State.variables.arcologies[0].FSRepopulationFocusLaw === 1 && State.variables.PC.pregKnown === 1) {
			costs -= 500;
		}
		return costs;
	}

	function getCitizenOrphanageCosts() {
		return State.variables.citizenOrphanageTotal * 100;
	}

	function getPrivateOrphanageCosts() {
		const costs = State.variables.privateOrphanageTotal * 500;
		return (State.variables.breederOrphanageTotal > 0) ? costs + 50 : costs;
	}

	function getPeacekeeperCosts() {
		return (State.variables.peacekeepers !== 0 && State.variables.peacekeepers.undermining !== 0) ? State.variables.peacekeepers.undermining : 0;
	}

	function getMercenariesCosts() {
		const V = State.variables;
		let costs = 0;
		let mercCosts = V.mercenaries * 2000;
		if (V.mercenaries > 0) {
			if (V.barracks) {
				mercCosts *= 0.5;
			}
			if ((V.PC.warfare >= 100) || (V.PC.career === 'arcology owner')) {
				mercCosts *= 0.5;
			}
			costs += mercCosts;
		}
		return costs;
	}

	function getMenialRetirementCosts() {
		return (State.variables.citizenRetirementMenials === 1) ? State.variables.menials * 2 : 0;
	}

	// policy and other expenses
	function getRecruiterCosts() {
		return (State.variables.Recruiter !== 0) ? 250 : 0;
	}

	function getSchoolCosts() {
		let costs = 0;
		if (State.variables.TSS.schoolPresent === 1) {
			costs += 1000;
		}
		if (State.variables.GRI.schoolPresent === 1) {
			costs += 1000;
		}
		if (State.variables.SCP.schoolPresent === 1) {
			costs += 1000;
		}
		if (State.variables.LDE.schoolPresent === 1) {
			costs += 1000;
		}
		if (State.variables.TGA.schoolPresent === 1) {
			costs += 1000;
		}
		if (State.variables.HA.schoolPresent === 1) {
			costs += 1000;
		}
		if (State.variables.TCR.schoolPresent === 1) {
			costs += 1000;
		}
		if (State.variables.NUL.schoolPresent === 1) {
			costs += 1000;
		}
		if ((State.variables.TFS.schoolPresent === 1) && ((State.variables.PC.dick === 0) || (State.variables.PC.vagina === 0) || (State.variables.PC.boobs === 0))) {
			costs += 1000;
		}
		if (State.variables.TSS.subsidize !== 0) {
			costs += 1000;
		}
		if (State.variables.GRI.subsidize !== 0) {
			costs += 1000;
		}
		if (State.variables.SCP.subsidize !== 0) {
			costs += 1000;
		}
		if (State.variables.LDE.subsidize !== 0) {
			costs += 1000;
		}
		if (State.variables.TGA.subsidize !== 0) {
			costs += 1000;
		}
		if (State.variables.HA.subsidize !== 0) {
			costs += 1000;
		}
		if (State.variables.TCR.subsidize !== 0) {
			costs += 1000;
		}
		if (State.variables.NUL.subsidize !== 0) {
			costs += 1000;
		}
		if (State.variables.TFS.subsidize !== 0) {
			costs += 1000;
		}
		return costs;
	}

	function getPolicyCosts() {
		let costs = 0;
		const policyCost = State.variables.policyCost;
		if (State.variables.alwaysSubsidizeGrowth === 1) {
			costs += policyCost;
		}
		if (State.variables.alwaysSubsidizeRep === 1) {
			costs += policyCost;
		}
		if (State.variables.RegularParties === 1) {
			costs += policyCost;
		}
		if (State.variables.ProImmigrationCash === 1) {
			costs += policyCost;
		}
		if (State.variables.AntiEnslavementCash === 1) {
			costs += policyCost;
		}
		if (State.variables.CoursingAssociation === 1) {
			costs += 1000;
		}
		return costs;
	}

	function getProstheticsCosts() {
		return ((100 * State.variables.researchLab.maxSpace) + (300 * State.variables.researchLab.hired) + (100 * State.variables.researchLab.hired));
	}

	// player expenses
	function getPCTrainingCosts() {
		const V = State.variables;
		const PA = Object.values(PersonalAttention);
		const currentPA = V.personalAttention;
		let costs = 0;
		if (V.PC.actualAge >= V.IsInPrimePC && V.PC.actualAge < V.IsPastPrimePC) {
			if (PA.includes(currentPA) && currentPA !== PersonalAttention.MAID) {
				costs += 10000 * V.AgeEffectOnTrainerPricingPC;
			}
		}
		return costs;
	}

	function getPCCosts() {
		let costs = 0;
		if (State.variables.PC.preg === -1) {
			costs += 25;
		} else if (State.variables.PC.fertDrugs === 1) {
			costs += 50;
		} else if (State.variables.PC.preg >= 16) {
			costs += 100;
		}
		if (State.variables.PC.staminaPills === 1) {
			costs += 50;
		}
		return costs;
	}

	function getPCMultiplierCosts(cost) {
		if (State.variables.PC.career === 'servant') {
			if (State.variables.personalAttention === PersonalAttention.MAID) {
				if (State.variables.PC.belly >= 5000) {
					cost *= 0.80;
				} else {
					cost *= 0.75;
				}
			} else {
				cost *= 0.9;
			}
		}
		return cost;
	}

	function getEnvironmentCosts(cost) {
		if (State.variables.secExp === 1) {
			if (State.variables.terrain === 'oceanic' || State.variables.terrain === 'marine') {
				if (State.variables.docks > 0) {
					cost *= (1 - State.variables.docks * 0.05);
				}
			} else if (State.variables.railway > 0) {
				cost *= (1 - State.variables.railway * 0.05);
			}
		}
		return Math.trunc(cost);
	}

	function getSFCosts() {
		let costs = 0;
		if (State.variables.SF.Toggle && State.variables.SF.Active >= 1 && State.variables.SF.Subsidy > 0) {
			App.SF.Count();
			costs += Math.ceil(State.temporary.SFSubsidy);
		}
		return costs;
	}

	function getWeatherCosts() {
		let costs = 0;
		if (State.variables.econWeatherDamage && State.variables.disasterResponse > 0) {
			costs += Math.trunc(State.variables.disasterResponse * 200000 / State.variables.localEcon);
		}
		if (State.variables.antiWeatherFreeze > 0) {
			costs += Math.trunc(State.variables.antiWeatherFreeze * 200000 / State.variables.localEcon);
		}
		return costs;
	}

	// the cost of keeping a slave under restrictive rules
	function getSlaveMinorCosts(slave) {
		let costs = 0;
		const rulesCost = State.variables.rulesCost;
		if (slave.assignment === Job.SERVANT || slave.assignment === Job.SERVER) {
			if (slave.trust < -20) {
				costs -= rulesCost * 4;
			} else if (slave.devotion < -20) {
				costs -= (slave.trust >= 20) ? rulesCost / 2 : rulesCost * 2;
			} else if (slave.devotion <= 20) {
				costs -= rulesCost * 3;
			} else if (slave.devotion <= 50) {
				costs -= rulesCost * 4;
			} else {
				costs -= rulesCost * 5;
			}
			if (slave.fetish === 'submissive') {
				costs -= rulesCost;
			} else if (slave.fetish === 'dom') {
				costs += rulesCost;
			}
			if (slave.relationship < -1) {
				costs -= rulesCost;
			}
			if (slave.energy < 20) {
				costs -= rulesCost;
			} else if (slave.energy < 40) {
				costs -= rulesCost / 2;
			}
			if (slave.lactation > 0) {
				costs -= 25;
			}
			if (slave.assignment === Job.SERVANT) {
				costs -= rulesCost;
			}
			if (setup.servantCareers.includes(slave.career) || slave.skill.servant >= State.variables.masteredXP) {
				costs -= rulesCost;
			}
		}
		return costs;
	}
})();

/**
 * @param {App.Entity.SlaveState} s
 * @returns {number}
 */
window.getSlaveCost = function(s) {
	if (!s) {
		return 0;
	}
	// Data duplicated from Cost Report
	let cost = 0;
	const rulesCost = State.variables.rulesCost;
	const foodCost = State.variables.foodCost;
	const drugsCost = State.variables.drugsCost;

	// Living expenses
	switch (s.assignment) {
		case Job.ARCADE:
			cost += rulesCost * 0.75;
			break;
		case Job.DAIRY:
			if (State.variables.dairyRestraintsSetting >= 2) {
				cost += rulesCost * 0.75;
			} else if (s.livingRules === LivingRule.NORMAL) {
				cost += rulesCost * 1.5;
			} else if (State.variables.dairyDecoration === 'Degradationist') {
				cost += rulesCost * 0.90;
			} else {
				cost += rulesCost;
			}
			break;
		case Job.FARMYARD:
			if (s.livingRules === LivingRule.NORMAL) {
				cost += rulesCost * 1.5;
			} else if (State.variables.farmyardDecoration === 'Roman Revivalist') {
				cost += rulesCost * 1.5;
			} else {
				cost += rulesCost;
			}
			break;
		case Job.BROTHEL:
			cost += (s.livingRules === LivingRule.NORMAL) ? rulesCost * 1.5 : rulesCost;
			break;
		case Job.SCHOOL:
		case Job.CLUB:
			cost += rulesCost * 1.5;
			break;
		case Job.CLINIC:
			if (s.livingRules === LivingRule.LUXURIOUS) {
				cost += rulesCost * 2;
			} else if (s.livingRules === LivingRule.NORMAL) {
				cost += rulesCost * 1.5;
			} else {
				cost += rulesCost;
			}
			break;
		case Job.SPA:
		case Job.NANNY:
			if (s.livingRules === LivingRule.LUXURIOUS) {
				cost += rulesCost * 1.75;
			} else if (s.livingRules === LivingRule.NORMAL) {
				cost += rulesCost * 1.5;
			} else {
				cost += rulesCost;
			}
			break;
		case Job.SERVANT:
			if (s.livingRules === LivingRule.NORMAL) {
				cost += rulesCost * 1.5;
			} else {
				cost += (State.variables.servantsQuartersDecoration === 'Degradationist') ? rulesCost * 0.90 : rulesCost;
			}
			break;
		case Job.JAIL:
			cost += (s.livingRules === LivingRule.NORMAL) ? rulesCost * 1.25 : rulesCost * 0.90;
			break;
		case Job.MADAM:
		case Job.DJ:
		case Job.NURSE:
		case Job.WARDEN:
		case Job.ATTEND:
		case Job.STEWARD:
		case Job.MILKMAID:
		case Job.FARMER:
		case Job.TEACHER:
		case Job.MATRON:
			cost += rulesCost * 2;
			break;
		default:
			if (s.livingRules === LivingRule.LUXURIOUS) {
				cost += rulesCost * (s.relationship >= 4 ? 3 : 4);
			} else if (s.livingRules === LivingRule.NORMAL) {
				cost += rulesCost * 2;
			} else {
				cost += rulesCost;
			}
			break;
	}

	// Food
	cost += foodCost * 4;
	switch (s.diet) {
		case 'fattening':
		case 'muscle building':
			cost += foodCost;
			break;
		case 'restricted':
		case 'slimming':
			cost -= foodCost;
			break;
	}
	if (s.geneticQuirks.fertility === 2 && s.geneticQuirks.hyperFertility === 2 && s.preg === 0 && (s.ovaries === 1 || s.mpreg === 1)) {
		cost += foodCost * 0.5;
	}
	if (s.weight > 130) {
		cost += foodCost * 2;
	} else if (s.weight > 50) {
		cost += foodCost;
	} else if (s.weight < -50) {
		cost -= foodCost;
	}
	if (s.geneticQuirks.rearLipedema === 2) {
		cost += foodCost * 0.2;
	}
	if (s.geneticQuirks.macromastia === 2) {
		cost += foodCost * 0.2;
	}
	if (s.geneticQuirks.gigantomastia === 2) {
		cost += foodCost * 0.2;
	}
	if (s.geneticQuirks.mGain === 2 && s.geneticQuirks.mLoss !== 2) {
		cost += foodCost * 0.2;
	}
	if (s.geneticQuirks.wGain === 2 && s.geneticQuirks.wLoss !== 2) {
		cost += foodCost * 0.2;
	}
	if (s.drugs === 'appetite suppressors') {
		cost -= foodCost;
	}
	if (s.lactation > 0) {
		cost += foodCost * s.lactation * (1 + Math.trunc(s.boobs / 10000));
	}
	if (s.preg > s.pregData.normalBirth / 8) {
		if (s.assignment === Job.DAIRY && State.variables.dairyFeedersSetting > 0) {
			// Extra feeding costs to support pregnancy are covered by dairy feeders.
			// TODO: Include them here anyway?
		} else if ((s.assignment === Job.MASTER_SUITE || s.assignment === Job.CONCUBINE) &&
			State.variables.masterSuiteUpgradePregnancy === 1) {
			// Extra feeding costs to support pregnancy are covered by master suite luxuries.
			// TODO: Include them here anyway?
		} else {
			cost += foodCost * s.pregType * (s.pregControl === 'speed up' ? 3 : 1);
			if (s.pregType >= 100) {
				cost += foodCost * 5 * s.pregType * (s.pregControl === 'speed up' ? 3 : 1);
			} else if (s.pregType >= 50) {
				cost += foodCost * 3 * s.pregType * (s.pregControl === 'speed up' ? 3 : 1);
			} else if (s.pregType >= 30) {
				cost += foodCost * 2 * s.pregType * (s.pregControl === 'speed up' ? 3 : 1);
			} else if (s.pregType >= 10) {
				cost += foodCost * s.pregType * (s.pregControl === 'speed up' ? 3 : 1);
			}
		}
	}
	if (s.diet === 'XX' || s.diet === 'XY' || s.diet === 'fertility') {
		cost += 25;
	} else if (s.diet === 'cleansing') {
		cost += 50;
	} else if (s.diet === 'XXY') {
		cost += 75;
	}

	// Accessibility costs
	if (State.variables.boobAccessibility !== 1 && s.boobs > 20000 &&
		(s.assignment !== Job.DAIRY || State.variables.dairyRestraintsSetting < 2) && (s.assignment !== Job.ARCADE)) {
		cost += 50;
	}
	if (State.variables.pregAccessibility !== 1 &&
		(s.belly >= 60000) && s.assignment !== Job.BABY_FACTORY && (s.assignment !== Job.DAIRY || State.variables.dairyRestraintsSetting < 2) && (s.assignment !== Job.ARCADE)) {
		cost += 100;
	}
	if (State.variables.dickAccessibility !== 1 && s.dick > 45 && (s.assignment !== Job.DAIRY || State.variables.dairyRestraintsSetting < 2) && (s.assignment !== Job.ARCADE)) {
		cost += 50;
	}
	if (State.variables.ballsAccessibility !== 1 && s.balls > 90 && (s.assignment !== Job.DAIRY || State.variables.dairyRestraintsSetting < 2) && (s.assignment !== Job.ARCADE)) {
		cost += 50;
	}
	if (State.variables.buttAccessibility !== 1 && s.butt > 15 && (s.assignment !== Job.DAIRY || State.variables.dairyRestraintsSetting < 2) && (s.assignment !== Job.ARCADE)) {
		cost += 50;
	}
	if (!canSee(s) && (s.assignment !== Job.DAIRY || State.variables.dairyRestraintsSetting < 2) && (s.assignment !== Job.ARCADE)) {
		cost += 50;
	} else if (s.eyes <= -1 && s.eyewear !== 'corrective glasses' && s.eyewear !== 'corrective contacts') {
		cost += 25;
	} else if (s.eyewear === 'blurring glasses' || s.eyewear === 'blurring contacts') {
		cost += 25;
	}
	if (!canHear(s) && (s.assignment !== Job.DAIRY || State.variables.dairyRestraintsSetting < 2) && (s.assignment !== Job.ARCADE)) {
		cost += 40;
	} else if (s.hears <= -1 && s.earwear !== 'hearing aids') {
		cost += 15;
	} else if (s.earwear === 'muffling ear plugs') {
		cost += 15;
	}
	if ((s.assignment !== Job.DAIRY || State.variables.dairyRestraintsSetting < 2) && (s.assignment !== Job.ARCADE)) {
		if (s.amp !== 0) {
			cost += (s.amp === 1) ? rulesCost : rulesCost / 2;
		} else if (!canWalk(s)) {
			cost += rulesCost;
		}
	}

	// Maintenance
	if (s.boobs > 10000 && s.boobsImplantType === 1) {
		cost += 50;
	}
	if (s.butt > 10 && s.buttImplantType === 1) {
		cost += 50;
	}
	if ((s.assignment !== Job.DAIRY || State.variables.dairyRestraintsSetting < 2) && (s.assignment !== Job.ARCADE)) {
		if (s.preg > s.pregData.minLiveBirth && State.variables.universalRulesBirthing === 1) {
			cost += 50;
		}
	}

	// Retirement account
	if (State.variables.citizenRetirementMenials === 1 && State.variables.CitizenRetirement === 0) {
		cost += 2;
	}

	if (State.variables.CitizenRetirement === 1) {
		cost += 250;
	}

	// Enemas
	if (s.inflation === 3) {
		switch (s.inflationType) {
			case 'water':
				cost += 100;
				break;
			case 'food':
				cost += (foodCost * 4);
				break;
			case 'curative':
			case 'aphrodisiac':
			case 'tightener':
				cost += (100 + (drugsCost * 2));
				break;
		}
	} else if (s.inflation === 2) {
		switch (s.inflationType) {
			case 'water':
				cost += 50;
				break;
			case 'food':
				cost += (foodCost * 2);
				break;
			case 'curative':
			case 'aphrodisiac':
			case 'tightener':
				cost += (50 + (drugsCost * 2));
				break;
		}
	} else if (s.inflation === 1) {
		switch (s.inflationType) {
			case 'water':
				cost += 25;
				break;
			case 'food':
				cost += (foodCost);
				break;
			case 'curative':
			case 'aphrodisiac':
			case 'tightener':
				cost += (25 + (drugsCost * 2));
				break;
		}
	}

	// Drugs
	switch (s.drugs) {
		case 'anti-aging cream':
			cost += drugsCost * 10;
			break;
		case 'female hormone injections':
		case 'male hormone injections':
		case 'intensive breast injections':
		case 'intensive butt injections':
		case 'intensive penis enhancement':
		case 'intensive testicle enhancement':
		case 'intensive lip injections':
		case 'hyper breast injections':
		case 'hyper butt injections':
		case 'hyper penis enhancement':
		case 'hyper testicle enhancement':
		case 'hyper lip injections':
		case 'growth stimulants':
			cost += drugsCost * 5;
			break;
		case 'sag-B-gone':
			cost += Math.trunc(drugsCost * 0.1);
			break;
		case 'no drugs':
		case 'none':
			break;
		default:
			cost += drugsCost * 2;
			break;
	}
	if (s.curatives > 0 && s.assignmentVisible === 1) {
		cost += drugsCost * s.curatives;
	}
	if (s.aphrodisiacs !== 0) {
		cost += Math.trunc(drugsCost * Math.abs(s.aphrodisiacs));
	}
	if (s.hormones !== 0) {
		cost += Math.trunc((drugsCost * Math.abs(s.hormones) * 0.5));
	}
	if (s.bodySwap > 0) {
		cost += Math.trunc((drugsCost * s.bodySwap * 10));
	}
	if (s.preg === -1 && isFertile(s)) {
		cost += Math.trunc((drugsCost * 0.5));
	}

	// Promotion costs
	if (State.variables.studio === 1) {
		if (s.pornFameSpending > 0) {
			cost += (s.pornFameSpending / State.variables.PCSlutContacts);
		}
	}

	if (isNaN(cost)) {
		throw new Error(`Cost calculation for slave ${s.slaveName} (${s.ID}) failed.`);
	}
	return cost;
};

// Supply and Demand for slaves (linear, simple)
// PC buying slaves reduces supply, selling slaves reduces demand.

window.menialSlaveCost = function(q) {
	if (!q) {
		q = 0;
	}
	const demand = State.variables.menialDemandFactor;
	const supply = State.variables.menialSupplyFactor;
	const baseCost = 1000;
	const random = State.variables.slaveCostRandom;
	return (Math.trunc(baseCost + demand / 400 - supply / 400 + q / 400) + random);
};

window.NPCSexSupply = function(LC) {
	const V = State.variables;
	const NPCSexSupply = {lowerClass: V.NPCSexSupply.lowerClass};

	// Lower class calculations
	LC += V.sexSubsidiesLC / 10 - V.sexSupplyBarriersLC / 20;
	if (LC >= 0.5) {
		NPCSexSupply.lowerClass += Math.max(Math.trunc(NPCSexSupply.lowerClass * ((LC - 0.5) * (0.2 - V.sexSupplyBarriersLC / 25))), (50 * (1 - V.sexSupplyBarriersLC / 5))); // Max growth of 10% per week, unless it is really low, than a flat 50
	} else if (LC < 0.5) {
		if (NPCSexSupply.lowerClass > V.lowerClass * (3 - V.sexSupplyBarriersLC / 2)) { // Natural market share of competitors is at least 30%
			NPCSexSupply.lowerClass -= Math.trunc(NPCSexSupply.lowerClass * ((0.5 - LC) / 5)); // Max reduction of 10% per week
		}
	}

	return NPCSexSupply;
};

// The function for calculating and storing a slave's sexual interaction with citizens/'the outside'
window.slaveJobValues = function() {
	const V = State.variables;
	const slaveJobValues = {arcade: 0, club: 0, clubSP: 0}; let clubSpots = 0; const toTheClubTotal = 0;
	V.slavesGettingHelp = 0;

	// This section is for specific slaves or non-unique slaves adding their values to the whole
	// Accounting for Fuckdolls
	if (V.fuckdolls > 0) {
		slaveJobValues.arcade += (V.fuckdolls - (V.arcade - V.arcadeSlaves)) * 140 + (V.arcade - V.arcadeSlaves) * (175 + 35 * V.arcadeUpgradeInjectors);
	}

	// Accounting for the DJ.
	V.DJ = V.slaves.find(s => {
		return s.assignment === "be the DJ";
	});
	if (V.DJ !== 0) {
		if (!canTalk(V.DJ)) {
			// <strong><u><span class="pink">$DJ.slaveName</span></u></strong> can't speak <span class="yellow">and cannot serve as your DJ any more.</span><br>
			V.DJ = 0;
			V.unDJ = 1;
		} else if (V.DJ.preg > 37 && V.DJ.broodmother === 2) {
			// <strong><u><span class="pink">$DJ.slaveName</span></u></strong> spends so much time giving birth and laboring that <span class="yellow">$he cannot effectively serve as your DJ any longer.</span>
			V.DJ = 0;
			V.unDJ = 2;
		} else if (V.DJ.fetish === "mindbroken") {
			// <strong><u><span class="pink">$DJ.slaveName</span></u></strong> is mindbroken <span class="yellow">and cannot serve as your DJ any more.</span><br>
			V.DJ = 0;
			V.unDJ = 3;
		} else if (!canWalk(V.DJ)) {
			// <strong><u><span class="pink">$DJ.slaveName</span></u></strong> is no longer independently mobile <span class="yellow">and cannot serve as your DJ any more.</span><br>
			V.DJ = 0;
			V.unDJ = 4;
		} else if (!canHear(V.DJ)) {
			// <strong><u><span class="pink">$DJ.slaveName</span></u></strong> can no longer hear <span class="yellow">and cannot serve as your DJ any more.</span><br>
			V.DJ = 0;
			V.unDJ = 5;
		}
	}
	if (V.DJ !== 0) {
		V.DJRepBonus = 0;
		if (V.DJ.relationship === -3 && V.DJ.devotion > 50) {
			V.DJRepBonus += 0.1;
			// $He tries $his best to be your energetic, cheerful wife.
		}
		if (V.DJ.eyes === -2) {
			V.DJRepBonus += 0.15;
		}
		if (V.DJ.skill.entertainment <= 10) {
			// Though $DJ.slaveName does $his best to lead on the club, with $his lack of skill $he can do little.
		} else if (V.DJ.skill.entertainment <= 30) {
			V.DJRepBonus += 0.05;
			// $DJ.slaveName's basic skills marginally <span class="green">improve</span> the atmosphere in $clubName.
		} else if (V.DJ.skill.entertainment <= 60) {
			V.DJRepBonus += 0.1;
			// $DJ.slaveName's skills <span class="green">improve</span> the atmosphere in $clubName.
		} else if (V.DJ.skill.entertainment < 100) {
			V.DJRepBonus += 0.15;
			// $DJ.slaveName's skills greatly <span class="green">improve</span> the atmosphere in $clubName.
		} else if (V.DJ.skill.entertainment >= 100) {
			V.DJRepBonus += 0.20;
			// $DJ.slaveName's mastery immensely <span class="green">;improves</span> the atmosphere in $clubName.
		}
		if (V.DJ.muscles > 5 && V.DJ.muscles <= 95) {
			V.DJRepBonus += 0.05;
			// $His toned body helps $him lead $his fellow club girls by letting $him dance all night.
		}
		if (V.DJ.intelligence + V.DJ.intelligenceImplant > 15) {
			V.DJRepBonus += 0.05 * Math.floor((V.DJ.intelligence + V.DJ.intelligenceImplant) / 32);
			// $He's smart enough to make an actual contribution to the music, greatly enhancing the entire experience.
		}
		if (V.DJ.face > 95) {
			V.DJRepBonus += 0.05;
			// $His great beauty is a further draw, even when $he's in $his DJ booth, but especially when $he comes out to dance.
		}
		if (setup.DJCareers.includes(V.DJ.career)) {
			V.DJRepBonus += 0.05;
			// $He has musical experience from $his life before $he was a slave, a grounding that gives $his tracks actual depth.
		} else if (V.DJ.skill.DJ >= V.masteredXP) {
			V.DJRepBonus += 0.05;
			// $He has musical experience from working for you, giving $his tracks actual depth.
		}

		// The DJ adding to 'club'
		SJVClub(V.slaves[V.slaveIndices[V.DJ.ID]]);
	}

	// Checking for space in the club
	if (V.club > 0 && V.ClubiIDs.length < V.club) {
		clubSpots = V.club - V.ClubiIDs.length;
	}

	// Glory hole slaves adding to 'arcade'
	V.JobIDArray["work a glory hole"].forEach(ID => {
		const s = V.slaves[V.slaveIndices[ID]];
		s.sexAmount = Math.trunc((jsRandom(160, 200) + (20 * (4 - s.anus)) + (10 * (4 - s.vagina)) + Math.trunc(s.health / 5)) * 0.8);
		slaveJobValues.arcade += s.sexAmount;
	});

	// Public sluts adding to 'club'
	V.JobIDArray["serve the public"].forEach(ID => {
		SJVClub(V.slaves[V.slaveIndices[ID]]);
	});

	// This loops through every slave, checks their assignment and applies the appropriate value to both slave and the aggregate
	// The slave value sees use during individual end of the week evaluation
	// The aggregate is used for determining macro variables like 'prices' for slave goods and services to then be used in end week calculations
	V.slaves.forEach(s => {
		// Arcade slaves adding to 'arcade'
		if (s.assignment === "be confined in the arcade") {
			s.sexAmount = (jsRandom(200, 240) + (20 * (4 - (s.anus - 2 * V.arcadeUpgradeInjectors))) + (10 * (4 - (s.vagina - 2 * V.arcadeUpgradeInjectors))) + Math.trunc(s.health / 5));
			slaveJobValues.arcade += s.sexAmount;
		}

		// Club and public sluts adding to 'club'. Also recruiters assigned as sexual ambassador to another arcology.
		if (s.assignment === "serve in the club" || (s.assignment === "recruit girls" && V.recruiterTarget === "other arcologies")) {
			SJVClub(s);
		}
	});

	function SJVClub(s) {
		let toTheClub = 0;
		let beautyMultiplier = 1;
		s.minorInjury = 0;

		// The beauty multiplier
		if (s.sexualFlaw === "attention whore") {
			beautyMultiplier += 0.1;
		}
		if (V.arcologies[0].FSEdoRevivalist !== "unset") {
			beautyMultiplier += V.arcologies[0].FSEdoRevivalist / (V.FSLockinLevel * 3);
		}
		if (((V.universalRulesFacilityWork === 1) && (s.assignment === "serve the public") && (clubSpots > 0)) || (s.assignment === "serve in the club")) {
			if (s.assignment === "serve the public") {
				toTheClub = 1;
				V.slavesGettingHelp += 1;
			}
			if (V.clubAdsSpending !== 0) {
				if (V.clubAdsStacked === 1) {
					if (isStacked(s) === true) {
						beautyMultiplier += 0.05;
						// $His stacked body fits $clubName's ad campaign, getting $him more attention.
					}
				} else if (V.clubAdsStacked === -1) {
					if (isSlim(s) === true) {
						beautyMultiplier += 0.05;
						// $His slim body fits $clubName's ad campaign, getting $him more attention.
					}
				}
				if (V.clubAdsPreg === 1) {
					if (isPreg(s) === true) {
						beautyMultiplier += 0.05;
						// $His gravid body fits $clubName's ad campaign, getting $him more attention.
					}
				} else if (V.clubAdsPreg === -1) {
					if (isNotPreg(s) === true) {
						beautyMultiplier += 0.05;
						// $His flat belly fits $clubName's ad campaign, getting $him more attention.
					}
				}
				if (V.clubAdsModded === 1) {
					if (SlaveStatsChecker.isModded(s) === true) {
						beautyMultiplier += 0.05;
						// Body art like $hers is a major draw.
					}
				} else if (V.clubAdsModded === -1) {
					if (SlaveStatsChecker.isUnmodded(s) === true) {
						beautyMultiplier += 0.05;
						// Very clean bodies like $hers are a major draw.
					}
				}
				if (V.clubAdsImplanted === 1) {
					if (isSurgicallyImproved(s) === true) {
						beautyMultiplier += 0.05;
						// Many citizens come to $clubName looking to fuck a plastic slut like $him.
					}
				} else if (V.clubAdsImplanted === -1) {
					if (isPure(s) === true) {
						beautyMultiplier += 0.05;
						// Many citizens come to $clubName looking to get with a natural $girl like $him.
					}
				}
				if (V.clubAdsOld === 1) {
					if (isYoung(s) === false) {
						beautyMultiplier += 0.05;
						// $He's perfect for $clubName, which practically exists to match citizens up with mature slaves.
					}
				} else if (V.clubAdsOld === -1) {
					if (isYoung(s) === true && s.physical >= 18) {
						beautyMultiplier += 0.05;
						// $He's perfect for $clubName, which practically exists to match citizens up with young slaves.
					}
				} else if (V.clubAdsOld === -2) {
					if (s.physical <= 18 && s.physical >= 13) {
						beautyMultiplier += 0.05;
						// $He's perfect for $clubName, which practically exists to match citizens up with teenage slaves.
					}
				} else if (V.clubAdsOld === -3) {
					if (s.physical < 13) {
						beautyMultiplier += 0.05;
						// $He's perfect for $clubName, which practically exists to match citizens up with $loli slaves.
					}
				}
				if (V.clubAdsXX === 1) {
					if (s.dick === 0) {
						beautyMultiplier += 0.05;
						// Almost everyone who comes to $clubName is looking to fuck a $girl like $him.
					}
				} else if (V.clubAdsXX === -1) {
					if (s.dick > 0) {
						beautyMultiplier += 0.05;
						// Almost everyone who comes to $clubName is looking to poke a $girl who cums when buttfucked.
					}
				}
			}
		}
		if (s.assignment === "serve in the club" || toTheClub === 1) {
			beautyMultiplier += V.DJRepBonus;
		}
		if (canHear(s) === false) {
			beautyMultiplier -= 0.15;
			// $His inability to move to the rhythm of the music is very off putting to those looking to party.
		}

		// Injuries
		if (s.curatives < 1 || s.inflationType !== "curative") {
			if (s.health < -50) {
				s.health -= 8;
				s.minorInjury = 1;
			} else if (s.health < -20 && jsRandom(1, 100) > 50) {
				s.health -= 5;
				s.minorInjury = 1;
			} else if (!canDoVaginal(s)) {
				if (canDoAnal(s)) {
					if (jsRandom(1, 100) > 40 + (10 * (s.skill.anal + s.skill.oral))) {
						s.health -= 5;
						s.minorInjury = 1;
					}
				} else if (jsRandom(1, 100) > 40 + (10 * s.skill.oral)) {
					s.health -= 5;
					s.minorInjury = 1;
				}
			} else if (s.skill.anal + s.skill.oral + s.skill.vaginal < 300) {
				if (jsRandom(1, 100) > 10 + ((s.skill.anal + s.skill.oral + s.skill.vaginal) / 10)) {
					s.minorInjury = 1;
				}
			}
		}
		if (s.minorInjury === 1 && s.assignment === "serve the public") {
			let injuryChance;
			s.health -= 5;
			beautyMultiplier -= 0.05;
			if (canDoAnal(s)) {
				injuryChance = jsRandom(1, 100);
			} else {
				injuryChance = jsRandom(1, 80);
			}
			if (injuryChance > 80) {
				s.minorInjury = "sore ass";
			} else if (injuryChance > 60) {
				s.minorInjury = "black eye";
			} else if (injuryChance > 40) {
				s.minorInjury = "split lip";
			} else if (injuryChance > 20) {
				s.minorInjury = "bad bruise";
			} else {
				s.minorInjury = "sore muscle";
			}
		}
		if ((s.hears === -1 && s.earwear !== "hearing aids") || (s.hears === 0 && s.earwear === "muffling ear plugs") || (s.hears === -2)) {
			if (!canHear(s)) {
				beautyMultiplier -= 0.5;
			} else {
				beautyMultiplier -= 0.75;
			}
		}

		// The amount of sexual acts
		s.sexAmount = Beauty(s) / 2 + 100;

		if (s.assignment === "be the DJ") {
			if ((V.clubSlaves + toTheClubTotal > 0) && (V.clubSlaves + toTheClubTotal < 10)) {
				s.sexAmount *= (10 - V.clubSlaves - toTheClubTotal) / 10;
			}
		}
		s.sexAmount = Math.trunc(s.sexAmount * beautyMultiplier);

		// The quality/value of each sexual act
		s.sexQuality = FResult(s);
		if ((s.releaseRules === "restrictive" || s.releaseRules === "chastity") && s.standardReward !== "orgasm" && s.energy >= 20) {
			s.sexQuality += 2;
		}
		if (canDoAnal(s) && s.anus === 0) {
			s.sexQuality += 5; // This was at 10, not sure what the reasoning behind that was
		}
		if (canDoVaginal(s) && s.vagina === 0) {
			s.sexQuality += 5;
		}
		if (s.devotion > 95 || s.energy > 95) {
			s.sexQuality += 2;
		} else if (s.devotion > 50) {
			s.sexQuality += 1;
		} else if (s.devotion > 20) {
			// Nothing happens
		} else if (s.trust < -20) {
			s.sexQuality -= 1;
		} else {
			s.sexQuality -= 2;
		}
		if (s.assignment === "serve in the club") {
			s.sexQuality += 2;
		} else if (toTheClub === 1) {
			s.sexQuality += 2;
			clubSpots -= 1;
		}
		if (s.assignment !== "recruit girls") {
			slaveJobValues.club += s.sexAmount * s.sexQuality;
		}
	}

	// Saturation penalty for public servants. Even the most beautiful slaves lose some of their shine if they have too much competition.
	if (slaveJobValues.club > 0) {
		slaveJobValues.clubSP = (Math.pow(slaveJobValues.club / 1000, 0.95) * 1000) / slaveJobValues.club;
	}
	return slaveJobValues;
};

// Corporation Value

window.corpValue = function() {
	const V = State.variables;
	if (V.corpIncorporated === 0) {
		return 0;
	}
	let corpAssets = 0;
	if (V.corpDivExtra > 0) {
		corpAssets += V.corpDivExtraDev * 16000 + V.corpDivExtraSlaves * 10000;
	}
	if (V.corpDivLegal > 0) {
		corpAssets += V.corpDivLegalDev * 20000 + V.corpDivLegalSlaves * 15000;
	}
	if (V.corpDivBreak > 0) {
		corpAssets += V.corpDivBreakDev * 7200 + V.corpDivBreakSlaves * 10000 + V.corpDivBreakSlaves2 * 15000;
	}
	if (V.corpDivSurgery > 0) {
		corpAssets += V.corpDivSurgeryDev * 16000 + V.corpDivSurgerySlaves * 15000 + V.corpDivSurgerySlaves2 * 23000;
	}
	if (V.corpDivTrain > 0) {
		if (V.corpDivSurgery + V.corpDivTrain < 2 && V.corpDivTrainSurgerySwitch === 0) {
			corpAssets += V.corpDivTrainDev * 20000 + V.corpDivTrainSlaves * 15000 + V.corpDivTrainSlaves2 * 26000;
		} else if (V.corpDivTrainSurgerySwitch === 1 && V.corpDivTrainSurgeryTimer < 5) {
			corpAssets += V.corpDivTrainDev * 20000 + V.corpDivTrainSlaves * (15000 + 1600 * V.corpDivTrainSurgeryTimer) + V.corpDivTrainSlaves2 * (26000 + 1600 * V.corpDivTrainSurgeryTimer);
		} else {
			corpAssets += V.corpDivTrainDev * 20000 + V.corpDivTrainSlaves * 23000 + V.corpDivTrainSlaves2 * 34000;
		}
	}
	if (V.corpDivArcade > 0) {
		corpAssets += V.corpDivArcadeDev * 4000 + V.corpDivArcadeSlaves * 10000;
	}
	if (V.corpDivMenial > 0) {
		corpAssets += V.corpDivMenialDev * 5200 + V.corpDivMenialSlaves * 15000;
	}
	if (V.corpDivDairy > 0) {
		corpAssets += V.corpDivDairyDev * 12000 + V.corpDivDairySlaves * 23000;
	}
	if (V.corpDivWhore > 0) {
		if (V.corpDivSurgery + V.corpDivTrain < 2 && V.corpDivTrainSurgerySwitch === 0) {
			corpAssets += V.corpDivWhoreDev * 16000 + V.corpDivWhoreSlaves * 26000;
		} else if (V.corpDivTrainSurgerySwitch === 1 && V.corpDivTrainSurgeryTimer < 20) {
			corpAssets += V.corpDivWhoreDev * 16000 + V.corpDivWhoreSlaves * (26000 + 400 * V.corpDivTrainSurgeryTimer);
		} else {
			corpAssets += V.corpDivWhoreDev * 16000 + V.corpDivWhoreSlaves * 34000;
		}
	}
	return corpAssets + V.corpDividend + V.corpCash;
};

// Corporation Share Price
// A positive q means adding shares to the market, negative means removing them

window.corpSharePrice = function(q = 0) {
	const V = State.variables;
	if (V.corpIncorporated === 0) {
		return 0;
	}
	return Math.trunc(1000 * (corpValue() / (V.personalShares + V.publicShares + q)));
};

// Corporation Division Slave room
// The amount of additional slaves you can fit in a division
// Can we condense this?

window.corpDivBreakSlavesRoom = function() {
	const V = State.variables;
	if (V.corpDivBreak === 1 && V.corpDivBreakDev > V.corpDivBreakSlaves) {
		return V.corpDivBreakDev - V.corpDivBreakSlaves;
	}
	return 0;
};

window.corpDivSurgerySlavesRoom = function() {
	const V = State.variables;
	if (V.corpDivSurgery === 1 && V.corpDivSurgeryDev > V.corpDivSurgerySlaves) {
		return V.corpDivSurgeryDev - V.corpDivSurgerySlaves;
	}
	return 0;
};

window.corpDivTrainSlavesRoom = function() {
	const V = State.variables;
	if (V.corpDivTrain === 1 && V.corpDivTrainDev > V.corpDivTrainSlaves) {
		return V.corpDivTrainDev - V.corpDivTrainSlaves;
	}
	return 0;
};

window.corpDivArcadeSlavesRoom = function() {
	const V = State.variables;
	if (V.corpDivArcade === 1 && V.corpDivArcadeDev > V.corpDivArcadeSlaves) {
		return V.corpDivArcadeDev - V.corpDivArcadeSlaves;
	}
	return 0;
};

window.corpDivMenialSlavesRoom = function() {
	const V = State.variables;
	if (V.corpDivMenial === 1 && V.corpDivMenialDev > V.corpDivMenialSlaves) {
		return V.corpDivMenialDev - V.corpDivMenialSlaves;
	}
	return 0;
};

window.corpDivDairySlavesRoom = function() {
	const V = State.variables;
	if (V.corpDivDairy === 1 && V.corpDivDairyDev > V.corpDivDairySlaves) {
		return V.corpDivDairyDev - V.corpDivDairySlaves;
	}
	return 0;
};

window.corpDivWhoreSlavesRoom = function() {
	const V = State.variables;
	if (V.corpDivWhore === 1 && V.corpDivWhoreDev > V.corpDivWhoreSlaves) {
		return V.corpDivWhoreDev - V.corpDivWhoreSlaves;
	}
	return 0;
};

// Corporation race blacklisting/whitelisting
// race is the lowercase string representing the race, 'blacklist' is either 1 or 0. 1 means we are blacklisting and 0 means we are whitelisting said race
window.corpBlacklistRace = function(race, blacklist) {
	let raceArray = State.variables.corpSpecRaces;
	if (raceArray.length > 0 && blacklist === 1) {
		raceArray.delete(race);
	} else if (blacklist === 1) {
		raceArray = setup.filterRacesLowercase.filter(x => x !== race);
	} else {
		raceArray.push(race);
	}
	return raceArray;
};

window.getSlaveStatisticData = function(s, facility) {
	if (!s || !facility) {
		// Base data, even without facility
		return {
			ID: s.ID,
			slaveName: s.slaveName,
			customLabel: s.custom.label,
			income: 0,
			adsIncome: 0,
			rep: 0,
			food: 0,
			cost: getSlaveCost(s),
			customers: 0 /* brothel, club, ... */
		};
	}

	if (!facility.income) {
		facility.income = new Map();
	}

	if (facility.income.has(s.ID)) {
		return facility.income.get(s.ID);
	}

	const data = {
		ID: s.ID,
		slaveName: s.slaveName,
		customLabel: s.custom.label,
		income: 0,
		adsIncome: 0,
		rep: 0,
		food: 0,
		cost: getSlaveCost(s),
		customers: 0 /* brothel, club, ... */
	};
	facility.income.set(s.ID, data);
	return data;
};

window.initFacilityStatistics = function(facility = {}) {
	facility.adsIncome = 0;
	facility.maintenance = 0;
	facility.totalIncome = 0;
	facility.totalExpenses = 0;
	facility.profit = 0;
	facility.income = new Map();
	return facility;
};

/*

Welcome to the new way to spend and make money, all while having it recorded: cashX! In the past, costs were directly deducted from $cash, with something like <<set $cash -= 100>>.

The new system will still happily spend your money, but it will also record it in the appropriate budget category and (optionally) the appropriate slave as well.

Let's say you were going to spend 100 on your favorite $activeSlave with cashX. You might try:

<<run cashX(-100, "slaveMod", $activeSlave)>>

There we go!
1. -100 taken from your account
2. Recorded: -100 for the slaveMod category, to be displayed on the Budget screen
3. Recorded: -100 noted in your activeSlave's permanent record. $He better get busy paying that off!

cashX can be used in JS as well, and can be included in [[]] style links.

Make sure that expenses arrive in the COST slot as a negative, they are often positive in code. Use the new function forceNeg or pass it along on a temporary variable if needed.

Costs don't have to be numbers either, you can use variables. <<run cashX(forceNeg($contractCost), "slaveTransfer", $activeSlave)>>. forceNeg makes sure that whatever value $contractCost has is negative, and will therefore be recorded as an expense. You don't have to use it if you're sure the number you are passing along is negative.

A full list of categories (slaveMod, slaveTransfer, event) are in the widget "setupLastWeeksCash", currently found in costsWidgets.tw. It's important to match your cost to one of those categories (or add a new one there, and display it in costsBudget.tw.)

The third category, the "slave slot" is completely optional. Sometimes you just want to spend money by yourself.

*/
window.cashX = function(cost, what, who) {
	const V = State.variables;

	if (!Number.isFinite(cost)) {
		V.lastWeeksCashErrors += `Expected a finite number for ${what}, but got ${cost}<br>`;
		return 0;
	}

	// remove fractions from the money
	cost = Math.trunc(cost);

	// Spend the money
	V.cash += cost;

	// INCOME
	if (cost > 0) {
		// record the action
		if (typeof V.lastWeeksCashIncome[what] !== 'undefined') {
			V.lastWeeksCashIncome[what] += cost;
		} else {
			V.lastWeeksCashErrors += `Unknown place "${what}" gained you ${cost}<br>`;
		}

		// record the slave, if available
		if (typeof who !== 'undefined') {
			who.lastWeeksCashIncome += cost;
			who.lifetimeCashIncome += cost;
		}
	} else if (cost < 0) { // EXPENSES
		// record the action
		if (typeof V.lastWeeksCashExpenses[what] !== 'undefined') {
			V.lastWeeksCashExpenses[what] += cost;
		} else {
			V.lastWeeksCashErrors += `Unknown place "${what}" charged you ${cost}<br>`;
		}

		// record the slave, if available
		if (typeof who !== 'undefined') {
			if (what === "slaveTransfer") {
				who.slaveCost = cost;
			} else {
				who.lifetimeCashExpenses += cost;
			}
		}
	}
	return cost;
};

window.repX = function(rep, what, who) {
	const V = State.variables;

	if (!Number.isFinite(rep)) {
		V.lastWeeksRepErrors += `Expected a finite number for ${what}, but got ${rep}<br>`;
		return 0;
	}

	// round the change
	rep = Math.trunc(rep);

	// INCOME
	// These are all scaled relative to current rep except when recording the who, to keep comparisons between slaves possible across times. This quite drastically reduces rep income at high levels of rep and only slightly at low levels.
	if (rep > 0) {
		// record the slave, if available
		if (typeof who !== 'undefined') {
			who.lastWeeksRepIncome += rep;
			who.lifetimeRepIncome += rep;
		}

		// record the action
		if (what === "cheating" || passage() === "init" || passage() === "init Nationalities") {
			/* we don't want to curve startup or cheating.*/
			V.lastWeeksRepIncome[what] += rep;
		} else if (typeof V.lastWeeksRepIncome[what] !== 'undefined') {
			rep = Math.round(Math.pow(1000 * rep + Math.pow(V.rep, 2), 0.5) - V.rep) * (V.corpEasy + 1);
			V.lastWeeksRepIncome[what] += rep;
		} else {
			V.lastWeeksRepErrors += `Unknown place "${what}" gained you ${rep}<br>`;
		}
	} else if (rep < 0) { // EXPENSES
		// record the action
		if (typeof V.lastWeeksRepExpenses[what] !== 'undefined') {
			V.lastWeeksRepExpenses[what] += rep;
		} else {
			V.lastWeeksRepErrors += `Unknown place "${what}" cost you ${rep}<br>`;
		}

		// record the slave, if available
		if (typeof who !== 'undefined') {
			who.lastWeeksRepExpenses += rep;
			who.lifetimeRepExpenses += rep;
		}
	}

	// Apply the reputation change
	V.rep += rep;

	// Check if total rep is over cap, and use "overflow" category to expense it down if needed.
	if (V.rep > 20000) {
		V.lastWeeksRepExpenses.overflow += (20000 - V.rep);
		V.rep = 20000;
	} else if (V.rep < 0) { // Rep should never be lower than 0. Record this rounding purely to keep the books balanced.
		V.lastWeeksRepIncome.overflow += (0 - V.rep);
		V.rep = 0;
	}

	return rep;
};

window.forceNeg = function(x) {
	return -Math.abs(x);
};

Number.prototype.toFixedHTML = function() {
	return num(Number.prototype.toFixed.apply(this, arguments)).replace(/\.0+$/, '<span style="opacity: 0.3">$&</span>');
};