code:
:: FamilyTreeJS [script]
'use strict';

var lastActiveSlave, lastSlaves, lastPC;

/*
	To use, add something like:

		<<link "Pull up the file on her family tree.">>
		<<replace #familyTreeLink>>
			<<run renderFamilyTree($slaves, $activeSlave.ID)>>
		<</replace>>
	<</link>>

*/

window.renderFamilyTree = function(slaves, filterID) {

	var ftreeWidth,ftreeHeight;
	var chartWidth, chartHeight;
	var margin;
	d3.select('#ftree-canvas').remove();
	var svg = d3.select('#familyTree')
		.append('svg')
		.attr('id','ftree-canvas');
	var chartLayer = svg.append('g').classed('chartLayer', true);

	var range = 100;
	var data = buildFamilyTree(slaves, filterID);

	initFtreeSVG(data);
	runFtreeSim(data);

	function initFtreeSVG(data) {
		ftreeWidth = data.nodes.length * 45;
		ftreeHeight = data.nodes.length * 35;
		if(ftreeWidth < 600) {
			ftreeWidth = 600;
		} else if(ftreeWidth > 1920) {
			ftreeWidth = 1920;
		}
		if(ftreeHeight < 480) {
			ftreeHeight = 480;
		} else if(ftreeHeight > 1200) {
			ftreeHeight = 1200;
		}

		margin = {top:0, left:0, bottom:0, right:0 }

		chartWidth = ftreeWidth - (margin.left+margin.right)
		chartHeight = ftreeHeight - (margin.top+margin.bottom)

		svg.attr('width', ftreeWidth).attr('height', ftreeHeight)

		var defs = svg.append('defs');

		svg.append('defs').append('marker')
			.attr('id','arrowhead')
			.attr('viewBox','-0 -5 10 10')
			.attr('refX',13)
			.attr('refY',0)
			.attr('orient','auto')
			.attr('markerWidth',13)
			.attr('markerHeight',13)
			.attr('xoverflow','visible')
			.append('svg:path')
			.attr('d', 'M 0,-1 L 5,0 L 0,1')
			.attr('fill', '#a1a1a1')
			.style('stroke','none');

		chartLayer
			.attr('width', chartWidth)
			.attr('height', chartHeight)
			.attr('transform', 'translate('+[margin.left, margin.top]+')')
	}

	function runFtreeSim(data) {
		var simulation = d3.forceSimulation()
			.force('link', d3.forceLink().id(function(d) { return d.index }))
			.force('collide',d3.forceCollide( function(d){ return 60; }).iterations(4) )
			.force('charge', d3.forceManyBody().strength(-200).distanceMin(100).distanceMax(1000))
			.force('center', d3.forceCenter(chartWidth / 2, chartHeight / 2))
			.force('y', d3.forceY(100))
			.force('x', d3.forceX(200))

		var link = svg.append('g')
			.attr('class', 'link')
			.selectAll('link')
			.data(data.links)
			.enter()
			.append('line')
			.attr('marker-end','url(#arrowhead)')
			.attr('stroke', function(d) {
				if(d.type == 'homologous') {
					return '#862d59';
				} else if(d.type == 'paternal') {
					return '#24478f';
				} else {
					return '#aa909b';
				}
			})
			.attr('stroke-width', 2)
			.attr('fill', 'none');

		var node = svg.selectAll('.node')
			.data(data.nodes)
			.enter().append('g')
			.attr('class', 'node')
			.call(d3.drag()
			.on('start', dragstarted)
			.on('drag', dragged)
			.on('end', dragended));

		node.append('circle')
			.attr('r', function(d){ return d.r })
			.attr('stroke', function(d) {
				if(d.ID == filterID) {
					return '#ffff20';
				} else {
					return '#5a5a5a';
				}
			})
			.attr('class', 'node-circle')
			.attr('r', 20);

		node.append('text')
			.text(function(d) {
				var ssym;
				if(d.ID == -1) {
					if(d.dick == 1 && d.vagina == 1) {
						ssym = '☿'
					} else if (d.dick == 1) {
						ssym = '♂';
					} else if (d.vagina == 1) {
						ssym = '♀';
					}
				} else if (d.dick > 0 && d.vagina > -1) {
					ssym = '☿'
				} else if (d.dick > 0) {
					ssym = '♂';
				} else if (d.vagina > -1) {
					ssym = '♀';
				} else {
					ssym = '?';
				}
				return d.name + '('+ssym+')';
			})
			.attr('dy', 4)
			.attr('dx', function(d) { return -(8*d.name.length)/2; })
			.attr('class', 'node-text')
			.style('fill', function(d) {
				if(d.is_mother && d.is_father) {
					return '#b84dff';
				} else if(d.is_father) {
					return '#00ffff';
				} else if(d.is_mother) {
					return '#ff3399';
				} else if(d.unborn) {
					return '#a3a3c2';
				} else {
					return '#66cc66';
				}
			});

		var circles = svg.selectAll('.node-circle');
		var texts = svg.selectAll('.node-text');

		var ticked = function() {
			link
				.attr('x1', function(d) { return d.source.x; })
				.attr('y1', function(d) { return d.source.y; })
				.attr('x2', function(d) { return d.target.x; })
				.attr('y2', function(d) { return d.target.y; });

			node
				.attr("transform", function (d) {return "translate(" + d.x + ", " + d.y + ")";});
		}

		simulation.nodes(data.nodes)
			.on('tick', ticked);

		simulation.force('link')
			.links(data.links);

		function dragstarted(d) {
			if (!d3.event.active) simulation.alphaTarget(0.3).restart();
			d.fx = d.x;
			d.fy = d.y;
		}

		function dragged(d) {
			d.fx = d3.event.x;
			d.fy = d3.event.y;
		}

		function dragended(d) {
			if (!d3.event.active) simulation.alphaTarget(0);
			d.fx = null;
			d.fy = null;
		}

	}
};

