code:
/* Major props to the anons who worked together to forge the Super Pregnancy Project. Let your legacy go unforgotten.*/
window.getPregBellySize = function(s) {
	let targetLen;
	let gestastionWeek = s.preg;
	let fetuses = s.pregType;
	let phi = 1.618;

	if (gestastionWeek <= 32) {
		targetLen = ((0.00006396 * Math.pow(gestastionWeek, 4)) - (0.005501 * Math.pow(gestastionWeek, 3)) + (0.161 * Math.pow(gestastionWeek, 2)) - (0.76 * gestastionWeek) + 0.208);
	} else if (gestastionWeek <= 106) {
		targetLen = ((-0.0000004675 * Math.pow(gestastionWeek, 4)) + (0.0001905 * Math.pow(gestastionWeek, 3)) - (0.029 * Math.pow(gestastionWeek, 2)) + (2.132 * gestastionWeek) - 16.575);
	} else {
		targetLen = ((-0.00003266 * Math.pow(gestastionWeek, 2)) + (0.076 * gestastionWeek) + 43.843);
	}

	let bellySize = ((4 / 3) * (Math.PI) * (phi / 2) * (Math.pow((targetLen / 2), 3)) * fetuses);
	return bellySize;
};

/**
 * @param {App.Entity.SlaveState} slave
 * @returns {string}
 */
window.bellyAdjective = function(slave) {
	if (slave.belly >= 1500) {
		if (slave.belly >= 1000000) {
			if (slave.preg > slave.pregData.normalBirth / 4) {
				return 'unfathomably distended, brimming with life';
			} else {
				return `unfathomable`;
			}
		} else if (slave.belly >= 750000) {
			if (slave.preg > slave.pregData.normalBirth / 4) {
				return 'monolithic bulging';
			} else {
				return `monolithic`;
			}
		} else if (slave.belly >= 600000) {
			if (slave.preg > slave.pregData.normalBirth / 4) {
				return 'titanic bulging';
			} else {
				return `titanic`;
			}
		} else if (slave.belly >= 450000) {
			if (slave.preg > slave.pregData.normalBirth / 4) {
				return 'gigantic bulgy';
			} else {
				return `gigantic`;
			}
		} else if (slave.belly >= 300000) {
			return 'massive';
		} else if (slave.belly >= 100000) {
			return 'giant';
		} else if (slave.belly >= 15000) {
			return 'huge';
		} else if (slave.belly >= 10000) {
			return 'big';
		} else {
			return `swollen`;
		}
	}
	return "";
};

