code:
:: itemAvailability [script]

/* intended to condense the clothing/toy/etc availability checks into something less asinine */
window.isItemAccessible = function(string) {

	const V = State.variables;

	if (State.variables.cheatMode === 1){
		return true;
	} else {
		switch(string) {
		case 'attractive lingerie for a pregnant woman':
			if ((V.arcologies[0].FSRepopulationFocus > 0) || (V.clothesBoughtMaternityLingerie === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'a bunny outfit':
			if ((V.arcologies[0].FSGenderFundamentalist > 0) || (V.clothesBoughtBunny === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'body oil':
			if ((V.arcologies[0].FSPhysicalIdealist > 0) || (V.clothesBoughtOil === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'chains':
			if ((V.arcologies[0].FSDegradationist > 0) || (V.clothesBoughtChains === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'a chattel habit':
			if ((V.arcologies[0].FSChattelReligionist > 0) || (V.clothesBoughtHabit === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'conservative clothing':
			if ((V.arcologies[0].FSPaternalist > 0) || (V.clothesBoughtConservative === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'harem gauze':
			if ((V.arcologies[0].FSArabianRevivalist > 0) || (V.clothesBoughtHarem === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'a huipil':
			if ((V.arcologies[0].FSAztecRevivalist > 0) || (V.clothesBoughtHuipil === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'a kimono':
			if ((V.arcologies[0].FSEdoRevivalist > 0) || (V.clothesBoughtKimono === 1) || (V.continent === 'Japan')) {
				return true;
			} else {
				return false;
			}
			break;
		case 'a maternity dress':
			if ((V.arcologies[0].FSRepopulationFocus > 0) || (V.clothesBoughtMaternityDress === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'a slutty qipao':
			if ((V.arcologies[0].FSChineseRevivalist > 0) || (V.clothesBoughtQipao === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'a long qipao':
			if ((V.arcologies[0].FSChineseRevivalist > 0) || (V.clothesBoughtCultural === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'stretch pants and a crop-top':
			if ((V.arcologies[0].FSHedonisticDecadence > 0) || (V.clothesBoughtLazyClothes === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'a toga':
			if ((V.arcologies[0].FSRomanRevivalist > 0) || (V.clothesBoughtToga === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'Western clothing':
			if ((V.arcologies[0].FSPastoralist > 0) || (V.clothesBoughtWestern === 1)) {
				return true;
			} else {
				return false;
			}
			break;

		case 'battlearmor':
		case 'a military uniform':
		case 'a red army uniform':
		case 'battledress':
			if (V.clothesBoughtMilitary === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'a biyelgee costume':
		case 'a dirndl':
		case 'lederhosen':
		case 'a mounty outfit':
		case 'a hanbok':
			if (V.clothesBoughtCultural === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'a burqa':
		case 'a burkini':
		case 'a blouse and hijab':
		case 'a niqab and abaya':
			if (V.clothesBoughtMiddleEastern === 1 || V.continent === 'the Middle East') {
				return true;
			} else {
				return false;
			}
			break;

		case 'a klan robe':
		case 'a slutty klan robe':
		case 'a schutzstaffel uniform':
		case 'a slutty schutzstaffel uniform':
			if (V.clothesBoughtPol === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'a nice nurse outfit':
		case 'a police uniform':
		case 'nice business attire':
			if (V.clothesBoughtCareer === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'a nice maid outfit':
			if (V.clothesBoughtCareer === 1 || V.PC.career === 'servant') {
				return true;
			} else {
				return false;
			}
			break;

		case 'a ball gown':
		case 'a gothic lolita dress':
		//case 'a halter top dress':
		//case 'a mini dress':
		//case 'a slave gown':
			if (V.clothesBoughtDresses === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'a cybersuit':
		case 'a latex catsuit':
			if (V.clothesBoughtBodysuits === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'a button-up shirt and panties':
		case 'a button-up shirt':
		case 'cutoffs':
		case 'jeans':
		case 'leather pants and a tube top':
		case 'leather pants':
		case 'an oversized t-shirt':
		case 'a sweater and cutoffs':
		case 'a sweater and panties':
		case 'a sweater':
		case 'a t-shirt and jeans':
		case 'a t-shirt and panties':
		case 'a t-shirt':
		case 'a tank-top and panties':
		case 'a tank-top':
		case 'a tube top':
			if (V.clothesBoughtCasual === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'boyshorts':
		case 'a bra':
		case 'kitty lingerie':
		case 'panties and pasties':
		case 'a skimpy loincloth':
		case 'a thong':
			if (V.clothesBoughtUnderwear === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'leather pants and pasties':
		case 'a t-shirt and thong':
		case 'a tube top and thong':
		case 'an oversized t-shirt and boyshorts':
			if (V.clothesBoughtUnderwear === 1 && V.clothesBoughtCasual === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'sport shorts and a sports bra':
		case 'sport shorts':
		case 'a sports bra':
			if (V.clothesBoughtSports === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'sport shorts and a t-shirt':
			if (V.clothesBoughtSports === 1 && V.clothesBoughtCasual === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'a nice pony outfit':
		case 'a slutty pony outfit':
			if (V.clothesBoughtPony === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'a monokini':
		case 'a one-piece swimsuit':
			if (V.clothesBoughtSwimwear === 1) {
				return true;
			} else {
				return false;
			}
			break;

		case 'shimapan panties':
		case 'a striped bra':
		case 'striped panties':
		case 'striped underwear':
			if (V.clothesBoughtPantsu === 1 || V.continent === 'Japan') {
				return true;
			} else {
				return false;
			}
			break;

		case 'bowtie':
			if ((V.arcologies[0].FSGenderFundamentalist > 0) || (V.clothesBoughtBunny === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'ancient Egyptian':
			if ((V.arcologies[0].FSEgyptianRevivalist > 0) || (V.clothesBoughtEgypt === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'massive dildo gag':
			if (V.toysBoughtGags === 1) {
				return true;
			} else {
				return false;
			}
			break;
		case 'a small empathy belly': case 'a medium empathy belly': case 'a large empathy belly': case 'a huge empathy belly':
			if ((V.arcologies[0].FSRepopulationFocus > 0) || (V.clothesBoughtBelly === 1)) {
				return true;
			} else {
				return false;
			}
			break;
		case 'long dildo': case 'long, large dildo': case 'long, huge dildo':
			if (V.toysBoughtDildos === 1) {
				return true;
			} else {
				return false;
			}
			break;
		case 'long plug': case 'long, large plug': case 'long, huge plug':
			if (V.toysBoughtButtPlugs === 1) {
				return true;
			} else {
				return false;
			}
			break;
		case 'tail': case 'cat tail': case 'fox tail':
			if (V.toysBoughtButtPlugTails === 1) {
				return true;
			} else {
				return false;
			}
			break;
		default:
			return true;
			break;
		}
	}
};


code:
:: pregJS [script]

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

	if(gestastionWeek <= 32) {
		var 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) {
		var 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 {
		var targetLen = ((-0.00003266 * Math.pow(gestastionWeek,2)) + (0.076 * gestastionWeek) + 43.843);
	}

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

window.bellyAdjective = function(slave) {
	slave = slave || State.variables.activeSlave;
	if(slave.belly >= 1500) {
		if(slave.belly >= 1000000) {
			if(slave.preg > 10) {
				return 'unfathomably distended, brimming with life';
			} else {
				return 'unfathomable';
			}
		} else if(slave.belly >= 750000) {
			if(slave.preg > 10) {
				return 'monolithic bulging';
			} else {
				return 'monolithic';
			}
		} else if(slave.belly >= 600000) {
			if(slave.preg > 10) {
				return 'titanic bulging';
			} else {
				return 'titanic';
			}
		} else if(slave.belly >= 450000) {
			if(slave.preg > 10) {
				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';
		}
	} else {
		return '';
	}
}

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

	var ovum = 1;
	var fertilityStack = 0; // adds an increasing bonus roll for stacked fertility drugs

	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.pregType == 0) {
			ovum += jsEither([0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); //base chance for twins
			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);
				}
			} else {
				ovum += jsRandom(0, fertilityStack);
				if(ovum > 12) {
					ovum = jsRandom(6, 12);
				}
			}
		}
	}
	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 r = "";
	if (V.seePreg !== 0) {
		if (jsRandom(0,99) < (chance + (V.reproductionFormula*((target.pregSource <= 0) ? ((target.ID == -1) ? 0 : 10) : 20)))) {
			if (target.mpreg === hole) {

				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 += "@@.lime;You have gotten pregnant.@@"; */
					} else if (target.fuckdoll === 0) {
						r += "@@.lime;She has become pregnant.@@";
					} else {
						r += "@@.lime;It has become pregnant.@@";
					}
				} else {
					target.pregKnown = 1;
				}

			} else if (hole === 2) {

				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 += "@@.lime;You have gotten pregnant.@@"; */
					} else if (target.fuckdoll === 0) {
						r += "@@.lime;She has become pregnant.@@";
					} else {
						r += "@@.lime;It has become pregnant.@@";
					}
				} else {
					target.pregKnown = 1;
				}
			}
		}
	}
	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(function(s) { return s.ID == fatherID; });
		}
	}
	if (father === undefined) {
		if (V.nursery > 0) {
			father = V.cribs.find(function(s) { return 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 */
window.getBaseBoobs = function(slave) {
	return slave.boobs-slave.boobsImplant-slave.boobsWombVolume;
}

repo_name: nook/fc


code:
:: Quick List [script]

window.sortDomObjects = function (objects, attrName, reverse = 0) {
	reverse = (reverse) ? -1 : 1;
	function sortingByAttr (a, b) {
		var aVal = a.getAttribute(attrName);
		var bVal = b.getAttribute(attrName);
		var 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 () {
	var $sortedButtons = $('#qlWrapper button').remove();
	$sortedButtons = sortDomObjects($sortedButtons, 'data-devotion');
	$($sortedButtons).appendTo($('#qlWrapper'));
	quickListBuildLinks();
};

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

window.quickListBuildLinks = function () {
	$("[data-scroll-to]").click(function() {
		var $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.
				var $offset = $this.attr('data-scroll-offset') * 1 || 0;
				var $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 () {
	var $sortedIncubatorPossibles = $('#qlIncubator div.possible').detach();
	$sortedIncubatorPossibles = sortDomObjects($sortedIncubatorPossibles, 'data-name');
	$($sortedIncubatorPossibles).appendTo($('#qlIncubator'));
};

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

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

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

window.sortIncubatorPossiblesByPreviousSort = function () {
	var sort = State.variables.sortIncubatorList;
	console.log(State.variables);
	console.log('sort', sort);
	if ('unsorted' !== sort) {
		console.log("sort isn't unsorted", sort);
		if ('Name' === sort) {
			console.log("sort is name", sort);
			sortIncubatorPossiblesByName();
		} else if ('Reserved Incubator Spots' === sort) {
			console.log("sort is spots", sort);
			sortIncubatorPossiblesByReservedSpots();
		} else if ('Pregnancy Week' === sort) {
			console.log("sort is week", sort);
			sortIncubatorPossiblesByPregnancyWeek();
		} else if ('Number of Children' === sort) {
			console.log("sort is count", sort);
			sortIncubatorPossiblesByPregnancyCount();
		}
	}
};

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

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

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

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

window.sortNurseryPossiblesByPreviousSort = function () {
	var sort = State.variables.sortNurseryList;
	console.log(State.variables);
	console.log('sort', sort);
	if ('unsorted' !== sort) {
		console.log("sort isn't unsorted", sort);
		if ('Name' === sort) {
			console.log("sort is name", sort);
			sortNurseryPossiblesByName();
		} else if ('Reserved Nursery Spots' === sort) {
			console.log("sort is spots", sort);
			sortNurseryPossiblesByReservedSpots();
		} else if ('Pregnancy Week' === sort) {
			console.log("sort is week", sort);
			sortNurseryPossiblesByPregnancyWeek();
		} else if ('Number of Children' === sort) {
			console.log("sort is count", sort);
			sortNurseryPossiblesByPregnancyCount();
		}
	}
};


code:
:: rbuttonJS [script]
/* This is modifed 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 setted 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');

		var replaceID = "";
		var 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 accessiblity
		})
		.addClass(`macro-${this.name}`)
		.on('change', function () {
			if (this.checked) {
			Wikifier.setValue(varName, checkValue);

			if (replaceID.length > 0 && replaceText.length > 0){

				var 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){

				var 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:
:: relationshipChecks [script]
window.rivalryTerm = function(id) {
	if (id.rivalry === 1) {
		return `growing rival`;
	} else if (id.rivalry === 2) {
		return `rival`;
	} else {
		return `bitter rival`;
	}
}
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`;
	}
}
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:
:: Remove activeSlave JS [script]

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)) {
			const _rasi = V.personalAttention.findIndex(function(s) { return s.ID === AS_ID; });
			if (_rasi !== -1) {
				V.personalAttention.deleteAt(_rasi);
				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;
			}
		}

		let _o;
		for (_o = 0; _o < V.organs.length; _o++) {
			if (V.organs[_o].ID === AS_ID) {
				V.organs.deleteAt(_o);
				_o--;
			}
		}
		for (_o = 0; _o < V.completedOrgans.length; _o++) {
			if (V.completedOrgans[_o].ID === AS_ID) {
				V.completedOrgans.deleteAt(_o);
				_o--;
			}
		}
		for (_o = 0; _o < V.limbs.length; _o++) {
			if (V.limbs[_o].ID === AS_ID) {
				V.limbs.deleteAt(_o);
				V.limbsCompleted--;
				_o--;
			}
		}

		const _geneIndex = V.genePool.findIndex(function(s) { return 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 ourself? */
					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;
	}
};


code:
:: rulesAssistant [script]

window.hasSurgeryRule = function(slave, rules) {
	return rules.some(
		rule => ruleApplied(slave, rule) && rule.set.autoSurgery > 0);
};

window.hasRuleFor = function(slave, rules, what) {
	return rules.some(
		rule => ruleApplied(slave, rule) && rule[what] !== "no default setting");
};

window.hasHColorRule = function(slave, rules) {
	return hasRuleFor(slave, rules, "hColor");
};

window.hasHStyleRule = function(slave, rules) {
	return hasRuleFor(slave, rules, "hStyle");
};

window.hasEyeColorRule = function(slave, rules) {
	return hasRuleFor(slave, rules, "eyeColor");
};

window.lastPregRule = function(slave, rules) {
	return rules.some(rule =>
		ruleApplied(slave, rule) && rule.set.preg === -1);
};

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
window.ruleApplied = function(slave, rule) {
	return slave.currentRules.includes(rule.ID);
};

// remove slave from the facility described by the rule
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
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";
	flag = flag &&
		!(cond.excludeSpecialSlaves && isLeaderP(slave)) &&
		(cond.assignment.length === 0 || cond.assignment.includes(assignment)) &&
		(cond.selectedSlaves.length === 0 || cond.selectedSlaves.includes(slave.ID)) &&
		!(cond.excludedSlaves.includes(slave.ID));
	return flag;
};

window.emptyDefaultRule = function emptyDefaultRule() {
	const id = generateNewID();
	const rule = {
		ID: id,
		name: `Rule ${id}`,
		condition: {
			function: false,
			data: {},
			excludeSpecialSlaves: false,
			assignment: [],
			selectedSlaves: [],
			excludedSlaves: [],
		},
		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",
			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",
			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",
			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",
			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_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_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",
		}
	};
	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.
window.RulesDeconfliction = function RulesDeconfliction(slave) {
	const before = clone(slave);
	DefaultRules(slave);
	State.variables.slaveAfterRA = clone(slave);
	slave = before;
}