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

repo_name: nook/fc


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 son`;
						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 son`;
						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:
:: Generate New Slave JS [script]

window.GenerateNewSlave = (function(){
	'use strict';
	let V, slave;

	function GenerateNewSlave(sex) {
		V = State.variables;
		BaseSlave();
		slave = V.activeSlave;

		preGenCombinedStats();
		if (!sex) {
			if (jsRandom(0,99) < V.seeDicks) {
				GenerateXYSlave();
			} else if (V.seeDicks > 0) {
				var femaleSlaveGen = 80;
				if (V.arcologies[0].FSGenderFundamentalistSMR == 1 || V.arcologies[0].FSRepopulationFocusSMR == 1) {
					femaleSlaveGen = 90;
				} else if (V.arcologies[0].FSGenderRadicalist != "unset") {
					femaleSlaveGen = 50;
				}
				if (jsRandom(1,100) > femaleSlaveGen && jsRandom(0,99) < V.seeDicks) {
					GenerateXYSlave();
				} else {
					GenerateXXSlave();
				}
			} else {
				GenerateXXSlave();
			}
		} else if (sex == "XY") {
			GenerateXYSlave();
		} else {
			GenerateXXSlave();
		}

		postGenCleanup();
	};

	function preGenCombinedStats() {
		slave.ID = V.IDNumber++;
		slave.weekAcquired = V.week;
		slave.canRecruit = 1;
		slave.devotion = jsRandom(-90,-60);
		slave.trust = jsRandom(-45,-25);
		slave.weight = jsRandom(-100,180);
		slave.health = jsRandom(-50,50);

		WombInit(slave);
		generateAge();
		generateIntelligence();
		generateCareer();
		generateNationality(); /* includes race selection */
		generateAccent();
		nationalityToName(slave);
		generateRacialTraits();
	};

	function postGenCleanup() {
		generateBoobTweaks(); /* split this up for female vs. male? */
		generateSkills();
		generateDisabilities();
		generatePronouns(slave);
		slave.origRace = slave.race;
		slave.origEye = slave.eyeColor;
		slave.origHColor = slave.hColor;
		slave.origSkin = slave.skin;
	};

	function GenerateXXSlave() {
		slave.ovaries = 1;
		slave.pubertyXY = 0;
		slave.energy = jsRandom(1,85);

		generateXXBodyProportions();
		generateVagina();
		generateXXPreferences();
		generateXXButt();
		generateXXBoobs();
		generateXXFace();
		generateXXPregAdaptation();
		generateXXVoice();
		generateXXTeeth();
		generateXXMods();
		generateXXBodyHair();
		generateXXPuberty();
	};

	function GenerateXYSlave() {
		slave.genes = "XY";
		slave.hLength = 10;
		slave.prostate = 1;
		slave.pubertyXX = 0;
		slave.energy = jsRandom(15,90);

		generateXYBodyProportions();
		generateDick();
		generateCircumcision();
		generateXYPreferences(); /* must happen after genitalia generation */
		generateXYButt(); /* must happen after preferences */
		generateXYBoobs();
		generateXYFace();
		generateXYPregAdaptation();
		generateXYVoice();
		generateXYTeeth();
		generateXYMods();
		generateXYBodyHair();
		generateXYPuberty();
	};

	function generateXXBodyProportions() {
		slave.height = Math.round(Height.random(slave));
		if (slave.height >= Height.mean(slave) * 170/162.5) {
			slave.hips = jsEither([-1, 0, 0, 1, 1, 2, 2]);
			slave.shoulders = jsEither([-1, -1, 0, 0, 0, 1]);
		} else {
			slave.hips = jsEither([-1, 0, 0, 0, 1, 1, 2]);
			slave.shoulders = jsEither([-2, -1, -1, 0, 0, 1]);
		}
		if (slave.physicalAge <= 11) {
			slave.hips = jsEither([-2, -2, -1, -1, 0]);
		} else if (slave.physicalAge <= 13) {
			slave.hips = jsEither([-2, -1, -1, 0, 1]);
		}
		if (slave.weight < -30) {
			slave.waist = jsRandom(-55,0);
		} else if (slave.physicalAge < 13) {
			slave.waist = jsRandom(-25,25);
		} else if (slave.weight <= 30) {
			slave.waist = jsRandom(-45,45);
		} else if (slave.weight <= 160) {
			slave.waist = jsRandom(0,55);
		} else {
			slave.waist = jsRandom(50,100);
		}
	};

	function generateXYBodyProportions() {
		slave.height = Math.round(Height.random(slave));
		if (slave.physicalAge <= 13) {
			if (slave.height > Height.mean(slave) * 170/172.5) {
				slave.hips = jsEither([-2, -1, -1, 0, 1]);
				slave.shoulders = jsEither([-1, -1, 0, 0, 0, 1]);
			} else {
				slave.hips = jsEither([-2, -2, -1, -1, 0]);
				slave.shoulders = jsEither([-2, -1, -1, 0, 0, 1]);
			}
		} else {
			if (slave.height > Height.mean(slave) * 170/172.5) {
				slave.hips = jsEither([-2, -1, -1, 0, 1]);
				slave.shoulders = jsEither([-1, 0, 1, 1, 2, 2]);
			} else {
				slave.hips = jsEither([-2, -2, -1, -1, 0]);
				slave.shoulders = jsEither([-1, 0, 0, 1, 1, 2]);
			}
		}
		if (slave.physicalAge < 13) {
			slave.waist = jsRandom(-15,25);
		} else if (slave.weight < -30) {
			slave.waist = jsRandom(-45,45);
		} else if (slave.weight <= 30) {
			slave.waist = jsRandom(-15,65);
		} else if (slave.weight <= 160) {
			slave.waist = jsRandom(5,100);
		} else {
			slave.waist = jsRandom(50,100);
		}
	};

	function generateVagina() {
		if (slave.physicalAge <= 13) {
			slave.vagina = jsEither([0, 0, 0, 0, 0, 0, 0, 1]);
		} else if (slave.physicalAge <= 15) {
			slave.vagina = jsEither([0, 0, 0, 0, 0, 0, 1, 1]);
		} else if (slave.physicalAge <= 17) {
			slave.vagina = jsEither([0, 0, 0, 0, 0, 1, 1, 1]);
		} else if (slave.physicalAge < 20) {
			slave.vagina = jsEither([0, 1]);
		} else if (slave.physicalAge > 30) {
			slave.vagina = jsEither([1, 1, 1, 1, 2]);
		} else {
			slave.vagina = jsEither([0, 0, 1, 1, 1]);
		}

		if (slave.physicalAge <= 11) {
			slave.clit = jsEither([0, 0, 0, 0, 0, 0, 0, 0, 1]);
		} else if (slave.physicalAge <= 13) {
			slave.clit = jsEither([0, 0, 0, 0, 0, 0, 0, 1, 1]);
		} else if (slave.physicalAge <= 15) {
			slave.clit = jsEither([0, 0, 0, 0, 0, 0, 0, 1, 2]);
		} else {
			slave.clit = jsEither([0, 0, 0, 0, 0, 0, 1, 1, 2]);
		}

		if (slave.physicalAge <= 11) {
			slave.labia = jsEither([0, 0, 0, 0, 0, 0, 0, 1, 1]);
		} else if (slave.physicalAge <= 12) {
			slave.labia = jsEither([0, 0, 0, 0, 0, 0, 1, 1, 1]);
		} else if (slave.physicalAge <= 13) {
			slave.labia = jsEither([0, 0, 0, 0, 0, 1, 1, 1, 1]);
		} else if (slave.physicalAge <= 14) {
			slave.labia = jsEither([0, 0, 0, 0, 1, 1, 1, 1, 2]);
		} else if (slave.physicalAge <= 15) {
			slave.labia = jsEither([0, 0, 0, 1, 1, 1, 1, 2, 2]);
		} else {
			slave.labia = jsEither([0, 0, 0, 1, 1, 1, 1, 2, 2, 3]);
		}

		if (slave.energy < random(1,80)) {
			slave.vaginaLube = 0;
		} else if ( slave.physicalAge > random(35,60)) {
			slave.vaginaLube = 0;
		} else {
			slave.vaginaLube = 1;
		}
		slave.foreskin = jsRandom(0,4);
	};

	function generateDick() {
		slave.vagina = -1;
		slave.clit = 0;
		slave.preg = 0;

		if (slave.physicalAge <= 13) {
			slave.dick = jsEither([1, 1, 1, 1, 2, 2, 2, 3]);
			if (V.seeExtreme == 1) {
				slave.balls = jsEither([0, 0, 1, 1, 1, 2, 2, 2, 2, 3, 3]);
			} else {
				slave.balls = jsEither([1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3]);
			}
			slave.scrotum = slave.balls;
		} else if (slave.physicalAge <= 15) {
			slave.dick = jsEither([1, 1, 1, 2, 2, 2, 3]);
			if (V.seeExtreme == 1) {
				slave.balls = jsEither([0, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4]);
			} else {
				slave.balls = jsEither([1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4]);
			}
			slave.scrotum = slave.balls;
		} else if (slave.physicalAge <= 17) {
			slave.dick = jsEither([1, 1, 2, 2, 3, 3]);
			if (V.seeExtreme == 1) {
				slave.balls = jsEither([0, 1, 1, 2, 2, 2, 3, 3, 3, 4, 5]);
			} else {
				slave.balls = jsEither([1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 5]);
			}
			slave.scrotum = slave.balls;
		} else {
			slave.dick = jsEither([1, 2, 2, 2, 3, 3, 3, 4, 4, 5]);
			if (V.seeExtreme == 1) {
				slave.balls = jsEither([0, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5]);
			} else {
				slave.balls = jsEither([1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 5]);
			}
			if (slave.balls != 0) {
				slave.scrotum = slave.balls + jsEither([0, 0, 1]);
			} else {
				slave.scrotum = 0;
			}
			if (jsRandom(1,100) < 3) {
				slave.vasectomy = 1;
			}
		}
	};

	function generateCircumcision() {
		/* The default rate of 50* is wildly unrepresentative, and there is extreme regional variation. */
		/*
		What we want is the prevalence among newborns, since this game
		happens about 20 years in the future, but we'll use this lacking
		something better.
		https://pophealthmetrics.biomedcentral.com/articles/10.1186/s12963-016-0073-5
		Right now we mostly just break it down by country.
		It would be better to break it down by both country
		and race if statistics are available.
		*/
		if (V.seeCircumcision == 0) {
			slave.foreskin = slave.dick + jsRandom(0,1);
		} else {
			/* Temporarily use activeSlave.foreskin to store the chance of circumcision. */
			switch (slave.nationality) {
				case "Afghan":
				case "Iranian":
				case "Moroccan":
				case "Palestinian":
				case "Sahrawi":
				case "Tunisian":
					slave.foreskin = 100;
					break;
				case "Comorian":
				case "Gabonese":
				case "Iraqi":
				case "Jordanian":
				case "Kurdish":
				case "Mauritanian":
				case "Nigerian":
				case "Tajik":
				case "Turkish":
				case "Yemeni":
					slave.foreskin = 99;
					break;
				case "Algerian":
				case "Azerbaijani":
				case "Liberian":
				case "Maldivian":
					slave.foreskin = 98;
					break;
				case "Djiboutian":
				case "Eritrean":
				case "Ivorian":
				case "Libyan":
				case "Saudi":
				case "Uzbek":
					slave.foreskin = 97;
					break;
				case "Nigerien":
				case "Pakistani":
				case "Sierra Leonean":
				case "Turkmen":
				case "Zairian":
					slave.foreskin = 96;
					break;
				case "a Cook Islander":
				case "Egyptian":
				case "Gambian":
				case "Guamanian":
				case "Malagasy":
				case "Nauruan":
				case "Ni-Vanuatu":
				case "Niuean":
				case "Palauan":
				case "Samoan":
				case "a Solomon Islander":
				case "Togolese":
				case "Tongan":
				case "Tuvaluan":
					slave.foreskin = 95;
					break;
				case "Cameroonian":
				case "Senegalese":
				case "Somali":
					slave.foreskin = 94;
					break;
				case "Bangladeshi":
				case "Beninese":
				case "Bissau-Guinean":
				case "Indonesian":
				case "Syrian":
					slave.foreskin = 93;
					break;
				case "Ethiopian":
				case "Filipina":
				case "Ghanan":
				case "Israeli":
				case "Kosovan":
					slave.foreskin = 92;
					break;
				case "Kenyan":
				case "Kyrgyz":
					slave.foreskin = 91;
					break;
				case "Burkinabé":
				case "Omani":
					slave.foreskin = 88;
					break;
				case "Equatoguinean":
					slave.foreskin = 87;
					break;
				case "Kuwaiti":
				case "Malian":
					slave.foreskin = 86;
					break;
				case "Guinean":
					slave.foreskin = 84;
					break;
				case "Bahraini":
					slave.foreskin = 81;
					break;
				case "French Polynesian":
					slave.foreskin = 78;
					break;
				case "American":
				case "Qatari":
					slave.foreskin = 77;
					break;
				case "Emirati":
					slave.foreskin = 76;
					break;
				case "Chadian":
					slave.foreskin = 74;
					break;
				case "Tanzanian":
					slave.foreskin = 72;
					break;
				case "Congolese":
					slave.foreskin = 70;
					break;
				case "Central African":
					slave.foreskin = 63;
					break;
				case "Burundian":
				case "Malaysian":
					slave.foreskin = 61;
					break;
				case "Lebanese":
					slave.foreskin = 60;
					break;
				case "Angolan":
					slave.foreskin = 58;
					break;
				case "Fijian":
				case "Kazakh":
					slave.foreskin = 56;
					break;
				case "Bruneian":
				case "Korean":
				case "Mosotho":
					/* Population-weighted average of South Korea and North Korea. */
					slave.foreskin = 52;
					break;
				case "New Caledonian":
					slave.foreskin = 50;
					break;
				case "Albanian":
					slave.foreskin = 48;
					break;
				case "Mozambican":
					slave.foreskin = 47;
					break;
				case "South African":
					slave.foreskin = 45;
					break;
				case "Dominican":
					slave.foreskin = 43;
					break;
				case "Bosnian":
					slave.foreskin = 42;
					break;
				case "Sudanese":
					slave.foreskin = 39;
					break;
				case "Mexican":
					slave.foreskin = 38;
					break;
				case "Macedonian":
					slave.foreskin = 34;
					break;
				case "a New Zealander":
					slave.foreskin = 33;
					break;
				case "Canadian":
					slave.foreskin = 32;
					break;
				case "Scottish":
					slave.foreskin = 28;
					break;
				case "Australian":
				case "Ugandan":
					slave.foreskin = 27;
					break;
				case "Namibian":
					slave.foreskin = 26;
					break;
				case "South Sudanese":
					slave.foreskin = 24;
					break;
				case "Belgian":
				case "Cypriot":
				case "Thai":
					slave.foreskin = 23;
					break;
				case "Malawian":
					slave.foreskin = 22;
					break;
				case "British":
					slave.foreskin = 21;
					break;
				case "Puerto Rican":
					slave.foreskin = 20;
					break;
				case "Montenegrin":
					slave.foreskin = 19;
					break;
				case "Mauritian":
					slave.foreskin = 17;
					break;
				case "Motswana":
				case "Singaporean":
				case "Surinamese":
					slave.foreskin = 15;
					break;
				case "Chinese":
				case "French":
				case "Indian":
				case "Jamaican":
					slave.foreskin = 14;
					break;
				case "Bulgarian":
				case "Rwandan":
				case "Zambian":
					slave.foreskin = 13;
					break;
				case "French Guianan":
				case "Guyanese":
				case "Russian":
					slave.foreskin = 12;
					break;
				case "German":
					slave.foreskin = 11;
					break;
				case "Belarusian":
				case "Georgian":
				case "Papua New Guinean":
					slave.foreskin = 10;
					break;
				case "Japanese":
				case "Zimbabwean":
					slave.foreskin = 9;
					break;
				case "Slovene":
				case "Sri Lankan":
				case "Swazi":
				case "Taiwanese":
					slave.foreskin = 8;
					break;
				case "Catalan":
				case "Haitian":
				case "Spanish":
					slave.foreskin = 7;
					break;
				case "Austrian":
				case "Dutch":
				case "East Timorese":
				case "Swiss":
				case "Trinidadian":
					slave.foreskin = 6;
					break;
				case "Danish":
				case "Greek":
				case "a Liechtensteiner":
				case "Swedish":
					slave.foreskin = 5;
					break;
				case "Burmese":
				case "Cambodian":
				case "Mongolian":
				case "Nepalese":
				case "Peruvian":
				case "Serbian":
					slave.foreskin = 4;
					break;
				case "Argentinian":
				case "Italian":
				case "Norwegian":
					slave.foreskin = 3;
					break;
				case "Luxembourgian":
				case "Tibetan":
				case "Ukrainian":
				case "Vincentian":
					slave.foreskin = 2;
					break;
				case "Andorran":
				case "Barbadian":
				case "Bermudian":
				case "Bhutanese":
				case "Brazilian":
				case "Croatian":
				case "Finnish":
				case "Hungarian":
				case "Irish":
				case "Moldovan":
				case "Monégasque":
				case "Panamanian":
				case "Portuguese":
				case "Seychellois":
				case "Uruguayan":
					slave.foreskin = 1;
					break;
				case "Antiguan":
				case "Armenian":
				case "Bahamian":
				case "Belizean":
				case "Bolivian":
				case "Cape Verdean":
				case "Chilean":
				case "Colombian":
				case "Costa Rican":
				case "Cuban":
				case "Czech":
				case "Dominiquais":
				case "Ecuadorian":
				case "Estonian":
				case "Greenlandic":
				case "Grenadian":
				case "Guatemalan":
				case "Honduran":
				case "I-Kiribati":
				case "Icelandic":
				case "Kittitian":
				case "Laotian":
				case "Latvian":
				case "Lithuanian":
				case "Maltese":
				case "Marshallese":
				case "Micronesian":
				case "Nicaraguan":
				case "Paraguayan":
				case "Polish":
				case "Romanian":
				case "Saint Lucian":
				case "Salvadoran":
				case "Sammarinese":
				case "São Toméan":
				case "Slovak":
				case "Vatican":
				case "Venezuelan":
				case "Vietnamese":
					slave.foreskin = 0;
					break;
				default:
					/* Some overlooked country, or possibly stateless. Use global average. */
					slave.foreskin = 38;
			}
			/* Second pass for minorities in other countries. */
			if (slave.race == "middle eastern" && slave.foreskin < 76) {
				slave.foreskin = 76;
			}
			if (slave.race == "semitic" && slave.foreskin < 90) {
				slave.foreskin = 90;
			}
			/* Chance activeSlave.foreskin back to the normal meaning. */
			if (jsRandom(0,99) < slave.foreskin) {
				slave.foreskin = 0;
			} else {
				slave.foreskin = slave.dick + jsRandom(0,1);
			}
		}
	};

	function generateXXPreferences() {
		randomizeAttraction(slave);
		slave.fetishStrength = jsRandom(0,90);
		slave.fetish = jsEither(["none", "none", "none", "none", "none", "none", "none", "none", "none", "none", "none", "none", "none", "submissive", "submissive", "cumslut", "humiliation", "humiliation", "buttslut", "boobs", "pregnancy", "dom", "sadist", "masochist"]);
		slave.behavioralFlaw = jsEither(["none", "none", "none", "arrogant", "bitchy", "odd", "hates men", "hates women", "hates women", "anorexic", "gluttonous", "devout", "liberated"]);

		if (slave.behavioralFlaw == "devout") {
			slave.sexualFlaw = jsEither(["none", "repressed", "shamefast", "apathetic", "crude", "judgemental"]);
		} else {
			slave.sexualFlaw = jsEither(["none", "none", "none", "none", "hates oral", "hates anal", "hates penetration", "repressed", "idealistic", "shamefast", "apathetic", "crude", "judgemental"]);
		}
		if (slave.behavioralFlaw == "none" && jsRandom(1,10) == 1) {
			slave.behavioralQuirk = jsEither(["confident", "cutting", "funny", "adores women", "adores men", "fitness", "insecure", "sinful", "advocate"]);
		}
		if (slave.sexualFlaw == "none" && jsRandom(1,10) == 1) {
			slave.sexualQuirk = jsEither(["gagfuck queen", "painal queen", "strugglefuck queen", "tease", "romantic", "perverted", "caring", "unflinching", "size queen"]);
		}
	};

	function generateXYPreferences() {
		randomizeAttraction(slave);
		slave.fetishStrength = jsRandom(0,90);
		slave.fetish = jsEither(["none", "none", "none", "none", "none", "none", "none", "none", "none", "none", "none", "none", "none", "submissive", "cumslut", "humiliation", "buttslut", "buttslut", "boobs", "dom", "sadist", "masochist"]);
		slave.behavioralFlaw = jsEither(["none", "none", "none", "arrogant", "bitchy", "odd", "hates men", "hates men", "hates men", "hates women", "anorexic", "gluttonous", "devout", "liberated"]);

		if (slave.behavioralFlaw == "devout") {
			slave.sexualFlaw = jsEither(["none", "repressed", "shamefast", "apathetic", "crude", "judgemental"]);
		} else {
			slave.sexualFlaw = jsEither(["none", "none", "none", "none", "hates oral", "hates anal", "hates anal", "repressed", "idealistic", "shamefast", "apathetic", "crude", "judgemental"]);
		}
		if (slave.behavioralFlaw == "none" && jsRandom(1,10) == 1) {
			slave.behavioralQuirk = jsEither(["confident", "cutting", "funny", "adores women", "adores men", "fitness", "insecure", "sinful", "advocate"]);
		}
		if (slave.sexualFlaw == "none" && jsRandom(1,10) == 1) {
			slave.sexualQuirk = jsEither(["gagfuck queen", "painal queen", "strugglefuck queen", "tease", "romantic", "perverted", "caring", "unflinching", "size queen"]);
		}
	};

	function generateXXButt() {
		if (slave.physicalAge <= 11) {
			slave.butt = jsEither([1, 1, 1, 1, 1, 1, 1]);
		} else if (slave.physicalAge <= 12) {
			slave.butt = jsEither([1, 1, 1, 1, 1, 2, 2]);
		} else if (slave.physicalAge <= 13) {
			slave.butt = jsEither([1, 1, 1, 1, 2, 2, 2]);
		} else if (slave.physicalAge <= 14) {
			slave.butt = jsEither([1, 1, 1, 2, 2, 2, 3]);
		} else if (slave.physicalAge <= 15) {
			slave.butt = jsEither([1, 1, 2, 2, 2, 2, 3]);
		} else {
			switch (slave.race) {
				case "black":
					slave.butt = jsEither([1, 2, 2, 3, 3, 4, 4]);
					break;
				case "indo-aryan":
				case "malay":
				case "pacific islander":
				case "amerindian":
				case "asian":
				case "middle eastern":
				case "semitic":
				case "southern european":
					slave.butt = jsEither([1, 2, 2, 3, 3]);
					break;
				default:
					slave.butt = jsEither([1, 2, 2, 3, 3, 4]);
			}
		}
		if (V.weightAffectsAssets != 0) {
			if (slave.weight < -10 && slave.butt > 1) {
				slave.butt -= 1;
			} else if (slave.weight > 100 && slave.butt < 6) {
				slave.butt += jsRandom(1,2);
			} else if (slave.weight > 10 && slave.butt < 4) {
				slave.butt += 1;
			}
		}
		slave.anus = jsEither([0, 0, 1, 1, 2]);
		slave.analArea = slave.anus + jsEither([0, 0, 0, 1]);
	};

	function generateXYButt() {
		if (slave.physicalAge <= 13) {
			slave.butt = jsEither([1, 1, 1, 2, 2, 3, 3, 4]);
		} else {
			slave.butt = jsEither([1, 1, 2, 3]);
		}
		if (V.weightAffectsAssets != 0) {
			if (slave.weight < -10 && slave.butt > 1) {
				slave.butt -= 1;
			} else if (slave.weight > 100 && slave.butt < 6) {
				slave.butt += jsRandom(1,2);
			} else if (slave.weight > 10 && slave.butt < 4) {
				slave.butt += 1;
			}
		}
		if (slave.attrXY > 0) {
			slave.anus = jsEither([0, 1, 2]);
		} else {
			if (slave.physicalAge <= 13) {
				slave.anus = jsEither([0, 0, 0, 0, 0, 1]);
			} else if (slave.physicalAge <= 15) {
				slave.anus = jsEither([0, 0, 0, 0, 1, 1, 1]);
			} else if (slave.physicalAge <= 17) {
				slave.anus = jsEither([0, 0, 0, 1, 1, 1]);
			} else {
				slave.anus = jsEither([0, 0, 1, 1, 2]);
			}
		}
		slave.analArea = slave.anus + jsEither([0, 0, 0, 1]);
	};

	function generateXXBoobs() {
		if (slave.physicalAge <= 10) {
			slave.boobs = 100;
		} else if (slave.physicalAge == 11) {
			slave.boobs = jsEither([100, 100, 150, 150, 150, 300]);
		} else if (slave.physicalAge == 12) {
			slave.boobs = jsEither([100, 100, 150, 150, 150, 200, 200, 300]);
		} else if (slave.physicalAge == 13) {
			slave.boobs = jsEither([100, 150, 200, 200, 300, 300, 300, 400]);
		} else if (slave.physicalAge == 14) {
			slave.boobs = jsEither([100, 150, 200, 300, 300, 300, 350, 400, 400]);
		} else if (slave.physicalAge == 15) {
			slave.boobs = jsEither([150, 200, 300, 300, 300, 350, 350, 350, 400, 400, 450, 450]);
		} else {
			switch (slave.race) {
				case "black":
					slave.boobs = BoobGenerator.rollBreast(150);
					break;
				case "white":
					slave.boobs = BoobGenerator.rollBreast(50);
					break;
				case "asian":
					slave.boobs = BoobGenerator.rollBreast(-100);
					break;
				default:
					slave.boobs = BoobGenerator.rollBreast(0);
			}
		}
	};

	function generateXYBoobs() {
		slave.boobs = jsEither([100, 200, 200, 300, 300, 400, 500]);
	};

	function generateXXFace() {
		slave.face = jsRandom(-60,60);
		if (jsRandom(0,2) == 0) {
			slave.face = jsRandom(-10,10);
		}
		if (slave.physicalAge > 40) {
			slave.face -= jsRandom(0,20);
		} else if (slave.physicalAge > 35) {
			slave.face -= jsRandom(0,10);
		} else if (slave.physicalAge <= 20) {
			slave.face += jsRandom(0,20);
		} else if (slave.physicalAge <= 25) {
			slave.face += jsRandom(0,10);
		}
		if (slave.physicalAge > 10) {
			slave.faceShape = jsEither(["androgynous", "cute", "sensual", "exotic", "normal", "normal"]);
		} else {
			slave.faceShape = jsEither(["androgynous", "androgynous", "cute", "cute", "sensual", "exotic", "normal", "normal"]);
		}
		switch (slave.faceShape) {
			case "sensual":
			case "cute":
				slave.face += jsRandom(0,20);
				break;
			case "exotic":
			case "androgynous":
				slave.face += jsRandom(-10,10);
				break;
			case "masculine":
				slave.face += jsRandom(-10,0);
		}
	};

	function generateXYFace() {
		slave.face = jsRandom(-70,20);
		if (jsRandom(0,2) == 0) {
			slave.face = jsRandom(-40,-10);
		}
		if (slave.physicalAge > 40) {
			slave.face -= jsRandom(0,20);
		} else if (slave.physicalAge > 35) {
			slave.face -= jsRandom(0,10);
		} else if (slave.physicalAge <= 20) {
			slave.face += jsRandom(0,20);
		} else if (slave.physicalAge <= 25) {
			slave.face += jsRandom(0,10);
		}
		if (slave.physicalAge >= 17) {
			slave.faceShape = jsEither(["masculine", "masculine", "masculine", "androgynous"]);
		} else if (slave.physicalAge >= 15) {
			slave.faceShape = jsEither(["masculine", "masculine", "masculine", "masculine", "masculine", "masculine", "masculine", "masculine", "androgynous", "sensual", "exotic", "normal"]);
		} else if (slave.physicalAge >= 13) {
			slave.faceShape = jsEither(["masculine", "masculine", "masculine", "androgynous", "cute", "sensual", "exotic", "normal"]);
		} else if (slave.physicalAge >= 11) {
			slave.faceShape = jsEither(["masculine", "androgynous", "cute", "sensual", "exotic", "normal", "normal"]);
		} else {
			slave.faceShape = jsEither(["androgynous", "androgynous", "cute", "cute", "sensual", "exotic", "normal", "normal"]);
		}
		switch (slave.faceShape) {
			case "sensual":
			case "cute":
				slave.face += jsRandom(0,20);
				break;
			case "exotic":
			case "androgynous":
				slave.face += jsRandom(-10,10);
				break;
			case "masculine":
				slave.face += jsRandom(-10,0);
		}
	};

	function generateXXPregAdaptation() {
		if (slave.physicalAge <= 6) {
			slave.pregAdaptation = 5;
		} else if (slave.physicalAge <= 11) {
			slave.pregAdaptation = slave.physicalAge - 1;
		} else if (slave.physicalAge <= 14) {
			slave.pregAdaptation = 4*(slave.physicalAge - 12) + 14;
		} else if (slave.physicalAge <= 15) {
			slave.pregAdaptation = 28;
		} else if (slave.physicalAge <= 16) {
			slave.pregAdaptation = 34;
		} else if (slave.physicalAge <= 17) {
			slave.pregAdaptation = 42;
		} else {
			slave.pregAdaptation = 50;
		}
	};

	function generateXYPregAdaptation() {
		if (slave.physicalAge <= 6) {
			slave.pregAdaptation = 5;
		} else if (slave.physicalAge <= 11) {
			slave.pregAdaptation = slave.physicalAge - 1;
		} else if (slave.physicalAge <= 15) {
			slave.pregAdaptation = 2*(slave.physicalAge - 12) + 12;
		} else {
			slave.pregAdaptation = 20;
		}
	};

	function generateXXVoice() {
		if (slave.physicalAge <= 13) {
			slave.voice = jsEither([2, 2, 2, 3, 3, 3, 3, 3, 3]);
		} else if (slave.physicalAge <= 16) {
			slave.voice = jsEither([2, 2, 2, 2, 2, 3, 3, 3, 3]);
		} else {
			slave.voice = jsEither([1, 2, 2, 2, 2, 2, 2, 3, 3, 3]);
		}
	};

	function generateXYVoice() {
		if (slave.physicalAge <= 11) {
			slave.voice = jsEither([2, 2, 2, 3, 3, 3, 3, 3, 3]);
		} else if (slave.physicalAge <= 13) {
			slave.voice = jsEither([1, 1, 2, 2, 2, 2, 2, 3, 3]);
		} else if (slave.physicalAge <= 16) {
			slave.voice = jsEither([1, 1, 1, 2, 2, 2, 2, 2, 3]);
		} else {
			if (slave.balls > 2) {
				slave.voice = 1;
			} else if (slave.balls > 0) {
				slave.voice = jsEither([1, 1, 2]);
			} else {
				slave.voice = jsEither([1, 2, 2]);
			}
		}
	};

	function generateXXTeeth() {
		var femaleCrookedTeethGen = slave.intelligence+slave.intelligenceImplant;
		if ("American" == slave.nationality) {
			femaleCrookedTeethGen += 20;
		} else if (["Andorran", "Antiguan", "Argentinian", "Aruban", "Australian", "Austrian", "Bahamian", "Bahraini", "Barbadian", "Belarusian", "Belgian", "Bermudian", "Brazilian", "British", "Bruneian", "Bulgarian", "Canadian", "Catalan", "Chilean", "a Cook Islander", "Croatian", "Czech", "Cypriot", "Danish", "Dutch", "Emirati", "Estonian", "Finnish", "French", "German", "Greek", "Greenlandic", "Guamanian", "Hungarian", "Icelandic", "Irish", "Israeli", "Italian", "Japanese", "Kazakh", "Korean", "Kuwaiti", "Latvian", "a Liechtensteiner", "Lithuanian", "Luxembourgian", "Malaysian", "Maltese", "Mauritian", "Monégasque", "Montenegrin", "New Caledonian", "a New Zealander", "Niuean", "Norwegian", "Omani", "Palauan", "Panamanian", "Polish", "Portuguese", "Puerto Rican", "Qatari", "Romanian", "Russian", "Sammarinese", "Saudi", "Seychellois", "Singaporean", "Slovak", "Slovene", "Spanish", "Swedish", "Swiss", "Taiwanese", "Trinidadian", "Uruguayan", "Vatican"].includes(slave.nationality)) {
			/* do nothing */
		} else {
			femaleCrookedTeethGen -= 20;
		}

		if (jsRandom(0, femaleCrookedTeethGen) <= 15 && slave.physicalAge >= 12) {
			slave.teeth = jsEither(["crooked", "crooked", "crooked", "crooked", "crooked", "crooked", "crooked", "gapped"]);
		}

		if (slave.physicalAge < 6) {
			slave.teeth = "baby";
		} else if (slave.physicalAge < 12) {
			slave.teeth = "mixed";
		}
	};

	function generateXYTeeth() {
		var maleCrookedTeethGen = slave.intelligence+slave.intelligenceImplant;
		if ("American" == slave.nationality) {
			maleCrookedTeethGen += 22;
		} else if (["Andorran", "Antiguan", "Argentinian", "Aruban", "Australian", "Austrian", "Bahamian", "Bahraini", "Barbadian", "Belarusian", "Belgian", "Bermudian", "Brazilian", "British", "Bruneian", "Bulgarian", "Canadian", "Catalan", "Chilean", "a Cook Islander", "Croatian", "Czech", "Cypriot", "Danish", "Dutch", "Emirati", "Estonian", "Finnish", "French", "German", "Greek", "Greenlandic", "Guamanian", "Hungarian", "Icelandic", "Irish", "Israeli", "Italian", "Japanese", "Kazakh", "Korean", "Kuwaiti", "Latvian", "a Liechtensteiner", "Lithuanian", "Luxembourgian", "Malaysian", "Maltese", "Mauritian", "Monégasque", "Montenegrin", "New Caledonian", "a New Zealander", "Niuean", "Norwegian", "Omani", "Palauan", "Panamanian", "Polish", "Portuguese", "Puerto Rican", "Qatari", "Romanian", "Russian", "Sammarinese", "Saudi", "Seychellois", "Singaporean", "Slovak", "Slovene", "Spanish", "Swedish", "Swiss", "Taiwanese", "Trinidadian", "Uruguayan", "Vatican"].includes(slave.nationality)) {
			/* do nothing */
		} else {
			maleCrookedTeethGen -= 20;
		}

		if (jsRandom(0, maleCrookedTeethGen) <= 15 && slave.physicalAge >= 12) {
			slave.teeth = jsEither(["crooked", "crooked", "crooked", "crooked", "crooked", "crooked", "crooked", "gapped"]);
		}

		if (slave.physicalAge < 6) {
			slave.teeth = "baby";
		} else if (slave.physicalAge < 12) {
			slave.teeth = "mixed";
		}
	};

	function generateXXMods() {
		if (passage() != "Starting Girls") {
			slave.earPiercing = jsEither([0,1]);
			slave.nosePiercing = jsEither([0,0,0,1]);
			slave.eyebrowPiercing = jsEither([0,0,0,0,0,1]);
			slave.clitPiercing = jsEither([0,0,0,0,0,1]);
			slave.lipsPiercing = jsEither([0,0,0,0,0,1]);
			slave.navelPiercing = jsEither([0,0,0,1]);
			slave.nipplesPiercing = jsEither([0,0,0,0,1]);
		}
		if (slave.anus != 0 && Math.random() < 0.25) {
			slave.anusTat = "bleached";
		}
	};

	function generateXYMods() {
		if (passage() != "Starting Girls") {
			slave.earPiercing = jsEither([0,0,0,1]);
			slave.nosePiercing = jsEither([0,0,0,0,1]);
			slave.eyebrowPiercing = jsEither([0,0,0,0,0,1]);
			slave.clitPiercing = jsEither([0,0,0,0,0,1]);
			slave.lipsPiercing = jsEither([0,0,0,0,0,1]);
			slave.navelPiercing = jsEither([0,0,0,0,1]);
			slave.nipplesPiercing = jsEither([0,0,0,0,1]);
		}
		if (slave.anus != 0 && Math.random() < 0.25) {
			slave.anusTat = "bleached";
		}
	};

	function generateXXBodyHair() {
		slave.pubicHColor = slave.hColor;
		slave.underArmHColor = slave.hColor;
		slave.pubicHStyle = jsEither(["hairless", "bald", "bald", "waxed", "waxed", "waxed", "waxed", "waxed", "waxed", "in a strip", "in a strip", "in a strip", "in a strip", "in a strip", "neat", "neat", "neat", "neat", "neat", "bushy in the front and neat in the rear", "bushy in the front and neat in the rear", "bushy in the front and neat in the rear", "bushy in the front and neat in the rear", "bushy", "bushy", "bushy", "bushy", "bushy", "very bushy", "very bushy"]);
		slave.underArmHStyle = jsEither(["hairless", "bald", "bald", "waxed", "waxed", "waxed", "waxed", "shaved", "shaved", "shaved", "shaved", "shaved", "neat", "neat", "neat", "neat", "neat", "bushy", "bushy", "bushy"]);
		if ((slave.pubicHStyle == "hairless" || slave.underArmHStyle == "hairless") && Math.random() > 0.4) {
			slave.pubicHStyle = "hairless";
			slave.underArmHStyle = "hairless";
		}
		if (slave.hColor == "blonde" && Math.random() > 0.85) {
			slave.eyebrowHColor = jsEither(["brown", "brown", "brown", "brown", "black"]);
			slave.override_Brow_H_Color = 1;
		} else {
			slave.eyebrowHColor = slave.hColor;
		}
		slave.eyebrowHStyle = jsEither(["bald", "shaved", "shaved", "straight", "straight", "straight", "straight", "straight", "straight", "rounded", "rounded", "rounded", "rounded", "rounded", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "slanted inwards", "slanted inwards", "slanted outwards", "slanted outwards", "high-arched", "high-arched", "high-arched", "elongated", "elongated", "elongated", "shortened", "shortened", "shortened", "curved", "curved", "curved", "curved", "curved", "curved", "curved"]);
		slave.eyebrowFullness = jsEither(["pencil-thin", "pencil-thin", "thin", "thin", "thin", "threaded", "threaded", "threaded", "threaded", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "tapered", "tapered", "tapered", "tapered", "thick", "thick", "thick", "bushy", "bushy"]);
	};

	function generateXYBodyHair() {
		slave.pubicHColor = slave.hColor;
		slave.underArmHColor = slave.hColor;
		slave.pubicHStyle = jsEither(["hairless", "bald", "bald", "waxed", "waxed", "waxed", "waxed", "waxed", "waxed", "in a strip", "in a strip", "in a strip", "neat", "neat", "neat", "neat", "neat", "neat", "bushy in the front and neat in the rear", "bushy in the front and neat in the rear", "bushy in the front and neat in the rear", "bushy", "bushy", "bushy", "bushy", "bushy", "bushy", "very bushy", "very bushy"]);
		slave.underArmHStyle = jsEither(["hairless", "bald", "bald", "waxed", "waxed", "waxed", "waxed", "shaved", "shaved", "shaved", "shaved", "shaved", "neat", "neat", "neat", "neat", "neat", "neat", "neat", "bushy", "bushy", "bushy", "bushy", "bushy"]);
		if ((slave.pubicHStyle == "hairless" || slave.underArmHStyle == "hairless") && Math.random() > 0.4) {
			slave.pubicHStyle = "hairless";
			slave.underArmHStyle = "hairless";
		}
		if (slave.hColor == "blonde" && Math.random() > 0.85) {
			slave.eyebrowHColor = jsEither(["brown", "brown", "brown", "brown", "black"]);
			slave.override_Brow_H_Color = 1;
		} else {
			slave.eyebrowHColor = slave.hColor;
		}
		slave.eyebrowHStyle = jsEither(["bald", "shaved", "shaved", "straight", "straight", "straight", "straight", "straight", "straight", "rounded", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "slanted inwards", "slanted outwards", "high-arched", "elongated", "shortened", "curved", "curved", "curved", "curved", "curved"]);
		slave.eyebrowFullness = jsEither(["pencil-thin", "thin", "thin", "threaded", "threaded", "threaded", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "natural", "tapered", "tapered", "tapered", "thick", "thick", "bushy"]);
	};

	function generateXXPuberty() {
		if (slave.physicalAge >= slave.pubertyAgeXX) {
			slave.pubertyXX = 1;
		} else {
			slave.pubertyXX = 0;
		}
	}

	function generateXYPuberty() {
		if (slave.balls > 0) {
			if (slave.physicalAge >= slave.pubertyAgeXY) {
				slave.pubertyXY = 1;
			} else {
				slave.pubertyXY = 0;
			}
		} else {
			slave.pubertyXY = 0;
		}
	};

	function generateAge() {
		if (V.activeSlaveOneTimeMaxAge > 998) {
			V.activeSlaveOneTimeMaxAge = (V.pedo_mode === 1) ? 18 : 42;
		} else if (V.pedo_mode === 1 && V.one_time_age_overrides_pedo_mode === 0 && V.activeSlaveOneTimeMaxAge > 18) {
			V.activeSlaveOneTimeMaxAge = 18;
		}
		if (V.retirementAge < V.activeSlaveOneTimeMaxAge) {
			V.activeSlaveOneTimeMaxAge = (V.retirementAge - 1);
		}
		if (V.activeSlaveOneTimeMinAge < V.minimumSlaveAge) {
			V.activeSlaveOneTimeMinAge = V.minimumSlaveAge;
		} else if (V.pedo_mode === 1 && V.one_time_age_overrides_pedo_mode === 0) {
			V.activeSlaveOneTimeMinAge = V.minimumSlaveAge;
		}
		if (V.activeSlaveOneTimeMaxAge < V.activeSlaveOneTimeMinAge) {
			V.activeSlaveOneTimeMaxAge = V.activeSlaveOneTimeMinAge;
		}
		if (V.activeSlaveOneTimeMaxAge >= 30 && V.arcologies[0].FSMaturityPreferentialist !== "unset" && V.ageAdjustOverride !== 1) {
			V.activeSlaveOneTimeMaxAge += 10;
		}
		slave.actualAge = jsRandom(V.activeSlaveOneTimeMinAge, V.activeSlaveOneTimeMaxAge);
		const secondAgeRoll = jsRandom(V.activeSlaveOneTimeMinAge, V.activeSlaveOneTimeMaxAge);
		if (V.arcologies[0].FSYouthPreferentialist !== "unset" && V.arcologies[0].FSYouthPreferentialist >= jsRandom(1, 100)) {
			slave.actualAge = Math.min(slave.actualAge, secondAgeRoll);
		} else if (V.arcologies[0].FSMaturityPreferentialist !== "unset" && V.arcologies[0].FSMaturityPreferentialist >= jsRandom(1, 100)) {
			slave.actualAge = Math.max(slave.actualAge, secondAgeRoll);
		}
		if (slave.actualAge >= V.retirementAge) {
			slave.actualAge = (V.retirementAge - 2);
		}
		V.activeSlaveOneTimeMinAge = 0;
		V.activeSlaveOneTimeMaxAge = 999;
		V.one_time_age_overrides_pedo_mode = 0;
		V.ageAdjustOverride = 0;
		slave.visualAge = slave.actualAge;
		slave.physicalAge = slave.actualAge;
		slave.ovaryAge = slave.actualAge;
		slave.age = slave.actualAge; /*compatibility*/
		slave.pubertyAgeXX = V.fertilityAge;
		slave.pubertyAgeXY = V.potencyAge;
	};

	function generateIntelligence() {
		const gaussian = gaussianPair();
		slave.intelligence = Intelligence.random();
		if (V.AgePenalty == 1 && slave.actualAge <= 24) {
			if (gaussian[0] < gaussian[1] + slave.intelligence/29 + (slave.actualAge - 24)/8 - 0.35) {
				slave.intelligenceImplant = 15;
				if (slave.intelligenceImplant > 0 && jsRandom(15,150) < slave.intelligence) {
					slave.intelligenceImplant = 30;
				}
			}
		} else {
			if (gaussian[0] < gaussian[1] + slave.intelligence/29 - 0.35) { /* 40.23% chance if intelligence is 0, 99.26% chance if intelligence is 100 */
				slave.intelligenceImplant = 15;
				if (slave.intelligenceImplant > 0 && jsRandom(15,150) < slave.intelligence) {
					slave.intelligenceImplant = 30;
				}
			}
		}
	};

	function generateCareer() {
		if (V.AgePenalty == 1) {
			if (slave.actualAge < 16) {
				slave.career = setup.veryYoungCareers.random();
			} else if (slave.actualAge <= 24) {
				slave.career = setup.youngCareers.random();
			} else if (slave.intelligenceImplant >= 15) {
				slave.career = setup.educatedCareers.random();
			} else {
				slave.career = setup.uneducatedCareers.random();
			}
		} else {
			if (slave.actualAge < 16) {
				slave.career = setup.veryYoungCareers.random();
			} else if (slave.intelligenceImplant >= 15) {
				slave.career = setup.educatedCareers.random();
			} else if (slave.actualAge <= 24) {
				slave.career = setup.youngCareers.random();
			} else {
				slave.career = setup.uneducatedCareers.random();
			}
		}
	};

	function generateNationality() {
		if (V.fixedRace == 0) {
			if (V.fixedNationality == 0) {
				slave.nationality = hashChoice(V.nationalities);
			} else {
				slave.nationality = V.fixedNationality;
				V.fixedNationality = 0;
			}
			nationalityToRace(slave);

			if (passage() == "Corporate Market" && (V.captureUpgradeRace != "unselected") && (V.captureUpgradeRace != "none")) {
				if (V.captureUpgradeRace == "mixed race") {
					slave.race = "mixed race";
				} else {
					const capUpgradeCheck = setup[V.captureUpgradeRace.toLowerCase().replace(/[ -]/g, '')+'Nationalities'];
					const keys = Object.keys(capUpgradeCheck);
					var capUpgradeNationalities = {};
					for (var i = 0; i < keys.length; i++) {
						if (keys[i] in V.nationalities) {
							capUpgradeNationalities[keys[i]] = capUpgradeCheck[keys[i]];
						}
					}
					if (Object.keys(capUpgradeNationalities).length > 0) {
						slave.nationality = hashChoice(capUpgradeNationalities);
					} else {
						slave.nationality = hashChoice(capUpgradeCheck);
					}
					slave.race = V.captureUpgradeRace;
				}
			}

		} else {
			switch (V.fixedRace) {
				case "white":
					slave.nationality = hashChoice(setup.whiteNationalities);
					break;
				case "asian":
					slave.nationality = hashChoice(setup.asianNationalities);
					break;
				case "latina":
					slave.nationality = hashChoice(setup.latinaNationalities);
					break;
				case "black":
					slave.nationality = hashChoice(setup.blackNationalities);
					break;
				case "pacific islander":
					slave.nationality = hashChoice(setup.pacificislanderNationalities);
					break;
				case "southern european":
					slave.nationality = hashChoice(setup.southerneuropeanNationalities);
					break;
				case "amerindian":
					slave.nationality = hashChoice(setup.amerindianNationalities);
					break;
				case "semitic":
					slave.nationality = hashChoice(setup.semiticNationalities);
					break;
				case "middle eastern":
					slave.nationality = hashChoice(setup.middleeasternNationalities);
					break;
				case "indo-aryan":
					slave.nationality = hashChoice(setup.indoaryanNationalities);
					break;
				case "malay":
					slave.nationality = hashChoice(setup.malayNationalities);
					break;
				default:
					slave.nationality = hashChoice(V.nationalities);
			}
			slave.race = V.fixedRace;
			V.fixedRace = 0;
		}
	};

	function generateAccent() {
		nationalityToAccent(slave);
		if ((slave.intelligenceImplant >= 15 || slave.intelligence > 95) && slave.accent >= 3 && slave.intelligence > jsRandom(0,100)) {
			slave.accent -= 1;
		}
	};

	function generateRacialTraits() {
		switch (slave.race) {
			case "black":
				slave.lips = jsRandom(5,30);
				slave.skin = jsEither(["black", "dark brown", "brown"]);
				slave.hColor = jsEither(["black", "black", "black", "brown"]);
				slave.hStyle = jsEither(["neat", "crinkled"]);
				break;
			case "white":
				slave.lips = jsRandom(5,25);
				if (slave.nationality == "German") {
					slave.skin = jsEither(["pale", "light", "fair"]);
					slave.eyeColor = jsEither(["blue", "blue", "blue", "brown", "green"]);
					slave.hColor = jsEither(["black", "blonde", "blonde", "blonde", "red", "brown"]);
				} else if (slave.nationality == "Icelandic") {
					slave.skin = jsEither(["pale", "pale", "light", "fair"]);
					slave.eyeColor = jsEither(["blue", "blue", "blue", "brown", "green"]);
					slave.hColor = jsEither(["black", "blonde", "blonde", "blonde", "red", "brown"]);
				} else if (slave.nationality == "Irish") {
					slave.skin = jsEither(["pale", "pale", "light", "fair"]);
					slave.eyeColor = jsEither(["blue", "brown", "green", "green", "green"]);
					slave.hColor = jsEither(["black", "blonde", "red", "red", "red", "brown"]);
				} else if (slave.nationality == "Scottish") {
					slave.skin = jsEither(["pale", "fair", "light", "fair"]);
					slave.eyeColor = jsEither(["blue", "brown", "brown", "green", "green", "green"]);
					slave.hColor = jsEither(["black", "black", "blonde", "red", "red", "red", "brown"]);
				} else {
					slave.skin = jsEither(["pale", "light", "fair"]);
					slave.eyeColor = jsEither(["blue", "brown", "green"]);
					slave.hColor = jsEither(["black", "blonde", "red", "brown"]);
				}
				slave.hStyle = "neat";
				break;
			case "latina":
				slave.lips = jsRandom(5,25);
				slave.skin = jsEither(["light olive", "brown", "dark brown", "tanned", "dark olive"]);
				slave.hColor = jsEither(["black", "brown"]);
				slave.hStyle = "neat";
				break;
			case "indo-aryan":
			case "malay":
			case "pacific islander":
			case "amerindian":
				slave.lips = jsRandom(5,25);
				slave.skin = jsEither(["dark", "light"]);
				slave.hColor = "black";
				slave.hStyle = "neat";
				break;
			case "asian":
				slave.lips = jsRandom(5,25);
				slave.skin = jsEither(["light olive", "dark olive", "light"]);
				slave.hColor = "black";
				slave.hStyle = "neat";
				break;
			case "middle eastern":
			case "semitic":
			case "southern european":
				slave.lips = jsRandom(5,25);
				slave.skin = jsEither(["fair", "light olive", "tanned", "light"]);
				slave.hColor = "black";
				slave.hStyle = "neat";
				break;
			default:
				slave.lips = jsRandom(5,25);
				slave.skin = jsEither(["pale", "dark", "light"]);
				slave.hColor = jsEither(["black", "black", "black", "black", "brown", "brown", "blonde", "red"]);
				slave.hStyle = "neat";
		}
		if (slave.skin == "pale" || slave.skin == "fair") {
			if (jsRandom(1,4) == 1) {
				slave.markings = jsEither(["freckles", "freckles", "freckles", "heavily freckled", "beauty mark", "beauty mark", "birthmark", "birthmark"]);
			}
		} else if (jsRandom(1,8) == 1) {
			slave.markings = jsEither(["beauty mark", "birthmark"]);
		}
	};

	function generateBoobTweaks() {
		if (V.weightAffectsAssets != 0) {
			if (slave.weight < -10 && slave.boobs > 200) {
				slave.boobs -= 100;
			} else if (slave.weight > 190 && slave.boobs < 3000) {
				slave.boobs += (jsRandom(3,8)*100);
			} else if (slave.weight > 160 && slave.boobs < 1500) {
				slave.boobs += (jsRandom(2,6)*100);
			} else if (slave.weight > 130 && slave.boobs < 1500) {
				slave.boobs += (jsRandom(1,4)*100);
			} else if (slave.weight > 95 && slave.boobs < 1200) {
				slave.boobs += (jsRandom(1,3)*100);
			} else if (slave.weight > 30 && slave.boobs < 1000) {
				slave.boobs += 100;
			}
		}

		var BoobShapeGen = [];
		if (slave.boobs > 250 && slave.boobs < 800) {
			BoobShapeGen.push("perky");
			BoobShapeGen.push("downward-facing");
		}
		if (slave.boobs > 400 && slave.boobs < 1200) {
			BoobShapeGen.push("torpedo-shaped");
			BoobShapeGen.push("wide-set");
		}
		if (slave.boobs > 800 && slave.physicalAge > jsRandom(10,50)) {
			BoobShapeGen.push("saggy");
		}
		if (BoobShapeGen.length == 1) {
			if (Math.random() < 0.5) {
				slave.boobShape = jsEither(BoobShapeGen);
			}
		} else if (BoobShapeGen.length > 1) {
			if (jsRandom(1,3) != 1) {
				slave.boobShape = jsEither(BoobShapeGen);
			}
		}

		if (slave.boobs < 250) {
			slave.nipples = jsEither(["tiny", "tiny", "tiny", "tiny", "cute", "cute", "puffy", "partially inverted"]);
		} else if (slave.boobs < 500) {
			slave.nipples = jsEither(["tiny", "cute", "cute", "cute", "puffy", "partially inverted"]);
		} else if (slave.boobs < 1000) {
			slave.nipples = jsEither(["tiny", "cute", "cute", "cute", "puffy", "puffy", "partially inverted", "inverted"]);
		} else {
			slave.nipples = jsEither(["cute", "puffy", "partially inverted", "inverted", "huge"]);
		}
	};

	function generateSkills() {
		slave.vaginalSkill = (slave.vagina == 0 ? 0 : jsRandom(0,15));
		slave.analSkill = (slave.anus == 0 ? 0 : jsRandom(0,15));
		slave.oralSkill = jsRandom(0,15);
		slave.entertainSkill = jsRandom(0,15);
		slave.whoreSkill = jsRandom(0,15);
	};

	function generateDisabilities() {
		if (slave.physicalAge >= jsRandom(0,100)) {
			slave.eyes = -1;
		}
		if (slave.physicalAge >= jsRandom(30,100)) {
			slave.hears = -1;
		}
		if (V.seeExtreme == 1) {
			let disList = [];
			disList.push("hearNot");
			disList.push("seeNot");
			disList.push("speakNot");
			let disableCount = 0;
			if (V.oneTimeDisableDisability === 0) {
				while (disList.length > 0) {
					let rolled = jsEither(disList);
					switch (rolled) {
					case "hearNot":
						if ((jsRandom(1,100)-(disableCount*2)) > 90) {
							slave.hears = -2;
						}
						disList.delete("hearNot");
						disableCount++;
						break;
					case "seeNot":
						if ((jsRandom(1,100)-(disableCount*2)) > 90) {
							slave.eyes = -2;
						}
						disList.delete("seeNot");
						disableCount++;
						break;
					case "speakNot":
						if ((jsRandom(1,100)-(disableCount*2)) > 90) {
							slave.voice = 0;
						}
						disList.delete("speakNot");
						disableCount++;
						break;
					}
				}
			}
			V.oneTimeDisableDisability = 0;
		}
	};

	return GenerateNewSlave;
})();


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