window.buildFamilyTree = function(slaves = State.variables.slaves, filterID) {
	var family_graph = {
		nodes: [],
		links: []
	};
	var node_lookup = {};
	var preset_lookup = {
		'-2': 'Social elite',
		'-3': 'Client',
		'-4': 'Former master',
		'-5': 'An arcology owner',
		'-6': 'A citizen'
	};
	var outdads = {};
	var outmoms = {};
	var kids = {};

	var fake_pc = {
		slaveName: State.variables.PC.name + '(You)',
		mother: State.variables.PC.mother,
		father: State.variables.PC.father,
		dick: State.variables.PC.dick,
		vagina: State.variables.PC.vagina,
		ID: State.variables.PC.ID
	};
	var charList = [fake_pc];
	charList.push.apply(charList, slaves);
	charList.push.apply(charList, State.variables.tanks);

	var unborn = {};
	for(var i = 0; i < State.variables.tanks.length; i++) {
		unborn[State.variables.tanks[i].ID] = true;
	}
	for (var i = 0; i < State.variables.cribs.length; i++) {
		unborn[State.variables.cribs[i].ID] = true;
	}

	for(var i = 0; i < charList.length; i++) {
		var mom = charList[i].mother;
		var dad = charList[i].father;

		if(mom) {
			if(!kids[mom]) {
				kids[mom] = {};
			}
			kids[mom].mother = true;
		}
		if(dad) {
			if(!kids[dad]) {
				kids[dad] = {};
			}
			kids[dad].father = true;
		}
	}

	for(var i = 0; i < charList.length; i++) {
		var character = charList[i];
		if(character.mother == 0 && character.father == 0 && !kids[character.ID]) {
			continue;
		}
		var mom = character.mother;
		if(mom < -6) {
			if (mom in State.variables.missingTable && State.variables.showMissingSlaves) {
				node_lookup[mom] = family_graph.nodes.length;
				var missing = State.variables.missingTable[mom];
				charList.push({ID: mom, mother: 0, father: 0, is_mother: true, dick: missing.dick, vagina: missing.vagina, slaveName: missing.slaveName});
			} else {
				if(typeof outmoms[mom] == 'undefined') {
					outmoms[mom] = [];
				}
				outmoms[mom].push(character.slaveName);
			}
		} else if(mom < 0 && typeof node_lookup[mom] == 'undefined' && typeof preset_lookup[mom] != 'undefined') {
			node_lookup[mom] = family_graph.nodes.length;
			charList.push({ID: mom, mother: 0, father: 0, is_father: true, dick: 0, vagina: 1, slaveName: preset_lookup[mom]});
		}

		var dad = character.father;
		if(dad < -6) {
			if (dad in State.variables.missingTable && State.variables.showMissingSlaves) {
				node_lookup[dad] = family_graph.nodes.length;
				var missing = State.variables.missingTable[dad];
				charList.push({ID: dad, mother: 0, father: 0, is_father: true, dick: missing.dick, vagina: missing.vagina, slaveName: missing.slaveName});
			} else {
				if(typeof outdads[dad] == 'undefined') {
					outdads[dad] = [];
				}
				outdads[dad].push(character.slaveName);
			}
		} else if(dad < 0 && typeof node_lookup[dad] == 'undefined' && typeof preset_lookup[dad] != 'undefined') {
			node_lookup[dad] = family_graph.nodes.length;
			charList.push({ID: dad, mother: 0, father: 0, is_father: true, dick: 1, vagina: -1, slaveName: preset_lookup[dad]});
		}
	}
	var mkeys = Object.keys(outmoms);
	for(var i = 0; i < mkeys.length; i++) {
		var name;
		var key = mkeys[i];
		var names = outmoms[key];
		if(names.length == 1) {
			name = names[0];
		} else if(names.length == 2) {
			name = names.join(' and ');
		} else {
			names[-1] = 'and '+names[-1];
			name = names.join(', ');
		}
		node_lookup[key] = family_graph.nodes.length;
		//Outside extant slaves set
		charList.push({ID: key, mother: 0, father: 0, is_mother: true, dick: 0, vagina: 1, slaveName: name+"'s mother"});
	}

	var dkeys = Object.keys(outdads);
	for(var i = 0; i < dkeys.length; i++) {
		var name;
		var key = dkeys[i];
		var names = outdads[key];
		if(names.length == 1) {
			name = names[0];
		} else if(names.length == 2) {
			name = names.join(' and ');
		} else {
			names[-1] = 'and '+names[-1];
			name = names.join(', ');
		}
		node_lookup[key] = family_graph.nodes.length;
		//Outside extant slaves set
		charList.push({ID: key, mother: 0, father: 0, is_father: true, dick: 1, vagina: -1, slaveName: name+"'s father"});
	}

	var charHash = {};
	for(var i = 0; i < charList.length; i++) {
		charHash[charList[i].ID] = charList[i];
	}

	var related = {};
	var seen = {};
	var saveTree = {};
	function relatedTo(character, targetID, relIDs = {tree: {}, related: false}) {
		relIDs.tree[character.ID] = true;
		if(related[character.ID]) {
			relIDs.related = true;
			return relIDs;
		}
		if(character.ID == targetID) {
			relIDs.related = true;
		}
		if(seen[character.ID]) {
			return relIDs;
		}
		seen[character.ID] = true;
		if(character.mother != 0) {
			if(charHash[character.mother]) {
				relatedTo(charHash[character.mother], targetID, relIDs);
			}
		}
		if(character.father != 0) {
			if(charHash[character.father]) {
				relatedTo(charHash[character.father], targetID, relIDs);
			}
		}
		return relIDs;
	}
	if(filterID) {
		if(charHash[filterID]) {
			var relIDs = relatedTo(charHash[filterID], filterID);
			for(var k in relIDs.tree) {
				related[k] = true;
			}
			for(var i = 0; i < charList.length; i++) {
				if(charHash[charList[i].ID]) {
					var pRelIDs = relatedTo(charHash[charList[i].ID], filterID);
					if(pRelIDs.related) {
						for(var k in pRelIDs.tree) {
							related[k] = true;
							if(saveTree[k]) {
								for(var k2 in saveTree[k].tree) {
									related[k2] = true;
								}
							}
						}
					}
					saveTree[charList[i].ID] = pRelIDs;
				}
			}
		}
	}

	for(var i = 0; i < charList.length; i++) {
		var character = charList[i];
		var char_id = character.ID;
		if(character.mother == 0 && character.father == 0 && !kids[char_id]) {
			continue;
		}
		if(filterID && !related[char_id]) {
			continue;
		}
		node_lookup[char_id] = family_graph.nodes.length;
		var char_obj = {
			ID: char_id,
			name: character.slaveName,
			dick: character.dick,
			unborn: !!unborn[char_id],
			vagina: character.vagina
		};
		if(kids[char_id]) {
			char_obj.is_mother = !!kids[char_id].mother;
			char_obj.is_father = !!kids[char_id].father;
		} else {
			char_obj.is_mother = false;
			char_obj.is_father = false;
		}
		family_graph.nodes.push(char_obj);
	}

	for(var i = 0; i < charList.length; i++) {
		var character = charList[i];
		var char_id = character.ID;
		if(character.mother == 0 && character.father == 0 && !kids[char_id]) {
			continue;
		}
		if(filterID && !related[char_id]) {
			if(related[character.mother]) {
				console.log('wtf, mom');
			}
			if(related[character.father]) {
				console.log('wtf, dad');
			}
			continue;
		}
		if(typeof node_lookup[character.mother] != 'undefined') {
			var ltype;
			if(character.mother == character.father) {
				ltype = 'homologous';
			} else {
				ltype = 'maternal';
			}
			family_graph.links.push({
				type: ltype,
				target: node_lookup[char_id]*1,
				source: node_lookup[character.mother]*1
			});
		}
		if(character.mother == character.father) {
			continue;
		}
		if(typeof node_lookup[character.father] != 'undefined') {
			family_graph.links.push({
				type: 'paternal',
				target: node_lookup[char_id]*1,
				source: node_lookup[character.father]*1
			});
		}
	}
	return family_graph;
};

/*Old version. To use, do something like:

<<run updateFamilyTree($activeSlave, $slaves, $PC)>>

If you want to update the tree, just re-call the run line.

If there's no active slave, you can do:

<<run updateFamilyTree(null, $slaves, $PC)>>
*/