/* calculates and returns expected ovum count during conception*/
window.setPregType = function(actor) {
	/* IMHO rework is possible. Can be more interesting to play, if this code will take in account more body conditions - age, fat, food, hormone levels, etc. */

	let ovum = jsRandom(actor.pregData.normalOvaMin, actor.pregData.normalOvaMax); // for default human profile it's always 1.
	let fertilityStack = 0; // adds an increasing bonus roll for stacked fertility drugs

	/* Suggestion for better animal pregnancy support - usage of another variable then ovum for fertility drugs bonus, and then adding actor.pregData.drugsEffect multiplier to it before adding to ovum. Example:

		let bonus = 0;

		... (code below where ovum changed to bonus)

		bonus *= actor.pregData.drugsEffect;
		ovum += bonus;

	*/

	if (actor.broodmother < 1) { // Broodmothers should be not processed here. Necessary now.
		if (typeof actor.readyOva === "number" && actor.readyOva !== 0) {
			ovum = actor.readyOva; // just single override; for delayed impregnation cases
		} else if (actor.ID === -1) {
			if (actor.geneticQuirks.fertility === 2 && actor.geneticQuirks.hyperFertility === 2) { // Do not mix with sperm
				if (actor.fertDrugs === 1) {
					ovum += jsEither([2, 3, 3, 3, 3, 4, 4, 5]);
				} else {
					ovum += jsEither([1, 1, 2, 2, 3, 3, 4]);
				}
				if (actor.forcedFertDrugs > 0) {
					ovum += jsEither([3, 3, 4, 4, 5]);
				}
			} else if (actor.geneticQuirks.hyperFertility === 2) { // Predisposed to multiples
				if (actor.fertDrugs === 1) {
					ovum += jsEither([1, 2, 2, 2, 2, 3, 3, 4]);
				} else {
					ovum += jsEither([0, 1, 1, 1, 1, 1, 2, 3]);
				}
				if (actor.forcedFertDrugs > 0) {
					ovum += jsEither([2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4]);
				}
			} else if (actor.geneticQuirks.fertility === 2) { // Predisposed to twins
				if (actor.fertDrugs === 1) {
					ovum += jsEither([1, 1, 2, 2, 2, 2, 3, 3]);
				} else {
					ovum += jsEither([0, 0, 0, 1, 1, 1, 1, 1, 1, 2]);
				}
				if (actor.forcedFertDrugs > 0) {
					ovum += jsEither([1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4]);
				}
			} else {
				if (actor.fertDrugs === 1) {
					ovum += jsEither([0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3]);
				} else {
					ovum += jsEither([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
				}
				if (actor.forcedFertDrugs > 0) {
					ovum += jsEither([0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4]);
				}
			}
			ovum = Math.clamp(ovum, 0, 8);
		} else if (actor.preg === 0 || (actor.geneticQuirks.superfetation > 1 && actor.preg >= 0)) {
			if (actor.eggType === "horse" || actor.eggType === "cow") {
				if (actor.geneticQuirks.fertility === 2 && actor.geneticQuirks.hyperFertility === 2) { // Do not mix with sperm
					ovum += jsEither([0, 0, 0, 0, 0, 0, 1]);
					fertilityStack += 0.8;
				} else if (actor.geneticQuirks.hyperFertility === 2) { // Predisposed to multiples
					fertilityStack += 0.4;
				} else if (actor.geneticQuirks.fertility === 2) { // Predisposed to twins
					fertilityStack += 0.2;
				}
				if (actor.ovaImplant === "fertility") {
					fertilityStack += 0.3;
				}
				if (actor.hormones === 2) {
					fertilityStack += 0.2;
				}
				if (actor.hormoneBalance >= 200) {
					fertilityStack += 0.3;
				}
				if (actor.diet === "fertility") {
					fertilityStack += 0.3;
				}
				if (State.variables.masterSuitePregnancyFertilitySupplements === 1 && ((actor.assignment === "serve in the master suite" || actor.assignment === "be your Concubine"))) {
					fertilityStack += 0.5;
				}
				if (State.variables.reproductionFormula === 1 && (State.variables.week - actor.weekAcquired > 0)) {
					fertilityStack += 0.2;
				}
				if (actor.drugs === "super fertility drugs") {
					fertilityStack += 1.6;
				} else if (actor.drugs === "fertility drugs") {
					fertilityStack += 0.6;
				}
				fertilityStack = Math.floor(fertilityStack);
				if (State.variables.seeHyperPreg === 1) {
					if (actor.drugs === "super fertility drugs") {
						ovum += jsRandom(0, fertilityStack * 2);
					} else {
						ovum += jsRandom(0, fertilityStack);
					}
					if (actor.ovaImplant === "sympathy") {
						ovum *= 2;
					}
				} else {
					ovum += jsRandom(0, fertilityStack);
					if (actor.ovaImplant === "sympathy") {
						ovum *= 2;
						if (ovum > 4) {
							ovum = 4;
						}
					} else if (ovum > 3) {
						ovum = 3;
					}
				}
			} else if (actor.eggType === "dog") {
				if (actor.geneticQuirks.fertility === 2 && actor.geneticQuirks.hyperFertility === 2) { // Do not mix with sperm
					ovum += jsEither([1, 2, 2, 3]);
					fertilityStack++;
					fertilityStack++;
					fertilityStack++;
				} else if (actor.geneticQuirks.hyperFertility === 2) { // Predisposed to multiples
					ovum += jsEither([0, 1, 1, 2]);
					fertilityStack++;
					fertilityStack++;
				} else if (actor.geneticQuirks.fertility === 2) { // Predisposed to twins
					ovum += jsEither([0, 0, 0, 0, 1]);
					fertilityStack++;
				}
				if (actor.ovaImplant === "fertility") {
					ovum += jsEither([0, 0, 0, 0, 1]);
					fertilityStack++;
				}
				if (actor.hormones === 2) {
					ovum += jsEither([0, 0, 0, 1, 1, 1, 1, 2]);
					fertilityStack++;
				}
				if (actor.hormoneBalance >= 200) {
					ovum += jsEither([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2]);
					fertilityStack++;
				}
				if (actor.diet === "fertility") {
					ovum += jsEither([0, 0, 0, 0, 0, 0, 0, 0, 1]);
					fertilityStack++;
				}
				if (State.variables.masterSuitePregnancyFertilitySupplements === 1 && ((actor.assignment === "serve in the master suite" || actor.assignment === "be your Concubine"))) {
					ovum += jsEither([0, 0, 0, 1, 1, 2, 2, 2, 3, 3]);
					fertilityStack++;
					fertilityStack++;
				}
				if (State.variables.reproductionFormula === 1 && (State.variables.week - actor.weekAcquired > 0)) {
					fertilityStack++;
				}
				if (actor.drugs === "super fertility drugs") {
					ovum += jsEither([1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5]);
					fertilityStack++;
					fertilityStack++;
					fertilityStack++;
					fertilityStack++;
					fertilityStack++;
				} else if (actor.drugs === "fertility drugs") {
					ovum += jsEither([0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3]);
					fertilityStack++;
				}
				if (State.variables.seeHyperPreg === 1) {
					if (actor.drugs === "super fertility drugs") {
						ovum += jsRandom(0, fertilityStack * 2);
					} else {
						ovum += jsRandom(0, fertilityStack);
					}
					if (actor.ovaImplant === "sympathy") {
						ovum *= 2;
					}
				} else {
					ovum += jsRandom(0, fertilityStack);
					if (actor.ovaImplant === "sympathy") {
						ovum *= 2;
						if (ovum > 8) {
							ovum = jsEither([6, 8]);
						}
					} else if (ovum > 8) {
						ovum = jsRandom(6, 8);
					}
				}
			} else if (actor.eggType === "pig") {
				if (actor.geneticQuirks.fertility === 2 && actor.geneticQuirks.hyperFertility === 2) { // Do not mix with sperm
					ovum += jsRandom(4, 8);
					fertilityStack += 16;
				} else if (actor.geneticQuirks.hyperFertility === 2) { // Predisposed to multiples
					ovum += jsRandom(2, 6);
					fertilityStack += 10;
				} else if (actor.geneticQuirks.fertility === 2) { // Predisposed to twins
					ovum += jsRandom(2, 4);
					fertilityStack += 6;
				}
				if (actor.ovaImplant === "fertility") {
					ovum += jsRandom(4, 12);
					fertilityStack += 6;
				}
				if (actor.hormones === 2) {
					ovum += jsRandom(0, 4);
					fertilityStack += 3;
				}
				if (actor.hormoneBalance >= 200) {
					ovum += jsRandom(0, 4);
					fertilityStack += 3;
				}
				if (actor.diet === "fertility") {
					ovum += jsRandom(4, 10);
					fertilityStack += 6;
				}
				if (State.variables.masterSuitePregnancyFertilitySupplements === 1 && ((actor.assignment === "serve in the master suite" || actor.assignment === "be your Concubine"))) {
					ovum += jsRandom(8, 16);
					fertilityStack += 10;
				}
				if (State.variables.reproductionFormula === 1 && (State.variables.week - actor.weekAcquired > 0)) {
					fertilityStack += 2;
				}
				if (actor.drugs === "super fertility drugs") {
					ovum += jsRandom(10, 40);
					fertilityStack += 32;
				} else if (actor.drugs === "fertility drugs") {
					ovum += jsRandom(10, 20);
					fertilityStack += 16;
				}
				if (State.variables.seeHyperPreg === 1) {
					if (actor.drugs === "super fertility drugs") {
						ovum += jsRandom(fertilityStack / 2, fertilityStack * 2);
					} else {
						ovum += jsRandom(fertilityStack / 4, fertilityStack);
					}
					if (actor.ovaImplant === "sympathy") {
						ovum *= 2;
					}
				} else {
					ovum += jsRandom(0, fertilityStack);
					if (actor.ovaImplant === "sympathy") {
						ovum *= 2;
						if (ovum > 76) {
							ovum = jsEither([70, 72, 74, 76]);
						}
					} else if (ovum > 75) {
						ovum = jsRandom(60, 75);
					}
				}
			} else {
				if (actor.geneticQuirks.fertility === 2 && actor.geneticQuirks.hyperFertility === 2) { // Do not mix with sperm
					ovum += jsEither([1, 2, 2, 3]);
					fertilityStack++;
					fertilityStack++;
					fertilityStack++;
					fertilityStack++;
				} else if (actor.geneticQuirks.hyperFertility === 2) { // Predisposed to multiples
					ovum += jsEither([0, 1, 1, 2]);
					fertilityStack++;
					fertilityStack++;
				} else if (actor.geneticQuirks.fertility === 2) { // Predisposed to twins
					ovum += jsEither([0, 0, 0, 0, 1]);
					fertilityStack++;
				} else {
					ovum += jsEither([0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); // base chance for twins
				}
				if (actor.ovaImplant === "fertility") {
					ovum += jsEither([0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
					fertilityStack++;
				}
				if (actor.hormones === 2) {
					ovum += jsEither([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2]);
					fertilityStack++;
				}
				if (actor.hormoneBalance >= 200) {
					ovum += jsEither([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2]);
					fertilityStack++;
				}
				if (actor.diet === "fertility") {
					ovum += jsEither([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]);
					fertilityStack++;
				}
				if (State.variables.masterSuitePregnancyFertilitySupplements === 1 && ((actor.assignment === "serve in the master suite" || actor.assignment === "be your Concubine"))) {
					ovum += jsEither([0, 0, 0, 1, 1, 2, 2, 2, 3, 3]);
					fertilityStack++;
					fertilityStack++;
				}
				if (State.variables.reproductionFormula === 1 && (State.variables.week - actor.weekAcquired > 0)) {
					fertilityStack++;
				}
				if (actor.drugs === "super fertility drugs") {
					ovum += jsEither([1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5]);
					fertilityStack++;
					fertilityStack++;
					fertilityStack++;
					fertilityStack++;
					fertilityStack++;
				} else if (actor.drugs === "fertility drugs") {
					ovum += jsEither([0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3]);
					fertilityStack++;
				}
				if (State.variables.seeHyperPreg === 1) {
					if (actor.drugs === "super fertility drugs") {
						ovum += jsRandom(0, fertilityStack * 2);
					} else {
						ovum += jsRandom(0, fertilityStack);
					}
					if (actor.ovaImplant === "sympathy") {
						ovum *= 2;
					}
				} else {
					ovum += jsRandom(0, fertilityStack);
					if (actor.ovaImplant === "sympathy") {
						ovum *= 2;
						if (ovum > 12) {
							ovum = jsEither([10, 12]);
						}
					} else if (ovum > 12) {
						ovum = jsRandom(6, 12);
					}
				}
			}
		}
	}
	if (actor.geneticQuirks.superfetation === 2 && actor.womb.length > 0) {
		ovum = Math.ceil(ovum / 4);
	}
	return ovum;
};

/*
 Penetrative ability, ability to become pregnant, and canBreed() must be checked outside of this. Designed to assume .eggType === "human".
 target is the slave to get pregnant. Also accepts the PC.
 chance is the % chance to conceive.
 hole control's the hole involved (0 - vagina, 1 - ass, 2 - both). .mpreg did this.
 fatherID is the ID of her sire or 0 if undefined.
 displayOverride is an override if defined - fatherID must be defined in this case.
*/
window.knockMeUp = function(target, chance, hole, fatherID, displayOverride) {
	const V = State.variables;
	let pronouns;
	let He;
	let r = ``;
	if (target.ID !== -1) {
		pronouns = getPronouns(target);
		He = capFirstChar(pronouns.pronoun);
	}
	if (V.seePreg !== 0) {
		// eslint-disable-next-line no-nested-ternary
		if (jsRandom(0, 99) < (chance + (V.reproductionFormula * ((target.pregSource <= 0) ? ((target.ID === -1) ? 0 : 10) : 20)))) {
			if (target.mpreg === hole) {
				if (target.pregWeek <= 0) {
					target.preg = 1;
					target.pregSource = (!fatherID ? 0 : fatherID);
					if (target.ID !== -1) {
						target.pregWeek = 1;
					}
				}

				target.pregType = setPregType(target);
				WombImpregnate(target, target.pregType, target.pregSource, 1);

				if (V.menstruation === 1) {
					//
				} else if (!displayOverride) {
					target.pregKnown = 1;
					if (target.ID === -1) {
						/* r += "You have gotten pregnant."; */
					} else {
						r += `<span class="lime">${He} has become pregnant.</span>`;
					}
				} else {
					target.pregKnown = 1;
				}
			} else if (hole === 2) {
				if (target.pregWeek <= 0) {
					target.preg = 1;
					target.pregSource = (!fatherID ? 0 : fatherID);
					if (target.ID !== -1) {
						target.pregWeek = 1;
					}
				}

				target.pregType = setPregType(target);
				WombImpregnate(target, target.pregType, target.pregSource, 1);

				if (V.menstruation === 1) {
					//
				} else if (!displayOverride) {
					target.pregKnown = 1;
					if (target.ID === -1) {
						/* r += "You have gotten pregnant."; */
					} else {
						r += `<span class="lime">${He} has become pregnant.</span>`;
					}
					if (target.geneticQuirks.superfetation === 2 && target.womb.length > 0) {
						if (V.seeHyperPreg === 1) {
							target.fertPeak = 1;
						} else {
							target.fertPeak = 4;
						}
					}
				} else {
					target.pregKnown = 1;
					if (target.geneticQuirks.superfetation === 2 && target.womb.length > 0) {
						if (V.seeHyperPreg === 1) {
							target.fertPeak = 1;
						} else {
							target.fertPeak = 4;
						}
					}
				}
			}
		}
	}
	return r;
};

window.getIncubatorReserved = function( /* slaves */ ) {
	return FetusGlobalReserveCount("incubator");
};

window.getNurseryReserved = function( /* slaves */ ) {
	return FetusGlobalReserveCount("nursery");
};

window.findFather = function(fatherID) {
	let father;
	let V = State.variables;

	father = V.slaves[V.slaveIndices[fatherID]];
	if (father === undefined) {
		if (V.incubator > 0) {
			father = V.tanks.find(s => s.ID === fatherID);
		}
	}
	if (father === undefined) {
		if (V.nursery > 0) {
			father = V.cribs.find(s => s.ID === fatherID);
		}
	}

	return father;
};

window.adjustFatherProperty = function(actor, property, newValue) {
	let father = findFather(actor.ID);
	if (father) {
		father[property] = newValue;
	}
};

/* OLD
window.adjustFatherProperty = function(actor, property, newValue) {
	let V = State.variables;
	let fatherIndex;

	fatherIndex = V.slaves.findIndex(function(s) { return s.ID === actor.ID; });
	if (fatherIndex > 0) {
		V.slaves[fatherIndex][property] = newValue;
	} else if (V.incubator > 0) {
		fatherIndex = V.tanks.findIndex(function(s) { return s.ID === actor.ID; });
		if (fatherIndex > 0) {
			V.tanks[fatherIndex][property] = newValue;
		}
	}
	if (fatherIndex === -1) {
		if (V.nursery > 0) {
			fatherIndex = V.cribs.findIndex(function(s) { return s.ID === actor.ID; });
			if (fatherIndex !== -1) {
				V.cribs[fatherIndex][property] = newValue;
			}
		}
	}
}
*/

/* not to be used until that last part is defined. It may become slave.boobWomb.volume or some shit */
/**
 * @param {App.Entity.SlaveState} slave
 * @returns {number}
 */
window.getBaseBoobs = function(slave) {
	return slave.boobs - slave.boobsImplant - slave.boobsMilk - slave.boobsWombVolume;
};


code:
window.sortDomObjects = function(objects, attrName, reverse = 0) {
	reverse = (reverse) ? -1 : 1;

	function sortingByAttr(a, b) {
		let aVal = a.getAttribute(attrName);
		let bVal = b.getAttribute(attrName);
		let aInt = parseInt(aVal);
		if (!isNaN(aInt)) {
			return ((parseInt(bVal) - aInt) * reverse);
		} else if (bVal > aVal) {
			return -1 * reverse;
		}
		return ((aVal === bVal) ? 0 : 1) * reverse;
	}
	return objects.toArray().sort(sortingByAttr);
};

window.sortButtonsByDevotion = function() {
	let $sortedButtons = $('#qlWrapper button').remove();
	$sortedButtons = sortDomObjects($sortedButtons, 'data-devotion');
	$($sortedButtons).appendTo($('#qlWrapper'));
	quickListBuildLinks();
};

window.sortButtonsByTrust = function() {
	let $sortedButtons = $('#qlWrapper button').remove();
	$sortedButtons = sortDomObjects($sortedButtons, 'data-trust');
	$($sortedButtons).appendTo($('#qlWrapper'));
	quickListBuildLinks();
};

window.quickListBuildLinks = function() {
	$("[data-scroll-to]").click(function() {
		let $this = $(this),
			$toElement = $this.attr('data-scroll-to');
		// note the * 1 enforces $offset to be an integer, without
		// it we scroll to True, which goes nowhere fast.
		let $offset = $this.attr('data-scroll-offset') * 1 || 0;
		let $speed = $this.attr('data-scroll-speed') * 1 || 500;
		// Use javascript scrollTop animation for in page navigation.
		$('html, body').animate({
			scrollTop: $($toElement).offset().top + $offset
		}, $speed);
	});
};

window.sortIncubatorPossiblesByName = function() {
	let $sortedIncubatorPossibles = $('#qlIncubator div.possible').detach();
	$sortedIncubatorPossibles = sortDomObjects($sortedIncubatorPossibles, 'data-name');
	$($sortedIncubatorPossibles).appendTo($('#qlIncubator'));
};

window.sortIncubatorPossiblesByPregnancyWeek = function() {
	let $sortedIncubatorPossibles = $('#qlIncubator div.possible').detach();
	$sortedIncubatorPossibles = sortDomObjects($sortedIncubatorPossibles, 'data-preg-week');
	$($sortedIncubatorPossibles).appendTo($('#qlIncubator'));
};

window.sortIncubatorPossiblesByPregnancyCount = function() {
	let $sortedIncubatorPossibles = $('#qlIncubator div.possible').detach();
	$sortedIncubatorPossibles = sortDomObjects($sortedIncubatorPossibles, 'data-preg-count');
	$($sortedIncubatorPossibles).appendTo($('#qlIncubator'));
};

window.sortIncubatorPossiblesByReservedSpots = function() {
	let $sortedIncubatorPossibles = $('#qlIncubator div.possible').detach();
	$sortedIncubatorPossibles = sortDomObjects($sortedIncubatorPossibles, 'data-reserved-spots');
	$($sortedIncubatorPossibles).appendTo($('#qlIncubator'));
};

window.sortIncubatorPossiblesByPreviousSort = function() {
	let sort = State.variables.sortIncubatorList;
	if (sort !== 'unsorted') {
		if (sort === 'Name') {
			sortIncubatorPossiblesByName();
		} else if (sort === 'Reserved Incubator Spots') {
			sortIncubatorPossiblesByReservedSpots();
		} else if (sort === 'Pregnancy Week') {
			sortIncubatorPossiblesByPregnancyWeek();
		} else if (sort === 'Number of Children') {
			sortIncubatorPossiblesByPregnancyCount();
		}
	}
};

window.sortNurseryPossiblesByName = function() {
	let $sortedNurseryPossibles = $('#qlNursery div.possible').detach();
	$sortedNurseryPossibles = sortDomObjects($sortedNurseryPossibles, 'data-name');
	$($sortedNurseryPossibles).appendTo($('#qlNursery'));
};

window.sortNurseryPossiblesByPregnancyWeek = function() {
	let $sortedNurseryPossibles = $('#qlNursery div.possible').detach();
	$sortedNurseryPossibles = sortDomObjects($sortedNurseryPossibles, 'data-preg-week');
	$($sortedNurseryPossibles).appendTo($('#qlNursery'));
};

window.sortNurseryPossiblesByPregnancyCount = function() {
	let $sortedNurseryPossibles = $('#qlNursery div.possible').detach();
	$sortedNurseryPossibles = sortDomObjects($sortedNurseryPossibles, 'data-preg-count');
	$($sortedNurseryPossibles).appendTo($('#qlNursery'));
};

window.sortNurseryPossiblesByReservedSpots = function() {
	let $sortedNurseryPossibles = $('#qlNursery div.possible').detach();
	$sortedNurseryPossibles = sortDomObjects($sortedNurseryPossibles, 'data-reserved-spots');
	$($sortedNurseryPossibles).appendTo($('#qlNursery'));
};

window.sortNurseryPossiblesByPreviousSort = function() {
	let sort = State.variables.sortNurseryList;
	if (sort !== 'unsorted') {
		if (sort === 'Name') {
			sortNurseryPossiblesByName();
		} else if (sort === 'Reserved Nursery Spots') {
			sortNurseryPossiblesByReservedSpots();
		} else if (sort === 'Pregnancy Week') {
			sortNurseryPossiblesByPregnancyWeek();
		} else if (sort === 'Number of Children') {
			sortNurseryPossiblesByPregnancyCount();
		}
	}
};


code:
/* This is modified radiobutton macro, for automatic checked state setup*/
/* Usage (be sure to use quotes around parameters):

	<<rbutton "$variable" "value">>
Or:
	<<rbutton "$variable" "value" "HTML_element_ID" "Text to replace with, inside html element with ID from previous parameter. <br> HTML tags allowed.">>

Group of radiobutton will be created based on variable name. Checked state will be set up if variable contain value matched with second parameter. Full form of macro call can be used to display extended description of selected value.
*/

Macro.add('rbutton', {
	handler() {
		if (this.args.length < 2) {
			const errors = [];
			if (this.args.length < 1) { errors.push('variable name'); }
			if (this.args.length < 2) { errors.push('checked value'); }
			return this.error(`no ${errors.join(' or ')} specified`);
		}

		// Ensure that the variable name argument is a string.
		if (typeof this.args[0] !== 'string') {
			return this.error('variable name argument is not a string');
		}

		const varName = this.args[0].trim();

		// Try to ensure that we receive the variable's name (incl. sigil), not its value.
		if (varName[0] !== '$' && varName[0] !== '_') {
			return this.error(`variable name "${this.args[0]}" is missing its sigil ($ or _)`);
		}

		const initValue = Wikifier.getValue(this.args[0]);
		const varId = Util.slugify(varName);
		const checkValue = this.args[1];
		const el = document.createElement('input');

		let replaceID = "";
		let replaceText = "";
		if (typeof this.args[2] === 'string') {
			replaceID = this.args[2];
		}
		if (typeof this.args[3] === 'string') {
			replaceText = this.args[3];
		}

		/*
		Setup and initialize the group counter.
		*/
		if (!TempState.hasOwnProperty(this.name)) {
			TempState[this.name] = {};
		}

		if (!TempState[this.name].hasOwnProperty(varId)) {
			TempState[this.name][varId] = 0;
		}

		/*
		Setup and append the input element to the output buffer.
		*/
		jQuery(el)
			.attr({
				id: `${this.name}-${varId}-${TempState[this.name][varId]++}`,
				name: `${this.name}-${varId}`,
				type: 'radio',
				tabindex: 0 // for accessibility
			})
			.addClass(`macro-${this.name}`)
			.on('change', function() {
				if (this.checked) {
					Wikifier.setValue(varName, checkValue);

					if (replaceID.length > 0 && replaceText.length > 0) {
						let replaceEl = document.getElementById(replaceID);
						// alert (replaceEl);
						if (replaceEl !== null) {
							replaceEl.innerHTML = replaceText;
						}
					}
				}
			})
			.ready(function() {
				// alert ("DOM finished");
				if (el.checked && replaceID.length > 0 && replaceText.length > 0) {
					let replaceEl = document.getElementById(replaceID);
					// alert (replaceEl);
					if (replaceEl !== null) {
						replaceEl.innerHTML = replaceText;
					}
				}
			})
			.appendTo(this.output);

		/*
		Set the story variable to the checked value and the input element to checked, if requested.
		*/
		if (initValue === checkValue) {
			el.checked = true;
			Wikifier.setValue(varName, checkValue);
		}
	}
});


code:
/**
 * @param {{ rivalry: number; }} id
 * @returns {string}
 */
window.rivalryTerm = function(id) {
	if (id.rivalry === 1) {
		return "growing rival";
	} else if (id.rivalry === 2) {
		return "rival";
	} else {
		return "bitter rival";
	}
};

/**
 * @param {{ relationship: number; }} id
 * @returns {string}
 */
window.relationshipTerm = function(id) {
	if (id.relationship === 1) {
		return "friend";
	} else if (id.relationship === 2) {
		return "best friend";
	} else if (id.relationship === 3) {
		return "friend with benefits";
	} else if (id.relationship === 4) {
		return "lover";
	} else {
		return "slave wife";
	}
};

/**
 * @param {{ relationship: number; }} id
 * @returns {string}
 */
window.relationshipTermShort = function(id) {
	if (id.relationship === 1) {
		return "friend";
	} else if (id.relationship === 2) {
		return "BFF";
	} else if (id.relationship === 3) {
		return "FWB";
	} else if (id.relationship === 4) {
		return "lover";
	} else {
		return "wife";
	}
};


code:
window.removeActiveSlave = function removeActiveSlave() {
	"use strict";
	const V = State.variables;

	const AS_ID = V.activeSlave.ID;
	let LENGTH = V.slaves.length;
	const INDEX = V.slaveIndices[AS_ID];
	let missing = false;

	WombChangeID(V.PC, AS_ID, V.missingParentID);
	if (V.PC.pregSource === V.missingParentID) {
		missing = true;
	}

	if (V.PC.mother === AS_ID) {
		V.PC.mother = V.missingParentID;
		missing = true;
	}
	if (V.PC.father === AS_ID) {
		V.PC.father = V.missingParentID;
		missing = true;
	}
	if (V.PC.sisters > 0) {
		if (areSisters(V.PC, V.activeSlave) > 0) {
			V.PC.sisters--;
		}
	}
	if (V.PC.daughters > 0) {
		if (V.activeSlave.father === -1 || V.activeSlave.mother === -1) {
			V.PC.daughters--;
		}
	}

	if (INDEX >= 0 && INDEX < LENGTH) {
		if (V.incubator > 0) {
			V.tanks.forEach(child => {
				if (AS_ID === child.mother) {
					child.mother = V.missingParentID;
					missing = true;
				}
				if (AS_ID === child.father) {
					child.father = V.missingParentID;
					missing = true;
				}
			});
		}
		if (V.nursery > 0) {
			V.cribs.forEach(child => {
				if (AS_ID === child.mother) {
					child.mother = V.missingParentID;
					missing = true;
				}
				if (AS_ID === child.father) {
					child.father = V.missingParentID;
					missing = true;
				}
			});
		}
		V.slaves.forEach(slave => {
			WombChangeID(slave, AS_ID, V.missingParentID); /* This check is complex, should be done in JS now, all needed will be done here. */
			WombChangeGeneID(slave, AS_ID, V.missingParentID);
			if (slave.pregSource === V.missingParentID) {
				missing = true;
			}
			if (V.activeSlave.daughters > 0) {
				if (slave.mother === AS_ID) {
					slave.mother = V.missingParentID;
				}
				if (slave.father === AS_ID) {
					slave.father = V.missingParentID;
				}
				missing = true;
			}
			if (V.activeSlave.mother > 0 || V.activeSlave.father > 0) {
				if (V.activeSlave.mother === slave.ID || V.activeSlave.father === slave.ID) {
					slave.daughters--;
				}
			}
			if (V.activeSlave.sisters > 0) {
				if (areSisters(V.activeSlave, slave) > 0) {
					slave.sisters--;
				}
			}
			if (slave.ID === V.activeSlave.relationTarget) {
				slave.relation = 0;
				slave.relationTarget = 0;
			}
			if (slave.milkSource !== 0) {
				if (slave.milkSource === AS_ID) {
					slave.milkSource = 0;
					slave.inflation = 0;
					slave.inflationType = "none";
					slave.inflationMethod = 0;
				}
			}
			if (slave.cumSource !== 0) {
				if (slave.cumSource === AS_ID) {
					slave.cumSource = 0;
					slave.inflation = 0;
					slave.inflationType = "none";
					slave.inflationMethod = 0;
				}
			}
			if (slave.ID === V.activeSlave.relationshipTarget) {
				slave.relationship = 0;
				slave.relationshipTarget = 0;
			}
			if (slave.ID === V.activeSlave.rivalryTarget) {
				slave.rivalry = 0;
				slave.rivalryTarget = 0;
			}
			/* moved to saDevotion as a discovery event
				if (slave.origBodyOwnerID === AS_ID) {
				slave.origBodyOwnerID = 0;
				}
			*/
		});

		/* remove from Pit fighters list, if needed */
		V.fighterIDs.delete(AS_ID);

		/* remove from Coursing Association, if needed */
		if (V.Lurcher !== 0 && V.Lurcher.ID === AS_ID) {
			V.Lurcher = 0;
		}

		if (Array.isArray(V.personalAttention)) {
			V.personalAttention.deleteWith(s => s.ID === AS_ID);
			if (V.personalAttention.length === 0) {
				if (V.PC.career === "escort") {
					V.personalAttention = "whoring";
				} else if (V.PC.career === "servant") {
					V.personalAttention = "upkeep";
				} else {
					V.personalAttention = "business";
				}
			}
		}

		/* Remove from facility array or leadership role, if needed */
		removeJob(V.activeSlave, V.activeSlave.assignment);

		if (V.traitor !== 0) {
			missing = true; /* no exceptions, fetus system relies on this */
			if (AS_ID === V.traitor.pregSource) {
				V.traitor.pregSource = 0;
			}
			if (V.traitor.mother === AS_ID) {
				V.traitor.mother = V.missingParentID;
			}
			if (V.traitor.father === AS_ID) {
				V.traitor.father = V.missingParentID;
			}
			if (V.traitor.origBodyOwnerID === AS_ID) {
				V.traitor.origBodyOwnerID = 0;
			}
		}
		if (V.boomerangSlave !== 0) {
			missing = true;
			if (AS_ID === V.boomerangSlave.pregSource) {
				V.boomerangSlave.pregSource = 0;
			}
			if (V.boomerangSlave.mother === AS_ID) {
				V.boomerangSlave.mother = V.missingParentID;
			}
			if (V.boomerangSlave.father === AS_ID) {
				V.boomerangSlave.father = V.missingParentID;
			}
			if (V.boomerangSlave.origBodyOwnerID === AS_ID) {
				V.traitor.origBodyOwnerID = 0;
			}
		}

		V.organs.deleteWith(s => s.ID === AS_ID);
		V.completedOrgans.deleteWith(s => s.ID === AS_ID);

		for (let _o = 0; _o < V.adjustProsthetics.length; _o++) {
			if (V.adjustProsthetics[_o].ID === AS_ID) {
				V.adjustProsthetics.deleteAt(_o);
				V.adjustProstheticsCompleted--;
				_o--;
			}
		}

		const _geneIndex = V.genePool.findIndex(s => s.ID === AS_ID);
		if (_geneIndex !== -1) {
			let keep = false;
			if (V.traitor !== 0) {
				if (isImpregnatedBy(V.traitor, V.activeSlave) || V.traitor.ID === AS_ID) {
					/* did we impregnate the traitor, or are we the traitor? */
					keep = true;
				}
			}
			if (V.boomerangSlave !== 0) {
				if (isImpregnatedBy(V.boomerangSlave, V.activeSlave) || V.boomerangSlave.ID === AS_ID) {
					/* did we impregnate the boomerang, or are we the boomerang? */
					keep = true;
				}
			}
			if (isImpregnatedBy(V.PC, V.activeSlave)) {
				/* did we impregnate the PC */
				keep = true;
			}
			if (!keep) {
				/* avoid going through this loop if possible */
				keep = V.slaves.some(slave => {
					/* have we impregnated a slave that is not ourselves? */
					return (slave.ID !== AS_ID && isImpregnatedBy(slave, V.activeSlave));
				});
			}
			if (!keep) {
				V.genePool.deleteAt(_geneIndex);
			}
		}
		if (missing) {
			V.missingTable[V.missingParentID] = {
				slaveName: V.activeSlave.slaveName,
				slaveSurname: V.activeSlave.slaveSurname,
				fullName: SlaveFullName(V.activeSlave),
				dick: V.activeSlave.dick,
				vagina: V.activeSlave.vagina,
				ID: V.missingParentID
			};
			if (V.traitor.ID === V.activeSlave.ID) {
				/* To link developing fetuses to their parent */
				V.traitor.missingParentTag = V.missingParentID;
			} else if (V.boomerangSlave.ID === V.activeSlave.ID) {
				V.boomerangSlave.missingParentTag = V.missingParentID;
			}
			V.missingParentID--;
		}

		removeSlave(INDEX);
		LENGTH--;
		V.activeSlave = 0;
		V.JobIDArray = resetJobIDArray(); /* need to call this once more to update count of resting slaves*/
	}
};
/**
 * @param {App.Entity.SlaveState} removedSlave
 */
window.removeNonNGPSlave = function removeNonNGPSlave(removedSlave) {
	"use strict";

	const V = State.variables;
	const ID = removedSlave.ID;
	let LENGTH = V.slaves.length;
	const INDEX = V.slaveIndices[ID];
	let missing = false;

	// Only bother if PC is being kept
	if (V.freshPC !== 1) {
		WombChangeID(V.PC, ID, V.missingParentID);
		if (V.PC.pregSource === V.missingParentID) {
			missing = true;
		}
		if (V.PC.mother === ID) {
			V.PC.mother = V.missingParentID;
			missing = true;
		}
		if (V.PC.father === ID) {
			V.PC.father = V.missingParentID;
			missing = true;
		}
		if (V.PC.sisters > 0) {
			if (areSisters(V.PC, removedSlave) > 0) {
				V.PC.sisters--;
			}
		}
		if (V.PC.daughters > 0) {
			if (removedSlave.father === -1 || removedSlave.mother === -1) {
				V.PC.daughters--;
			}
		}
	}

	if (INDEX >= 0 && INDEX < LENGTH) {
		V.slaves.forEach(slave => {
			if (slave.assignment === "be imported") {
				WombChangeID(slave, ID, V.missingParentID); /* This check is complex, should be done in JS now, all needed will be done here. */
				WombChangeGeneID(slave, ID, V.missingParentID);
				if (slave.pregSource === V.missingParentID) {
					missing = true;
				}
				if (removedSlave.daughters > 0) {
					if (slave.mother === ID) {
						slave.mother = V.missingParentID;
					}
					if (slave.father === ID) {
						slave.father = V.missingParentID;
					}
					missing = true;
				}
				if (slave.ID === removedSlave.relationTarget) {
					slave.relation = 0;
					slave.relationTarget = 0;
				}
				if (slave.milkSource !== 0) {
					if (slave.milkSource === ID) {
						slave.milkSource = 0;
						slave.inflation = 0;
						slave.inflationType = "none";
						slave.inflationMethod = 0;
					}
				}
				if (slave.cumSource !== 0) {
					if (slave.cumSource === ID) {
						slave.cumSource = 0;
						slave.inflation = 0;
						slave.inflationType = "none";
						slave.inflationMethod = 0;
					}
				}
				if (slave.ID === removedSlave.relationshipTarget) {
					slave.relationship = 0;
					slave.relationshipTarget = 0;
				}
				if (slave.ID === removedSlave.rivalryTarget) {
					slave.rivalry = 0;
					slave.rivalryTarget = 0;
				}
			}
		});

		const _geneIndex = V.genePool.findIndex(s => s.ID === ID);
		if (_geneIndex !== -1) {
			let keep = false;
			if (isImpregnatedBy(V.PC, removedSlave)) {
				/* did we impregnate the PC */
				keep = true;
			}
			if (!keep) {
				/* avoid going through this loop if possible */
				keep = V.slaves.some(slave => {
					/* have we impregnated a slave that is not ourselves? */
					return (slave.ID !== ID && isImpregnatedBy(slave, removedSlave));
				});
			}
			if (!keep) {
				V.genePool.deleteAt(_geneIndex);
			}
		}
		if (missing) {
			V.missingTable[V.missingParentID] = {
				slaveName: removedSlave.slaveName,
				slaveSurname: removedSlave.slaveSurname,
				fullName: SlaveFullName(removedSlave),
				dick: removedSlave.dick,
				vagina: removedSlave.vagina,
				ID: V.missingParentID
			};
			V.missingParentID--;
		}

		removeSlave(INDEX);
	}
};


code:
/**
 * @param {App.Entity.SlaveState} slave
 * @param {Object[]} rules
 * @returns {boolean}
 */
window.hasSurgeryRule = function(slave, rules) {
	return rules.some(
		rule => ruleApplied(slave, rule) && rule.set.autoSurgery > 0);
};

/**
 * @param {App.Entity.SlaveState} slave
 * @param {Object[]} rules
 * @param {string} what
 * @returns {boolean}
 */
window.hasRuleFor = function(slave, rules, what) {
	return rules.some(
		rule => ruleApplied(slave, rule) && rule[what] !== "no default setting");
};

/**
 * @param {App.Entity.SlaveState} slave
 * @param {Object[]} rules
 * @returns {boolean}
 */
window.hasHColorRule = function(slave, rules) {
	return hasRuleFor(slave, rules, "hColor");
};

/**
 * @param {App.Entity.SlaveState} slave
 * @param {Object[]} rules
 * @returns {boolean}
 * */
window.hasHStyleRule = function(slave, rules) {
	return hasRuleFor(slave, rules, "hStyle");
};

/**
 * @param {App.Entity.SlaveState} slave
 * @param {Object[]} rules
 * @returns {boolean}
 * */
window.hasEyeColorRule = function(slave, rules) {
	return hasRuleFor(slave, rules, "eyeColor");
};

/**
 * return if a rule is applied on a slave
 * @param {App.Entity.SlaveState} slave
 * @param {Object[]} rules
 * @returns {boolean}
 */
window.lastPregRule = function(slave, rules) {
	return rules.some(rule =>
		ruleApplied(slave, rule) && rule.set.preg === -1);
};

/**
 * @param {Object[]} rules
 * @returns {Object}
 */
window.mergeRules = function mergeRules(rules) {
	const combinedRule = {};
	rules.forEach(rule => {
		// A rule overrides any preceding ones if,
		// * there are no preceding ones,
		// * or it sets autoBrand,
		// * or it does not set autoBrand and is not "no default setting"
		Object.keys(rule).forEach(key => {
			const applies = (combinedRule[key] === undefined ||
				(key === "autoBrand" && rule[key]) ||
				(key !== "autoBrand" && rule[key] !== "no default setting"));
			if (!applies) { return; }
			combinedRule[key] = rule[key];
		});
	});
	return combinedRule;
};

/**
 * return if a rule is applied on a slave
 * @param {App.Entity.SlaveState} slave
 * @param {Object} rule
 * @returns {boolean}
 */
window.ruleApplied = function(slave, rule) {
	return slave.currentRules.includes(rule.ID);
};

/**
 * remove slave from the facility described by the rule
 * @param {App.Entity.SlaveState} slave
 * @param {Object} rule
 * @returns {string}
 */
window.RAFacilityRemove = function RAFacilityRemove(slave, rule) {
	const V = State.variables;
	let r = "";
	if (!rule.facilityRemove) { return r; }
	switch (rule.setAssignment) {
		case "be confined in the arcade":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${V.arcadeName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "work in the brothel":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${V.brothelName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "serve in the club":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${clubName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "work in the dairy":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${V.dairyName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "work as farmhand":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${V.farmyardName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "rest in the spa":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${V.spaName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "work as a nanny":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${V.nurseryName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "get treatment in the clinic":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>{slave.slaveName} has been removed from ${V.clinicName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "serve in the master suite":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>{slave.slaveName} has been removed from ${V.masterSuiteName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "live with your Head Girl":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${HGSuiteName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "work as a servant":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${V.servantsQuartersName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "learn in the schoolroom":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${V.schoolroomName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;

		case "be confined in the cellblock":
			if (slave.assignment === rule.setAssignment) {
				r += `<br>${slave.slaveName} has been removed from ${V.cellblockName} and has been assigned to ${rule.removalAssignment}.`;
				assignJob(slave, rule.removalAssignment);
			}
			break;
	}
};

/**
 * return whether the rule applies to the slave
 * @param {{function:boolean|string, data, specialSlaves, selectedSlaves, excludedSlaves, assignment}} cond
 * @param {App.Entity.SlaveState} slave
 * @returns {boolean} flag */
window.ruleAppliesP = function ruleAppliesP(cond, slave) {
	let flag;

	// attribute / function check
	switch (cond.function) {
		case true: // always applies
			flag = true;
			break;
		case false: // never applies
			flag = false;
			break;
		case "between": // between two values of a slave's attribute
			flag = between(
				slave[cond.data.attribute],
				cond.data.value[0],
				cond.data.value[1]);
			break;
		case "belongs": // the attribute belongs in the list of values
			flag = cond.data.value.includes(slave[cond.data.attribute]);
			break;
		case "custom": // user provided JS function
			flag = eval(cond.data)(slave);
			break;
	}
	// assignment / facility / special slaves / specific slaves check
	let assignment = slave.assignment;
	if (assignment === "be your Concubine") { assignment = "serve in the master suite"; }

	if (cond.specialSlaves !== -1) { // not "Include", which means "doesn't matter"
		flag = flag && (cond.specialSlaves == isLeaderP(slave)); // eslint-disable-line eqeqeq
	}

	flag = flag &&
		(cond.assignment.length === 0 || cond.assignment.includes(assignment)) &&
		(cond.selectedSlaves.length === 0 || cond.selectedSlaves.includes(slave.ID)) &&
		!(cond.excludedSlaves.includes(slave.ID));
	return flag;
};

/**
 * @returns {Object}
 */
window.emptyDefaultRule = function emptyDefaultRule() {
	const id = generateNewID();
	const rule = {
		ID: id,
		name: `Rule ${id}`,
		condition: {
			function: false,
			data: {},
			specialSlaves: -1,
			assignment: [],
			selectedSlaves: [],
			excludedSlaves: [],
		},
		/* eslint-disable */
		// TODO: rename properties in snake_case to camelCase?
		set: {
			releaseRules: "no default setting",
			toyHole: "no default setting",
			clitSetting: "no default setting",
			clitSettingXY: "no default setting",
			clitSettingXX: "no default setting",
			clitSettingEnergy: "no default setting",
			speechRules: "no default setting",
			clothes: "no default setting",
			collar: "no default setting",
			shoes: "no default setting",
			legAccessory: "no default setting",
			chastityVagina: "no default setting",
			chastityAnus: "no default setting",
			chastityPenis: "no default setting",
			virginAccessory: "no default setting",
			aVirginAccessory: "no default setting",
			vaginalAccessory: "no default setting",
			aVirginDickAccessory: "no default setting",
			dickAccessory: "no default setting",
			bellyAccessory: "no default setting",
			aVirginButtplug: "no default setting",
			buttplug: "no default setting",
			buttplugAttachment: "no default setting",
			eyeColor: "no default setting",
			makeup: "no default setting",
			nails: "no default setting",
			hColor: "no default setting",
			hLength: "no default setting",
			haircuts: "no default setting",
			hStyle: "no default setting",
			eyebrowHColor: "no default setting",
			eyebrowHStyle: "no default setting",
			eyebrowFullness: "no default setting",
			markings: "no default setting",
			pubicHColor: "no default setting",
			pubicHStyle: "no default setting",
			nipplesPiercing: "no default setting",
			areolaePiercing: "no default setting",
			clitPiercing: "no default setting",
			vaginaLube: "no default setting",
			vaginaPiercing: "no default setting",
			dickPiercing: "no default setting",
			anusPiercing: "no default setting",
			lipsPiercing: "no default setting",
			tonguePiercing: "no default setting",
			earPiercing: "no default setting",
			nosePiercing: "no default setting",
			eyebrowPiercing: "no default setting",
			navelPiercing: "no default setting",
			corsetPiercing: "no default setting",
			boobsTat: "no default setting",
			buttTat: "no default setting",
			vaginaTat: "no default setting",
			dickTat: "no default setting",
			lipsTat: "no default setting",
			anusTat: "no default setting",
			shouldersTat: "no default setting",
			armsTat: "no default setting",
			legsTat: "no default setting",
			backTat: "no default setting",
			stampTat: "no default setting",
			curatives: "no default setting",
			livingRules: "no default setting",
			relationshipRules: "no default setting",
			standardPunishment: "no default setting",
			standardReward: "no default setting",
			diet: "no default setting",
			dietCum: "no default setting",
			dietMilk: "no default setting",
			onDiet: "no default setting",
			muscles: "no default setting",
			XY: "no default setting",
			XX: "no default setting",
			gelding: "no default setting",
			preg: "no default setting",
			abortion: "no default setting",
			growth_boobs: "no default setting",
			growth_butt: "no default setting",
			growth_lips: "no default setting",
			growth_dick: "no default setting",
			growth_balls: "no default setting",
			hyper_drugs: 0,
			aphrodisiacs: "no default setting",
			autoSurgery: 0,
			autoBrand: 0,
			pornFeed: "no default setting",
			pornFameSpending: "no default setting",
			dietGrowthSupport: 0,
			eyewear: "no default setting",
			earwear: "no default setting",
			setAssignment: "no default setting",
			facilityRemove: false,
			removalAssignment: "rest",
			surgery_eyes: "no default setting",
			surgery_hears: "no default setting",
			surgery_smells: "no default setting",
			surgery_tastes: "no default setting",
			surgery_lactation: "no default setting",
			surgery_prostate: "no default setting",
			surgery_cosmetic: "no default setting",
			surgery_accent: "no default setting",
			surgery_shoulders: "no default setting",
			surgery_shouldersImplant: "no default setting",
			surgery_boobs: "no default setting",
			surgery_hips: "no default setting",
			surgery_hipsImplant: "no default setting",
			surgery_butt: "no default setting",
			surgery_faceShape: "no default setting",
			surgery_lips: "no default setting",
			surgery_holes: "no default setting",
			surgery_tummy: "no default setting",
			surgery_hair: "no default setting",
			surgery_bodyhair: "no default setting",
			surgery_vasectomy: "no default setting",
			surgery_bellyImplant: "no default setting",
			underArmHColor: "no default setting",
			underArmHStyle: "no default setting",
			drug: "no default setting",
			eyes: "no default setting",
			pregSpeed: "no default setting",
			bellyImplantVol: -1,
			teeth: "no default setting",
			label: "no default setting",
			removeLabel: "no default setting",
			skinColor: "no default setting",
			inflationType: "no default setting",
		}
		/* eslint-enable */
	};
	return rule;
};

/**
 * Saves the slave, silently fires the RA, saves the slave's after-RA state, and then reverts the slave.
 * Call and then check potential change against $slaveAfterRA to see if the RA would revert it.
 * @param {App.Entity.SlaveState} slave
 *
 */
window.RulesDeconfliction = function RulesDeconfliction(slave) {
	const before = clone(slave);
	DefaultRules(slave);
	State.variables.slaveAfterRA = clone(slave);
	slave = before;
};

/**
 * Creates a table to summarize RA
 * @returns {string}
 */
window.RASummaryCell = function RASummaryCell() {
	const V = State.variables;
	let r = "";
	let i;
	let j;
	let rules = Object.keys(V.defaultRules); /* needed to determine number of rule sets (chart width)*/
	let keys = Object.keys(V.defaultRules[0].set); /* needed to determine length of rules (chart height)*/
	let values;
	let display = 0;

	/* start row title */
	r += `<tr><td></td>`;

	/* make rest of row title */
	for (i = 0; i < rules.length; i++) {
		r += `<td>${V.defaultRules[i].name}</td>`;
	}
	r += `</tr>`;

	/* A row for every condition the RA can set. */
	/* start loop for row*/
	for (i = 0; i < keys.length; i++) { /* i is for rows/"what they are fed" */
		/* Check if this row will have anything interesting*/
		for (j = 0; j < rules.length; j++) { /* j is the rule set it comes from/"obedient slaves" */
			values = V.defaultRules[j].set[keys[i]];
			if (values && values !== "no default setting") {
				display++;
			}
		}

		/* Show the interesting row */
		if (display > 0) {
			/* make row title */
			r += `<tr><td>${keys[i]}</td>`;
			/* make rest of cells */
			for (j = 0; j < rules.length; j++) {
				values = V.defaultRules[j].set[keys[i]];
				if (values === "no default setting" || !values) {
					r += `<td></td>`;
				} else {
					r += `<td>${V.defaultRules[j].set[keys[i]]}</td>`;
				}
			}
			display = 0;
			r += `</tr>`;
		}
	}
	return r;
};