window.updateFamilyTree = function(activeSlave = lastActiveSlave, slaves = lastSlaves, PC = lastPC) {
	lastActiveSlave = activeSlave;
	lastSlaves = slaves;
	lastPC = PC;
	var treeDepth = 0;
	var numTreeNodes = 0;

	var graphElement = document.getElementById("graph");
	if(!graphElement)
		return;
	graphElement.innerHTML = "";

	/* The way this code works is that we start with the activeSlave then we call
		slaveInfo() recursively to work our way up the tree finding their parents.

	*/

	function getSlave(id, expectedGenes) {
		if(id == -1) {
			return {"slaveName":"YOU", "ID":id, "physicalAge":PC.physicalAge, "genes":PC.genes, father:PC.father, mother:PC.mother};
		}
		if(id == 0) {
			return {"slaveName":"-", "ID":id, "genes":expectedGenes};
		}
		if(id == activeSlave.ID) {
			return activeSlave;
		}
		for(var i = 0; i < slaves.length; ++i) {
			if(slaves[i].ID == id)
				return slaves[i];
			}
		return {"slaveName":"-", "ID":id, "genes":expectedGenes};
		}

	function slaveInfo(slave, activeSlaveId, recursionProtectSlaveId = {}) {
	numTreeNodes = 0;
	treeDepth = 0;
	if(recursionProtectSlaveId[slave.ID]) {
		console.log("Recursion protection");
		return slaveInfo_(slave, activeSlaveId);
	}
	recursionProtectSlaveId[slave.ID] = true;

	if(typeof slave.father == "undefined" || typeof slave.mother == "undefined")
		return slaveInfo_(slave, activeSlaveId);

	if(slave.father == -1 || slave.mother == -1) {
		return slaveInfo(getSlave(-1), activeSlaveId, recursionProtectSlaveId);
	}
	if(slave.father != 0) {
		return slaveInfo(getSlave(slave.father, "unknownXY"), activeSlaveId, recursionProtectSlaveId);
	}

	if(slave.mother != 0) {
		return slaveInfo(getSlave(slave.mother, "unknownXX"), activeSlaveId, recursionProtectSlaveId);
	}
	return slaveInfo_(slave, activeSlaveId);
	}
	function slaveInfo_(slave, activeSlaveId, slavesAdded={}, depth = 1) {
	numTreeNodes += 1;
	treeDepth = Math.max(treeDepth, depth);
	var shouldAddChildren = false;
	if(!slavesAdded[slave.ID]) {
		shouldAddChildren = true;
		slavesAdded[slave.ID] = true;
	}
	var data = {
		"name": slave.slaveName + (slave.physicalAge?(" (" + slave.physicalAge + ")"):""),
		"class" : slave.genes,
		"textClass": (activeSlaveId == slave.ID)?"emphasis":"",
		"marriages": [],
	};

	var spouseToChild = {};

	function maybeAddSpouseToChild(child) {
		if(child.ID == slave.ID)
		return;
		if (child.father == slave.ID) {
		if(!spouseToChild[child.mother]) {
			spouseToChild[child.mother] = []
		}
		spouseToChild[child.mother].push(child);
		} else if (child.mother == slave.ID) {
		if(!spouseToChild[child.father]) {
			spouseToChild[child.father] = []
		}
		spouseToChild[child.father].push(child);
		}
	}

	if(activeSlave.ID != PC.ID)
		maybeAddSpouseToChild(activeSlave);
		maybeAddSpouseToChild(getSlave(-1));

	for(var i = 0; i < slaves.length; ++i) {
		var child = slaves[i];
		if(child.ID != activeSlave.ID)
		maybeAddSpouseToChild(child);
	}

	for(var key in spouseToChild) {
		if(spouseToChild.hasOwnProperty(key)) {
			var children = shouldAddChildren?spouseToChild[key]:[];
			var spouse = getSlave(key, (slaves.genes=="XX")?"unknownXY":(slaves.genes=="XY")?"unknownXX":"unknown");
			var spouseName;
			if (spouse.ID != slave.ID){
				spouseName = spouse.slaveName + (spouse.physicalAge?(" (" + spouse.physicalAge + ")"):"")
			} else {
				spouseName = (spouse.ID==-1)?"(yourself)":"(themselves)";
			}
			var marriage = {
				"spouse": {"name": spouseName, "class": spouse.genes},
				"children": children.map(function(x) { return slaveInfo_(x, activeSlaveId, slavesAdded, depth+1)} ),
			};
			data.marriages.push(marriage);
			}
		}
	return data;
	}

	if(activeSlave == PC || activeSlave == null)
		activeSlave = getSlave(-1)
		const treeData = [slaveInfo(activeSlave, activeSlave.ID)];
		console.log("Family tree is", treeData, 'and has:', numTreeNodes);

		var parentWidth = document.getElementById('editFamily').offsetWidth;

		console.log(parentWidth, document.getElementById('passages').offsetWidth);
		if(!parentWidth)
			parentWidth = document.body.offsetWidth - 483;

			console.log(parentWidth, Math.min(200 + 40*numTreeNodes,parentWidth-200) + 200);

			dTree.init(treeData, {
			target: "#graph",
			debug: true,
			height: 50 + 50*treeDepth, /* very rough heuristics */
			width: Math.min(200 + 40*numTreeNodes,
					parentWidth-200) + 200,
			callbacks: {
				nodeClick: function(name, extra) {
			}
		}
	});

};


code:
:: Foreach Macro JS [script]

Macro.add('foreach', {
	skipArgs : true,
	tags : null,

	handler() {
		const payload = this.payload[0].contents.replace(/\n$/, '');
		let statement = this.args.raw.trim();
		let variable;
		let array;
		let result;

		if (statement.length !== 0) {
			const parts = statement.match(/^(\S+?)\s+of\s+(\S.*?)\s*$/i);
			if(parts !== null) {
				variable = parts[1];
				array = parts[2];
			}
		}
		if(!variable || !array) {
			return this.error('invalid syntax, format: <<foreach variable of array-expression>>... <</foreach>>');
		}

		try {
			result = Scripting.evalTwineScript(array);
		} catch (ex) {
			return this.error(`bad evaluation: ${typeof ex === 'object' ? ex.message : ex}`);
		}

		let resultLength = result['length'];

		// We don't check for "instanceof Array" to also be able to pass arguments or other strange objects
		if(typeof resultLength !== 'number' || (resultLength % 1) !== 0) {
			return this.error("bad evaluation: '" + result + "' is not an array or array-like object");
		}

		if(resultLength > Config.macros.maxLoopIterations) {
			return this.error('Array too large for maxLoopIterations (' + resultLength + ' > ' + Config.macros.maxLoopIterations + ')');
		}

		if(!new RegExp(`^(${Patterns.variable})$`).test(variable)) {
			return this.error('not a variable identifier: ' + variable);
		}

		if(resultLength <= 0) {
			// Don't bother with empty stuff
			return;
		}

		Config.debug && this.debugView.modes({block: true});

		payload.replace(/^\n/, '');
		for(let i = 0; i < resultLength; ++ i) {
			Wikifier.setValue(variable, result[i]);
			new Wikifier(this.output, payload);
		}
	}
});


code:
:: generateGenetics [script]

// Generates a child's genetics based off mother and father and returns it as an object to be attached to an ovum
window.generateGenetics = (function() {
	"use strict";
	let genes;
	let mother;
	let activeMother;
	let father;
	let activeFather;
	let V;

	function generateGenetics(actor1, actor2, x) {
		V = State.variables;
		genes = {gender: "XX", name: "blank", surname: 0, mother: 0, motherName: "none", father: 0, fatherName: "none", nationality: "Stateless", race: "white", intelligence: 0, face: 0, eyeColor: "brown", hColor: "black", skin: "white", markings: "none", behavioralFlaw: "none", sexualFlaw: "none", pubicHSyle: "bushy", underArmHStyle: "bushy", geneticQuirks: 0};
		if (actor1.ID > 0) {
			mother = V.genePool.find(function(s) { return s.ID == actor1.ID; });
			if (mother === undefined) {
				mother = actor1;
			}
			activeMother = V.slaves[V.slaveIndices[actor1]];
			if (activeMother === undefined) {
				activeMother = actor1;
			}
		} else {
			activeMother = V.PC;
			mother = V.PC;
		}
		if (actor2 > 0) {
			father = V.genePool.find(function(s) { return s.ID == actor2.ID; });
			activeFather = V.slaves[V.slaveIndices[actor2]];
			if (father === undefined) {
				father = V.slaves[V.slaveIndices[actor2]];
				activeFather = V.slaves[V.slaveIndices[actor2]];
			}
			if (father === undefined) {
				if (V.incubator > 0) {
					father = V.tanks.find(function(s) { return s.ID == actor2.ID; });
					activeFather = 0; // activeFather = father?
				}
			}
			if (father === undefined) {
				if (V.nursery > 0) {
					father = V.cribs.find(function(s) { return s.ID == actor2.ID; });
					activeFather = 0; // activeFather = father?
				}
			}
			if (father === undefined) {
				father = 0;
				activeFather = 0;
			}
		} else if (actor2 == -1) {
			father = V.PC;
			activeFather = V.PC;
		} else {
			father = 0;
			activeFather = 0;
		}

		genes.gender = setGender(father);
		genes.name = setName(x);
		genes.mother = setMotherID(actor1.ID);
		genes.motherName = setMotherName(activeMother);
		genes.father = setFatherID(actor2);
		genes.fatherName = setFatherName(father, activeFather, actor2);
		genes.nationality = setNationality(father, mother);
		genes.skin = setSkin(father, mother);
		genes.race = setRace(father, mother, actor2);
		genes.intelligence = setIntelligence(father, mother, activeMother, actor2);
		genes.face = setFace(father, mother, activeMother, actor2);
		genes.eyeColor = setEyeColor(father, mother, actor2);
		genes.hColor = setHColor(father, mother, actor2);
		genes.underArmHStyle = setUnderArmHStyle(father, mother);
		genes.pubicHStyle = setPubicHStyle(father, mother);
		genes.markings = setMarkings(father, mother);
		genes.sexualFlaw = setSexualFlaw(father, mother);
		genes.behavioralFlaw = setBehavioralFlaw(father, mother);
		genes.fetish = setFetish(father, mother);

		return genes;
	}

	// gender
	function setGender(father) {
		let gender;
		if (V.seeDicksAffectsPregnancy == 1) {
			gender = Math.floor(Math.random()*100) < V.seeDicks ? "XY" : "XX";
		} else if (V.adamPrinciple == 1) {
			if (father !== 0) {
				if (father.genes == "XX") {
					gender = "XX";
				} else {
					gender = jsEither(["XX", "XY", "XY", "YY"]);
				}
			} else {
				gender = jsEither(["XX", "XY"]);
			}
		} else {
			gender = jsEither(["XX", "XY"]);
		}
		return gender;
	}

	// name
	function setName(x) {
		return "ovum" + x;
	}

	// motherID
	function setMotherID(actor1ID) {
		return actor1ID;
	}

	// motherName
	function setMotherName(activeMother) {
		let motherName;
		if (activeMother.ID == -1) {
			motherName = activeMother.name;
			if (activeMother.surname !== 0 && activeMother.surname !== "") { motherName + " " + activeMother.surname; }
		} else {
			motherName = activeMother.slaveName;
			if (activeMother.slaveSurname !== 0 && activeMother.slaveSurname !== "") { motherName + " " + activeMother.slaveSurname; }
		}
		return motherName;
	}

	// fatherID
	function setFatherID(actor2) {
		return actor2;
	}

	// fatherName
	function setFatherName(father, activeFather, actor2) {
		let fatherName;
		if (father !== 0) {
			if (father.ID == -1) {
				fatherName = activeFather.name;
				if (activeFather.surname !== 0 && activeFather.surname !== "") { fatherName + " " + activeFather.surname; }
			} else {
				fatherName = activeFather.slaveName;
				if (activeFather.slaveSurname !== 0 && activeFather.slaveSurname !== "") { fatherName + " " + activeFather.slaveSurname; }
			}
		} else {
			switch(actor2) {
				case -2:
				case -5:
					fatherName = "citizen";
					break;
				case -3:
					fatherName = "Your Master";
					break;
				case -4:
					fatherName = "Another arcology owner";
					break;
				case -6:
					fatherName = "The Societal Elite";
					break;
				case -7:
					fatherName = "Lab designed";
					break;
				default:
					fatherName = "Unknown";
			}
		}
		return fatherName;
	}

	// nationality
	function setNationality(father, mother) {
		return (father === 0) ? "Stateless"
			: (father.nationality == mother.nationality) ? mother.nationality
			: "Stateless";
	}

	// race
	function setRace(father, mother, actor2) {
		let race;
		if (father !== 0) {
			race = (mother.origRace == father.origRace) ? mother.origRace
			: (jsRandom(1,4)) == 4 ? jsEither([father.origRace, mother.origRace])
			: "mixed race";
		} else if (actor2 == -2 || actor2 == -5) {
			if (V.arcologies[0].FSSupremacist != "unset") {
				race = jsEither([mother.origRace, V.arcologies[0].FSSupremacistRace, V.arcologies[0].FSSupremacistRace]);
				if (mother.origRace != V.arcologies[0].FSSupremacistRace) {
					if (jsRandom(1,100) > 50) {
						race = "mixed race";
					}
				}
			} else {
				race = mother.origRace;
			}
		} else {
			race = mother.origRace;
		}
		return race;
	}

	//skin
	function setSkin(father, mother) {
		let skinToMelanin = {
			'pure black': 21,
			ebony: 20,
			black: 19,
			'dark brown': 18,
			brown: 17,
			'light brown': 16,
			dark: 15,
			'dark olive': 14,
			bronze: 13,
			tan: 12,
			tan: 11,
			olive: 10,
			'light olive': 9,
			light: 8,
			light: 7,
			white: 6,
			fair: 5,
			'very fair': 4,
			'extremely fair': 3,
			pale: 2,
			'extremely pale': 1,
			'pure white': 0
		};
		let momSkinIndex = mother ? (skinToMelanin[mother.origSkin] || 11) : 7;
		let dadSkinIndex = father !== 0 ? (skinToMelanin[father.origSkin] || 11) : 7;
		let skinIndex = Math.round(Math.random() * (dadSkinIndex - momSkinIndex) + momSkinIndex);
		return [
			'pure white',
			'extremely pale',
			'pale',
			'extremely fair',
			'very fair',
			'fair',
			'white',
			'light',
			'light',
			'light olive',
			'olive',
			'natural',
			'tan',
			'tan',
			'bronze',
			'dark olive',
			'dark',
			'light brown',
			'brown',
			'dark brown',
			'ebony',
			'black',
			'pure black'
		][skinIndex];
	};

	// eyeColor
	function setEyeColor(father, mother, actor2) {
		let eyeColor;
		if (father !== 0) {
			if (mother.origEye == father.origEye) {
				eyeColor = mother.origEye;
			} else if (mother.origEye == "red" || mother.origEye == "pale red" || mother.origEye == "light red" || mother.origEye == "pale gray" || mother.origEye == "milky white") {
				eyeColor = father.origEye;
			} else if (father.origEye == "red" || father.origEye == "pale red" || father.origEye == "light red" || father.origEye == "pale gray" || father.origEye == "milky white") {
				eyeColor = mother.origEye;
			} else if (mother.origEye == "blue") {
				if (jsRandom(1,4) == 2) {
					eyeColor = mother.origEye;
				} else {
					eyeColor = father.origEye;
				}
			} else if (father.origEye == "blue") {
				if (jsRandom(1,4) == 2) {
					eyeColor = father.origEye;
				} else {
					eyeColor = mother.origEye;
				}
			} else {
				eyeColor = jsEither([mother.origEye, father.origEye]);
			}
		} else if (actor2 === -2 || actor2 === 0 || actor2 === -5) {
			eyeColor = jsEither([mother.origEye, "brown", "blue", "brown", "green", "hazel", "green"]);
		} else {
			eyeColor = mother.origEye;
		}
		return eyeColor;
	}

	// hColor
	function setHColor(father, mother, actor2) {
		let hairColor;
		if (father !== 0) {
			if (mother.origHColor == father.origHColor) {
				hairColor = mother.origHColor;
			} else if (mother.origHColor == "white") {
				hairColor = jsRandom(1,100) == 69 ? mother.origHColor : father.origHColor;
			} else if (father.origHColor == "white") {
				hairColor = jsRandom(1,100) == 69 ? father.origHColor : mother.origHColor;
			} else if (mother.origHColor == "black") {
				hairColor = jsEither([mother.origHColor, mother.origHColor, mother.origHColor, mother.origHColor, mother.origHColor, mother.origHColor, mother.origHColor, father.origHColor]);
			} else if (father.origHColor == "black") {
				hairColor = jsEither([father.origHColor, father.origHColor, father.origHColor, father.origHColor, father.origHColor, father.origHColor, father.origHColor, mother.origHColor]);
			} else if (mother.origHColor == "brown") {
				hairColor = jsEither([mother.origHColor, mother.origHColor, mother.origHColor, father.origHColor]);
			} else if (father.origHColor == "brown") {
				hairColor = jsEither([father.origHColor, father.origHColor, father.origHColor, mother.origHColor]);
			} else {
				hairColor = jsEither([mother.origHColor, father.origHColor]);
			}
		} else if (actor2 === -2 || actor2 === 0 || actor2 === -5) {
			hairColor = jsEither([mother.origHColor, "brown", "blonde", "black", "brown", "black", "brown", "black"]);
		} else {
			hairColor = mother.origHColor;
		}
		return hairColor;
	}

	// underArmHairStyle
	function setUnderArmHStyle(father, mother) {
		let hair;
		if (father !== 0) {
			if (mother.underArmHStyle == "hairless" && father.underArmHStyle == "hairless") {
				hair = "hairless";
			} else if (mother.underArmHStyle == "hairless" || father.underArmHStyle == "hairless") {
				hair = (jsRandom(1,5) == 3) ? "hairless" : jsEither(["bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "hairless"]);
			} else {
				hair = jsEither(["bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "hairless"]);
			}
		} else if (mother.underArmHStyle == "hairless") {
			hair = (jsRandom(1,5) == 3) ? "hairless" : jsEither(["bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "hairless"]);
		} else {
			hair = jsEither(["bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "hairless"]);
		}
		return hair;
	}

	// pubicHairStyle
	function setPubicHStyle(father, mother) {
		let hair;
		if (father !== 0) {
			if (mother.pubicHStyle == "hairless" && father.pubicHStyle == "hairless") {
				hair = "hairless";
			} else if (mother.pubicHStyle == "hairless" || father.pubicHStyle == "hairless") {
				hair = (jsRandom(1,5) == 3) ? "hairless" : jsEither(["bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "hairless"]);
			} else {
				hair = jsEither(["bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "hairless"]);
			}
		} else if (mother.pubicHStyle == "hairless") {
			hair = (jsRandom(1,5) == 3) ? "hairless" : jsEither(["bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "hairless"]);
		} else {
			hair = jsEither(["bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "hairless"]);
		}
		return hair;
	}

	// markings
	function setMarkings(father, mother) {
		let markings;
		if (jsRandom(1,8) == 1) {
			markings = jsEither(["beauty mark", "birthmark"]);
		} else {
			markings = "none";
		}
		if (markings == "none") {
			if (father !== 0) {
				markings = jsEither([mother.markings, father.markings, "none", "none"]);
			} else {
				markings = jsEither([mother.markings, mother.markings, "none", "none"]);
			}
		}
		return markings;
	}

	// sexualFlaw
	function setSexualFlaw(father, mother) {
		let flaw;
		if (father !== 0) {
			flaw = jsEither([mother.sexualFlaw, father.sexualFlaw, "none", "none"]);
		} else {
			flaw = jsEither([mother.sexualFlaw, mother.sexualFlaw, "none", "none"]);
		}
		return flaw;
	}

	// behavioralFlaw
	function setBehavioralFlaw(father, mother) {
		let flaw;
		if (father !== 0) {
			flaw = jsEither([mother.behavioralFlaw, father.behavioralFlaw, "none", "none"]);
		} else {
			flaw = jsEither([mother.behavioralFlaw, mother.behavioralFlaw, "none", "none"]);
		}
		return flaw;
	}

	// fetish
	function setFetish(father, mother) {
		let fetish;
		if (father !== 0) {
			fetish = jsEither(["none", "none", "none", "none", "none", father.fetish, mother.fetish]);
		} else {
			fetish = jsEither(["none", "none", "none", "none", "none", mother.fetish, mother.fetish]);
		}
		if (fetish == "mindbroken") { fetish = "none"; }
		return fetish;
	}

	//intelligence
	function setIntelligence(father, mother, activeMother, actor2) {
		let smarts;
		if (mother.ID == -1) {
			if (actor2 == -6) {
				smarts = jsRandom(90,100);
			} else if (father !== 0) {
				if (father.intelligence < mother.intelligence) {
					smarts = jsRandom(father.intelligence, mother.intelligence);
				} else {
					smarts = jsRandom(mother.intelligence, father.intelligence);
				}
				if (smarts <= 50) {
					smarts += 30;
				}
			} else {
				smarts = jsRandom(50,100);
			}
		} else if (father !== 0) {
			if (father.intelligence < mother.intelligence) {
				smarts = jsRandom(father.intelligence, mother.intelligence);
			} else {
				smarts = jsRandom(mother.intelligence, father.intelligence);
			}
			if (activeMother.breedingMark == 1 && smarts <= 50) {
				smarts = jsRandom(60,100);
			}
		} else {
			smarts = mother.intelligence;
		}
		if (V.inbreeding == 1) {
			if (mother.ID != -1) {
				if (father !== 0 && father.ID == -1 && activeMother.breedingMark != 1) {
					if (smarts >= -95 && jsRandom(1,100) < 40) {
						smarts -= jsRandom(1,10);
						if (smarts >= -95 && jsRandom(1,100) < 20) {
							smarts -= jsRandom(1,5);
						}
					}
				} else {
					if (smarts >= -95 && jsRandom(1,100) < 50) {
						smarts -= jsRandom(1,15);
						if (smarts >= -95 && jsRandom(1,100) < 30) {
							smarts -= jsRandom(1,15);
						}
					}
				}
			}
		}
		return Math.clamp(smarts, -100, 100);
	}

	//face
	function setFace(father, mother, activeMother, actor2) {
		let face;
		if (mother.ID == -1) {
			if (actor2 == -6) {
				face = jsRandom(90,100);
			} else if (father !== 0) {
				if (father.face < mother.face) {
					face = jsRandom(father.face, mother.face);
				} else {
					face = jsRandom(mother.face, father.face);
				}
				if (face <= 40) {
					face += jsRandom(5,20);
				}
			} else {
				face = jsRandom(20,100);
			}
		} else if (father !== 0) {
			if (father.face < mother.face) {
				face = jsRandom(father.face, mother.face);
			} else {
				face = jsRandom(mother.face, father.face);
			}
			if (activeMother.breedingMark == 1 && face < 60) {
				face = jsRandom(60,100);
			}
		} else {
			face = mother.face;
		}
		if (V.inbreeding == 1) {
			if (mother.ID != -1) {
				if (father !== 0 && father.ID == -1 && activeMother.breedingMark != 1) {
					if (face > -100 && jsRandom(1,100) > 60) {
						face -= jsRandom(2,20);
					}
				} else {
					if (face > -100 && jsRandom(1,100) < 50) {
						face -= jsRandom(1,15);
						if (face >= -95 && jsRandom(1,100) < 30) {
							face -= jsRandom(5,20);
						}
					}
				}
			}
		}
		return Math.clamp(face, -100, 100);
	}

	return generateGenetics;

})();

window.generateChild = function(mother, ova, destination) {

	let V = State.variables;
	let genes = ova.genetics; //maybe just argument this? We'll see.
	let pregUpgrade = V.pregnancyMonitoringUpgrade;
	let child = {};

	if (!destination) { //does extra work for the incubator if defined, otherwise builds a simple object
		if (genes.gender == "XX") {
			child.genes = "XX";
			child.slaveSurname = genes.surname;
			if (!pregUpgrade) {
				if (genes.mother == -1) {
					if (genes.father <= 0) {
						child.slaveName = "Your daughter";
					} else {
						child.slaveName = `Your and ${genes.fatherName}'s daughter`;
					}
					child.slaveSurname = V.PC.surname;
				} else {
					if (genes.father == -1) {
						child.slaveName = `${genes.motherName} and your daughter`;
						child.slaveSurname = V.PC.surname;
					} else if (genes.father > 0) {
						child.slaveName = `${genes.motherName} and ${genes.fatherName}'s daughter`;
						let currentMother = getSlave(genes.mother);
						if (currentMother !== undefined) {
							if (currentMother.slaveSurname !== 0 && currentMother.slaveSurname !== "") {
								child.slaveSurname = currentMother.slaveSurname;
							}
						} else {
							let currentFather = getSlave(genes.father);
							if (currentFather !== undefined) {
								if (currentFather.slaveSurname !== 0 && currentFather.slaveSurname !== "") {
									child.slaveSurname = currentFather.slaveSurname;
								}
							}
						}
					} else {
						child.slaveName = `${genes.motherName}'s bastard daughter`;
						let currentMother = getSlave(genes.mother);
						if (currentMother !== undefined) {
							if (currentMother.slaveSurname !== 0 && currentMother.slaveSurname !== "") {
								child.slaveSurname = currentMother.slaveSurname;
							}
						}
					}
				}
			} else {
				child.slaveName = genes.name;
			}
		} else {
			child.genes = "XY";
			child.slaveSurname = genes.surname;
			if (!pregUpgrade) {
				if (genes.mother == -1) {
					if (genes.father <= 0) {
						child.slaveName = "Your son";
					} else {
						child.slaveName = `Your and ${genes.fatherName}'s son`;
					}
					child.slaveSurname = V.PC.surname;
				} else {
					if (genes.father == -1) {
						child.slaveName = `${genes.motherName} and your son`;
						child.slaveSurname = V.PC.surname;
					} else if (genes.father > 0) {
						child.slaveName = `${genes.motherName} and ${genes.fatherName}'s son`;
						let currentMother = getSlave(genes.mother);
						if (currentMother !== undefined) {
							if (currentMother.slaveSurname !== 0 && currentMother.slaveSurname !== "") {
								child.slaveSurname = currentMother.slaveSurname;
							}
						} else {
							let currentFather = getSlave(genes.father);
							if (currentFather !== undefined) {
								if (currentFather.slaveSurname !== 0 && currentFather.slaveSurname !== "") {
									child.slaveSurname = currentFather.slaveSurname;
								}
							}
						}
					} else {
						child.slaveName = `${genes.motherName}'s bastard son`;
						let currentMother = getSlave(genes.mother);
						if (currentMother !== undefined) {
							if (currentMother.slaveSurname !== 0 && currentMother.slaveSurname !== "") {
								child.slaveSurname = currentMother.slaveSurname;
							}
						}
					}
				}
			} else {
				child.slaveName = genes.name;
			}
		}

		child.mother = genes.mother;
		child.father = genes.father;
		child.nationality = genes.nationality;
		child.skin = genes.skin;
		child.race = genes.race;
		child.intelligence = genes.intelligence;
		if (mother.prematureBirth > 0) {
			if (child.intelligence >= -90) {
				child.intelligence -= jsRandom(0,10)
			}
			child.premature = 1;
		}
		child.face = genes.face;
		child.eyeColor = genes.eyeColor;
		child.hColor = genes.hColor;
		child.underArmHStyle = genes.underArmHStyle;
		child.pubicHStyle = genes.pubicHStyle;
		child.markings = genes.markings;
		child.sexualFlaw = genes.sexualFlaw;
		child.behavioralFlaw = genes.behavioralFlaw;
		child.fetish = genes.fetish;
		child.pubicHColor = child.hColor;
		child.underArmHColor = child.hColor;
		child.eyebrowHColor = child.hColor;
		child.birthWeek = child.birthWeek;
		if (mother.addict > 0) {
			child.addict = Math.trunc(mother.addict/2);
		}
		child.weekAcquired = V.week;
		if (child.nationality == "Stateless") {
			if (V.arcologies[0].FSRomanRevivalist > 90) {
				child.nationality = "Roman Revivalist";
			} else if (V.arcologies[0].FSAztecRevivalist > 90) {
				child.nationality = "Aztec Revivalist";
			} else if (V.arcologies[0].FSEgyptianRevivalist > 90) {
				child.nationality = "Ancient Egyptian Revivalist";
			} else if (V.arcologies[0].FSEdoRevivalist > 90) {
				child.nationality = "Edo Revivalist";
			} else if (V.arcologies[0].FSArabianRevivalist > 90) {
				child.nationality = "Arabian Revivalist";
			} else if (V.arcologies[0].FSChineseRevivalist > 90) {
				child.nationality = "Ancient Chinese Revivalist";
			}
		}

	} else {

		V.activeSlaveOneTimeMinAge = V.targetAge;
		V.activeSlaveOneTimeMaxAge = V.targetAge;
		V.one_time_age_overrides_pedo_mode = 1;
		V.ageAdjustOverride = 1;

		if (genes.gender == "XX") {
			GenerateNewSlave("XX");
			child = V.activeSlave;
			child.slaveSurname = genes.surname;
			if (!pregUpgrade) {
				if (genes.mother == -1) {
					if (genes.father <= 0) {
						child.slaveName = "Your daughter";
					} else {
						child.slaveName = `Your and ${genes.fatherName}'s daughter`;
					}
					child.slaveSurname = V.PC.surname;
				} else {
					if (genes.father == -1) {
						child.slaveName = `${genes.motherName} and your daughter`;
						child.slaveSurname = V.PC.surname;
					} else if (genes.father > 0) {
						child.slaveName = `${genes.motherName} and ${genes.fatherName}'s daughter`;
						let currentMother = getSlave(genes.mother);
						if (currentMother !== undefined) {
							if (currentMother.slaveSurname !== 0 && currentMother.slaveSurname !== "") {
								child.slaveSurname = currentMother.slaveSurname;
							}
						} else {
							let currentFather = getSlave(genes.father);
							if (currentFather !== undefined) {
								if (currentFather.slaveSurname !== 0 && currentFather.slaveSurname !== "") {
									child.slaveSurname = currentFather.slaveSurname;
								}
							}
						}
					} else {
						child.slaveName = `${genes.motherName}'s bastard daughter`;
						let currentMother = getSlave(genes.mother);
						if (currentMother !== undefined) {
							if (currentMother.slaveSurname !== 0 && currentMother.slaveSurname !== "") {
								child.slaveSurname = currentMother.slaveSurname;
							}
						}
					}
				}
			} else {
				child.slaveName = genes.name;
			}
		} else {
			GenerateNewSlave("XY");
			child = V.activeSlave;
			child.slaveSurname = genes.surname;
			if (!pregUpgrade) {
				if (genes.mother == -1) {
					if (genes.father <= 0) {
						child.slaveName = "Your son";
					} else {
						child.slaveName = `Your and ${genes.fatherName}'s son`;
					}
					child.slaveSurname = V.PC.surname;
				} else {
					if (genes.father == -1) {
						child.slaveName = `${genes.motherName} and your son`;
						child.slaveSurname = V.PC.surname;
					} else if (genes.father > 0) {
						child.slaveName = `${genes.motherName} and ${genes.fatherName}'s son`;
						let currentMother = getSlave(genes.mother);
						if (currentMother !== undefined) {
							if (currentMother.slaveSurname !== 0 && currentMother.slaveSurname !== "") {
								child.slaveSurname = currentMother.slaveSurname;
							}
						} else {
							let currentFather = getSlave(genes.father);
							if (currentFather !== undefined) {
								if (currentFather.slaveSurname !== 0 && currentFather.slaveSurname !== "") {
									child.slaveSurname = currentFather.slaveSurname;
								}
							}
						}
					} else {
						child.slaveName = `${genes.motherName}'s bastard son`;
						let currentMother = getSlave(genes.mother);
						if (currentMother !== undefined) {
							if (currentMother.slaveSurname !== 0 && currentMother.slaveSurname !== "") {
								child.slaveSurname = currentMother.slaveSurname;
							}
						}
					}
				}
			} else {
				child.slaveName = genes.name;
			}
		}

		child.mother = genes.mother;
		child.father = genes.father;
		child.nationality = genes.nationality;
		child.skin = genes.skin;
		child.origSkin = child.skin;
		child.race = genes.race;
		child.origRace = child.race;
		child.intelligence = genes.intelligence;
		if (mother.prematureBirth > 0) {
			if (child.intelligence >= -90) {
				child.intelligence -= jsRandom(0,10)
			}
			child.premature = 1;
		}
		child.face = genes.face;
		child.eyeColor = genes.eyeColor;
		child.origEye = child.eyeColor;
		child.hColor = genes.hColor;
		child.origHColor = child.HColor;
		child.underArmHStyle = genes.underArmHStyle;
		child.pubicHStyle = genes.pubicHStyle;
		child.markings = genes.markings;
		child.sexualFlaw = genes.sexualFlaw;
		child.behavioralFlaw = genes.behavioralFlaw;
		child.fetish = genes.fetish;
		child.pubicHColor = child.hColor;
		child.underArmHColor = child.hColor;
		child.eyebrowHColor = child.hColor;
		child.birthWeek = child.birthWeek;
		child.energy = 0;
		child.anus = 0;
		if (child.vagina > 0) {child.vagina = 0;}
		if (child.fetish != "none") {child.fetishStrength = 20;}
		if (child.dick > 0) {
			child.foreskin = 1;
			child.balls = 1;
			child.scrotum = 1;
		}
		if (mother.addict > 0) {
			child.addict = Math.trunc(mother.addict/2);
		}
		child.career = "a slave since birth";
		child.birthName = child.slaveName;
		child.birthSurname = child.slaveSurname;
		child.devotion = 0;
		child.trust = 0;
		child.weekAcquired = V.week;
		if (child.nationality == "Stateless") {
			if (V.arcologies[0].FSRomanRevivalist > 90) {
				child.nationality = "Roman Revivalist";
			} else if (V.arcologies[0].FSAztecRevivalist > 90) {
				child.nationality = "Aztec Revivalist";
			} else if (V.arcologies[0].FSEgyptianRevivalist > 90) {
				child.nationality = "Ancient Egyptian Revivalist";
			} else if (V.arcologies[0].FSEdoRevivalist > 90) {
				child.nationality = "Edo Revivalist";
			} else if (V.arcologies[0].FSArabianRevivalist > 90) {
				child.nationality = "Arabian Revivalist";
			} else if (V.arcologies[0].FSChineseRevivalist > 90) {
				child.nationality = "Ancient Chinese Revivalist";
			}
		}

		child.weight = -100;
		child.muscles = -100;
		child.boobs = 0;
		child.butt = 0;
		child.chem = 990;
		child.areolaePiercing = 0;
		child.corsetPiercing = 0;
		child.boobsImplant = 0;
		child.boobsImplantType = 0;
		child.nipplesPiercing = 0;
		child.areolaePiercing = 0;
		child.lactation = 0;
		child.hipsImplant = 0;
		child.buttImplant = 0;
		child.buttImplantType = 0;
		child.lipsImplant = 0;
		child.lipsPiercing = 0;
		child.tonguePiercing = 0;
		child.vaginaPiercing = 0;
		child.preg = 0;
		child.pregType = 0;
		child.pregKnown = 0;
		child.belly = 0;
		child.bellyPreg = 0;
		child.bellyFluid = 0;
		child.bellyImplant = -1;
		child.clitPiercing = 0;
		child.dickPiercing = 0;
		child.makeup = 0;
		child.nails = 0;
		child.earPiercing = 0;
		child.nosePiercing = 0;
		child.eyebrowPiercing = 0;
		child.stampTat = 0;
		child.bellyTat = 0;
		child.anusPiercing = 0;
		child.anusTat = 0;
		child.shouldersTat = 0;
		child.armsTat = 0;
		child.legsTat = 0;
		child.backTat = 0;
		child.combatSkill = 0;
		child.whoreSkill = 0;
		child.entertainSkill = 0;
		child.oralSkill = 0;
		child.analSkill = 0;
		child.vaginalSkill = 0;
		child.accent = 4;
		child.canRecruit = 0;
		child.hStyle = "long";
		child.hLength = 300;
		if (V.incubatorImprintSetting == "terror") {
			child.origin = "She was conditioned from birth into mindless terror in an aging tank.";
			child.tankBaby = 2;
		} else {
			child.origin = "She was conditioned from birth into trusting obedience in an aging tank.";
			child.tankBaby = 1;
		}
		child.intelligenceImplant = 0;
		child.navelPiercing = 0;
	}
	return child;
}


code:
:: HTAG Macro JS [script]

/*
 * <<htag>> macro
 * A simple macro which allows to create wrapping html elements with dynamic IDs.
 *	idea blatantly robbed from the spanMacroJS.tw but expanded to a more generic
 *	case, allowing <div>, <button> or whatever you want. elements, default is for
 *	the div though. In addition, you can pass an object in as the first argument
 *	instead of an id, and each of the object's attributes will become attributes
 *	of the generate tag.
 *
 * Usage: <<htag id>>...<</htag>>
 * Usage: <<htag id tag>>...<</htag>>
 * Usage: <<htag attributes>>...<</htag>>
 * Usage: <<htag attributes tag>>...<</htag>>
 */
Macro.add('htag', {
	tags: null,
	handler() {
		const payload = this.payload[0].contents.replace(/(^\n+|\n+$)/, '');
		let htag = 'div';
		let attributes;
		function munge (val, key) {
			return key + '="' + val + '"';
		}

		if (1 > this.args.length)
			return this.error('invalid syntax, format: <<htag [id [ tag ] | attributes [ tag ] >>');
		if (1 < this.args.length)
			htag = String(this.args[1]).trim();
		if ("object" === typeof this.args[0])
			attributes = $.map(this.args[0], munge).join(" ");
		else
			attributes = 'id="' + String(this.args[0]).trim() + '"';
		if (Config.debug)
			this.debugView.modes({block: true});

		jQuery('<' + htag + ' ' + attributes + ' />')
			.wiki(payload)
			.appendTo(this.output);
	}
});


code:
:: heroCreator.tw [script]

window.getHeroSlave = function(heroSlave, baseHeroSlave) {
	var newSlave = clone(baseHeroSlave);
	for (var attrname in heroSlave) {
		newSlave[attrname] = heroSlave[attrname];
	};
	return newSlave;
}


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 (V.cheatMode === 1){
		return true;
	} else {
		switch (string) { /* no breaks needed because we always return */
		case 'attractive lingerie for a pregnant woman':
			return (V.arcologies[0].FSRepopulationFocus > 0 || V.clothesBoughtMaternityLingerie === 1);
		case 'a bunny outfit':
			return (V.arcologies[0].FSGenderFundamentalist > 0 || V.clothesBoughtBunny === 1);
		case 'body oil':
			return (V.arcologies[0].FSPhysicalIdealist > 0 || V.clothesBoughtOil === 1);
		case 'chains':
			return (V.arcologies[0].FSDegradationist > 0 || V.clothesBoughtChains === 1);
		case 'a chattel habit':
			return (V.arcologies[0].FSChattelReligionist > 0 || V.clothesBoughtHabit === 1);
		case 'conservative clothing':
			return (V.arcologies[0].FSPaternalist > 0 || V.clothesBoughtConservative === 1);
		case 'harem gauze':
			return (V.arcologies[0].FSArabianRevivalist > 0 || V.clothesBoughtHarem === 1);
		case 'a huipil':
			return (V.arcologies[0].FSAztecRevivalist > 0 || V.clothesBoughtHuipil === 1);
		case 'a kimono':
			return (V.arcologies[0].FSEdoRevivalist > 0 || V.clothesBoughtKimono === 1 || V.continent === 'Japan');
		case 'a maternity dress':
			return (V.arcologies[0].FSRepopulationFocus > 0 || V.clothesBoughtMaternityDress === 1);
		case 'a slutty qipao':
			return (V.arcologies[0].FSChineseRevivalist > 0 || V.clothesBoughtQipao === 1);
		case 'a long qipao':
			return (V.arcologies[0].FSChineseRevivalist > 0 || V.clothesBoughtCultural === 1);
		case 'stretch pants and a crop-top':
			return (V.arcologies[0].FSHedonisticDecadence > 0 || V.clothesBoughtLazyClothes === 1);
		case 'a toga':
			return (V.arcologies[0].FSRomanRevivalist > 0 || V.clothesBoughtToga === 1);
		case 'Western clothing':
			return (V.arcologies[0].FSPastoralist > 0 || V.clothesBoughtWestern === 1);
		case 'battlearmor':
		case 'a military uniform':
		case 'a red army uniform':
		case 'battledress':
			return (V.clothesBoughtMilitary === 1);
		case 'a biyelgee costume':
		case 'a dirndl':
		case 'lederhosen':
		case 'a mounty outfit':
		case 'a hanbok':
			return (V.clothesBoughtCultural === 1);
		case 'a burqa':
		case 'a burkini':
		case 'a blouse and hijab':
		case 'a niqab and abaya':
			return (V.clothesBoughtMiddleEastern === 1 || V.continent === 'the Middle East');
		case 'a klan robe':
		case 'a slutty klan robe':
		case 'a schutzstaffel uniform':
		case 'a slutty schutzstaffel uniform':
			return (V.clothesBoughtPol === 1);
		case 'a nice nurse outfit':
		case 'a police uniform':
		case 'nice business attire':
			return (V.clothesBoughtCareer === 1);
		case 'a nice maid outfit':
			return (V.clothesBoughtCareer === 1 || V.PC.career === 'servant');
		case 'a ball gown':
		case 'a gothic lolita dress':
		//case 'a halter top dress':
		//case 'a mini dress':
		//case 'a slave gown':
			return (V.clothesBoughtDresses === 1);
		case 'a cybersuit':
		case 'a latex catsuit':
			return (V.clothesBoughtBodysuits === 1);
		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':
			return (V.clothesBoughtCasual === 1);
		case 'boyshorts':
		case 'a bra':
		case 'kitty lingerie':
		case 'panties and pasties':
		case 'a skimpy loincloth':
		case 'a thong':
			return (V.clothesBoughtUnderwear === 1);
		case 'leather pants and pasties':
		case 'a t-shirt and thong':
		case 'a tube top and thong':
		case 'an oversized t-shirt and boyshorts':
			return (V.clothesBoughtUnderwear === 1 && V.clothesBoughtCasual === 1);
		case 'sport shorts and a sports bra':
		case 'sport shorts':
		case 'a sports bra':
			return (V.clothesBoughtSports === 1);
		case 'sport shorts and a t-shirt':
			return (V.clothesBoughtSports === 1 && V.clothesBoughtCasual === 1);
		case 'a nice pony outfit':
		case 'a slutty pony outfit':
			return (V.clothesBoughtPony === 1);
		case 'a monokini':
		case 'a one-piece swimsuit':
			return (V.clothesBoughtSwimwear === 1);
		case 'shimapan panties':
		case 'a striped bra':
		case 'striped panties':
		case 'striped underwear':
			return (V.clothesBoughtPantsu === 1 || V.continent === 'Japan');
		case 'bowtie':
			return (V.arcologies[0].FSGenderFundamentalist > 0 || V.clothesBoughtBunny === 1);
		case 'ancient Egyptian':
			return (V.arcologies[0].FSEgyptianRevivalist > 0 || V.clothesBoughtEgypt === 1);
		case 'massive dildo gag':
			return (V.toysBoughtGags === 1);
		case 'a small empathy belly':
		case 'a medium empathy belly':
		case 'a large empathy belly':
		case 'a huge empathy belly':
			return (V.arcologies[0].FSRepopulationFocus > 0 || V.clothesBoughtBelly === 1);
		case 'long dildo':
		case 'long, large dildo':
		case 'long, huge dildo':
			return (V.toysBoughtDildos === 1);
		case 'long plug':
		case 'long, large plug':
		case 'long, huge plug':
			return (V.toysBoughtButtPlugs === 1);
		case 'tail':
		case 'cat tail':
		case 'fox tail':
			return (V.toysBoughtButtPlugTails === 1);
		default:
			return true;
		}
	}
};


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 > 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';
		}
	} 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 = jsRandom(actor.pregData.normalOvaMin, actor.pregData.normalOvaMax); //for default human profile it's always 1.
	var 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:

		var 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.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.boobsMilk-slave.boobsWombVolume;
};


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 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');

		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 accessibility
		})
		.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;
}