:: StoryJS [script]

/*config.history.tracking = false;*/
window.variableAsNumber = function(x, defaultValue, minValue, maxValue) {
	x = Number(x)
	if (x != x) {//NaN
		return defaultValue || 0;//In case the default value was not supplied.
	}
	if (x < minValue) {//Works even if minValue is undefined.
		return minValue;
	}
	if (x > maxValue) {//Works even if maxValue is undefined.
		return maxValue;
	}
	return x;
};
window.isSexuallyPure = function(slave) {
	if (!slave) {
		return null;
	}
	if (slave.vagina < 1 && slave.anus < 1 && !slave.analCount && !slave.vaginalCount && !slave.oralCount && !slave.mammaryCount && !slave.penetrativeCount) {
		return true;
	} else {
		return false;
	}
};
if (typeof interpolate == "undefined") {
	var interpolate = function(x0,y0,x1,y1,x) {
		if(x <= x0) {
			return y0;
		} else if(x >= x1) {
			return y1;
		} else {
			return (x - x0) * ((y1 - y0) / (x1 - x0)) + y0;
		}
	};
	window.interpolate = interpolate;
}

window.isFullyPotent = function(slave) {
	if (!slave) {
		return null;
	} else if (slave.dick > 0 && slave.balls > 0 && slave.ballType != 'sterile' && slave.hormoneBalance < 100 && slave.drugs !== 'hormone blockers') {
		return true;
	} else {
		return false;
	}
};

/* mousetrap v1.5.3 craig.is/killing/mice */
(function(C,r,g){function t(a,b,h){a.addEventListener?a.addEventListener(b,h,!1):a.attachEvent("on"+b,h)}function x(a){if("keypress"==a.type){var b=String.fromCharCode(a.which);a.shiftKey||(b=b.toLowerCase());return b}return l[a.which]?l[a.which]:p[a.which]?p[a.which]:String.fromCharCode(a.which).toLowerCase()}function D(a){var b=[];a.shiftKey&&b.push("shift");a.altKey&&b.push("alt");a.ctrlKey&&b.push("ctrl");a.metaKey&&b.push("meta");return b}function u(a){return"shift"==a||"ctrl"==a||"alt"==a||
"meta"==a}function y(a,b){var h,c,e,g=[];h=a;"+"===h?h=["+"]:(h=h.replace(/\+{2}/g,"+plus"),h=h.split("+"));for(e=0;e<h.length;++e)c=h[e],z[c]&&(c=z[c]),b&&"keypress"!=b&&A[c]&&(c=A[c],g.push("shift")),u(c)&&g.push(c);h=c;e=b;if(!e){if(!k){k={};for(var m in l)95<m&&112>m||l.hasOwnProperty(m)&&(k[l[m]]=m)}e=k[h]?"keydown":"keypress"}"keypress"==e&&g.length&&(e="keydown");return{key:c,modifiers:g,action:e}}function B(a,b){return null===a||a===r?!1:a===b?!0:B(a.parentNode,b)}function c(a){function b(a){a=
a||{};var b=!1,n;for(n in q)a[n]?b=!0:q[n]=0;b||(v=!1)}function h(a,b,n,f,c,h){var g,e,l=[],m=n.type;if(!d._callbacks[a])return[];"keyup"==m&&u(a)&&(b=[a]);for(g=0;g<d._callbacks[a].length;++g)if(e=d._callbacks[a][g],(f||!e.seq||q[e.seq]==e.level)&&m==e.action){var k;(k="keypress"==m&&!n.metaKey&&!n.ctrlKey)||(k=e.modifiers,k=b.sort().join(",")===k.sort().join(","));k&&(k=f&&e.seq==f&&e.level==h,(!f&&e.combo==c||k)&&d._callbacks[a].splice(g,1),l.push(e))}return l}function g(a,b,n,f){d.stopCallback(b,
b.target||b.srcElement,n,f)||!1!==a(b,n)||(b.preventDefault?b.preventDefault():b.returnValue=!1,b.stopPropagation?b.stopPropagation():b.cancelBubble=!0)}function e(a){"number"!==typeof a.which&&(a.which=a.keyCode);var b=x(a);b&&("keyup"==a.type&&w===b?w=!1:d.handleKey(b,D(a),a))}function l(a,c,n,f){function e(c){return function(){v=c;++q[a];clearTimeout(k);k=setTimeout(b,1E3)}}function h(c){g(n,c,a);"keyup"!==f&&(w=x(c));setTimeout(b,10)}for(var d=q[a]=0;d<c.length;++d){var p=d+1===c.length?h:e(f||
y(c[d+1]).action);m(c[d],p,f,a,d)}}function m(a,b,c,f,e){d._directMap[a+":"+c]=b;a=a.replace(/\s+/g," ");var g=a.split(" ");1<g.length?l(a,g,b,c):(c=y(a,c),d._callbacks[c.key]=d._callbacks[c.key]||[],h(c.key,c.modifiers,{type:c.action},f,a,e),d._callbacks[c.key][f?"unshift":"push"]({callback:b,modifiers:c.modifiers,action:c.action,seq:f,level:e,combo:a}))}var d=this;a=a||r;if(!(d instanceof c))return new c(a);d.target=a;d._callbacks={};d._directMap={};var q={},k,w=!1,p=!1,v=!1;d._handleKey=function(a,
c,e){var f=h(a,c,e),d;c={};var k=0,l=!1;for(d=0;d<f.length;++d)f[d].seq&&(k=Math.max(k,f[d].level));for(d=0;d<f.length;++d)f[d].seq?f[d].level==k&&(l=!0,c[f[d].seq]=1,g(f[d].callback,e,f[d].combo,f[d].seq)):l||g(f[d].callback,e,f[d].combo);f="keypress"==e.type&&p;e.type!=v||u(a)||f||b(c);p=l&&"keydown"==e.type};d._bindMultiple=function(a,b,c){for(var d=0;d<a.length;++d)m(a[d],b,c)};t(a,"keypress",e);t(a,"keydown",e);t(a,"keyup",e)}var l={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",
20:"capslock",27:"esc",32:"space",33:"pageup",34:"pagedown",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"ins",46:"del",91:"meta",93:"meta",224:"meta"},p={106:"*",107:"+",109:"-",110:".",111:"/",186:";",187:"=",188:",",189:"-",190:".",191:"/",192:"`",219:"[",220:"\\",221:"]",222:"'"},A={"~":"`","!":"1","@":"2","#":"3",$:"4","%":"5","^":"6","&":"7","*":"8","(":"9",")":"0",_:"-","+":"=",":":";",'"':"'","<":",",">":".","?":"/","|":"\\"},z={option:"alt",command:"meta","return":"enter",
escape:"esc",plus:"+",mod:/Mac|iPod|iPhone|iPad/.test(navigator.platform)?"meta":"ctrl"},k;for(g=1;20>g;++g)l[111+g]="f"+g;for(g=0;9>=g;++g)l[g+96]=g;c.prototype.bind=function(a,b,c){a=a instanceof Array?a:[a];this._bindMultiple.call(this,a,b,c);return this};c.prototype.unbind=function(a,b){return this.bind.call(this,a,function(){},b)};c.prototype.trigger=function(a,b){if(this._directMap[a+":"+b])this._directMap[a+":"+b]({},a);return this};c.prototype.reset=function(){this._callbacks={};this._directMap=
{};return this};c.prototype.stopCallback=function(a,b){return-1<(" "+b.className+" ").indexOf(" mousetrap ")||B(b,this.target)?!1:"INPUT"==b.tagName||"SELECT"==b.tagName||"TEXTAREA"==b.tagName||b.isContentEditable};c.prototype.handleKey=function(){return this._handleKey.apply(this,arguments)};c.init=function(){var a=c(r),b;for(b in a)"_"!==b.charAt(0)&&(c[b]=function(b){return function(){return a[b].apply(a,arguments)}}(b))};c.init();C.Mousetrap=c;"undefined"!==typeof module&&module.exports&&(module.exports=
c);"function"===typeof define&&define.amd&&define(function(){return c})})(window,document);

Mousetrap.bind("enter", function () {
	$("#story-caption #endWeekButton a.macro-link").trigger("click");
});
Mousetrap.bind("space", function () {
	$("#story-caption #nextButton a.macro-link").trigger("click");
});
Mousetrap.bind("c", function () {
	$("#story-caption #manageArcology a.macro-link").trigger("click");
});
Mousetrap.bind("p", function () {
	$("#story-caption #managePenthouse a.macro-link").trigger("click");
});
Mousetrap.bind("left", function () {
	$("#prevSlave a.macro-link").trigger("click");
	$("#prevRule a").trigger("click");
});
Mousetrap.bind("q", function () {
	$("#prevSlave a.macro-link").trigger("click");
	$("#prevRule a").trigger("click");
});
Mousetrap.bind("shift+left", function () {
	$("#firstRule a").trigger("click");
});
Mousetrap.bind("shift+q", function () {
	$("#firstRule a").trigger("click");
});
Mousetrap.bind("right", function () {
	$("#nextSlave a.macro-link").trigger("click");
	$("#nextRule a").trigger("click");
});
Mousetrap.bind("shift+right", function () {
	$("#lastRule a").trigger("click");
});
Mousetrap.bind("e", function () {
	$("#nextSlave a.macro-link").trigger("click");
	$("#nextRule a").trigger("click");
});
Mousetrap.bind("shift+e", function () {
	$("#lastRule a").trigger("click");
});
Mousetrap.bind("f", function () {
	$("#walkpast a.macro-link").trigger("click");
});
Mousetrap.bind("h", function () {
	$("#manageHG a.macro-link").trigger("click");
});
Mousetrap.bind("s", function () {
	$("#buySlaves a.macro-link").trigger("click");
});
Mousetrap.bind("a", function () {
	$("#managePA a.macro-link").trigger("click");
});
Mousetrap.bind("b", function () {
	$("#manageBG a.macro-link").trigger("click");
});
Mousetrap.bind("u", function () {
	$("#manageRecruiter a.macro-link").trigger("click");
});
Mousetrap.bind("o", function () {
	$("#story-caption #optionsButton a.macro-link").trigger("click");
});
Mousetrap.bind("y", function () {
	$("#story-caption #policyButton a.macro-link").trigger("click");
});
Mousetrap.bind("f", function () {
	$("#story-caption #FSButton a.macro-link").trigger("click");
});
Mousetrap.bind("t", function () {
	$("#story-caption #PAOButton a.macro-link").trigger("click");
});
Mousetrap.bind("v", function () {
	$("#story-caption #URButton a.macro-link").trigger("click");
});
Mousetrap.bind("r", function () {
	$("#RAButton a.macro-link").trigger("click");
});
Mousetrap.bind("x", function () {
	$("#story-caption #managePerson a.macro-link").trigger("click");
});
Mousetrap.bind("z", function () {
	$("#story-caption #SFMButton a.macro-link").trigger("click");
});
Mousetrap.bind("d", function () {
	$("#story-caption #edictButton a.macro-link").trigger("click");
});
Mousetrap.bind("shift+s", function () {
	$("#story-caption #securityHQ a.macro-link").trigger("click");
});
Mousetrap.bind("shift+a", function () {
	$("#story-caption #secBarracks a.macro-link").trigger("click");
});
Mousetrap.bind("shift+h", function () {
	$("#story-caption #propHub a.macro-link").trigger("click");
});
Mousetrap.bind("shift+r", function () {
	$("#story-caption #riotCenter a.macro-link").trigger("click");
});
/**
 * BoobGenerator namespace.
 */
if (typeof BoobGenerator == "undefined") {
	var BoobGenerator = {
		rollBreast: function (modif) {
			var volume = [0, 300, 500, 650, 800, 1000, 1200, 1400, 1600, 1800, 2050, 2300, 2600, 2900, 3250, 3600, 3950, 4300, 4700, 5100, 5500, 5900];
			var volume_dist = [90000, 470000, 720000, 840000, 908574, 947759, 970151, 982946, 990258, 994436, 996824, 998188, 998968, 999414, 999669, 999814, 999897, 999945, 999972, 999987, 999995, 1000000];
			var randomRoll = Math.floor(Math.random() * 1000000) + 1
			var actualSize = 0
			while (randomRoll > volume_dist[actualSize]) {
				actualSize = actualSize + 1
			}
			var minorSizeAdjustment = 0
			if (Math.random()<.5) {
				minorSizeAdjustment = (Math.floor(Math.random() * 2) + 1) * 50
			}
			var volResult = volume[actualSize] + minorSizeAdjustment + modif
			if (volResult < 0) {volResult = 0}
			return volResult
		}
	};
	// Raise namespace scope to Global.
	window.BoobGenerator = BoobGenerator;
};

/**
 * Slave checker namespace.
 */
if (typeof SlaveStatsChecker == "undefined") {
	var SlaveStatsChecker = {
		checkForLisp: function (slave) {
				/* Begin mod section: toggle whether slaves lisp. */
				if (State && State.variables.disableLisping == 1) {
					return false;
				}
				/* End mod section: toggle whether slaves lisp. */
				return ((slave.lips > 70) || (slave.lipsPiercing + slave.tonguePiercing > 2))
			}
	};
	// Raise namespace scope to Global.
	window.SlaveStatsChecker = SlaveStatsChecker;
};

window.removeFromArray = function(arr, val) {
	for (var i = 0; i < arr.length; i++) {
		if (val == arr[i])
			return arr.splice(i,1);
	}
	return null;
};

window.filterInPlace = function(arr, callback, thisArg) {
	var j = 0;

	arr.forEach(function(e, i) {
		if (callback.call(thisArg, e, i, arr))
			arr[j++] = e;
	});

	arr.length = j;
	return arr;
};

if (typeof FertilityAge == "undefined") {
	var FertilityAge = {
		setAge: function (age) {
			age = Number(age)
				if (age != age) {
					return 13;
				} else {
				return age
			}
		}
	};
	// Raise namespace scope to Global.
	window.FertilityAge = FertilityAge;
};

window.canGetPregnant = function(slave) {
	if (!slave) {
		return null;
	} else if (slave.preg == -1) { /* contraceptives check */
		return false;
	} else if (!isFertile(slave)) { /* check other fertility factors */
		return false;
	} else if ((slave.ovaries == 1) && (canDoVaginal(slave))) {
		return true;
	} else if ((slave.mpreg == 1) && (canDoAnal(slave))) { /* pregmod */
		return true;
	} else {
		return false;
	}
};

/* pregmod: are slave2's sperm compatible with slave1's eggs? */
window.canBreed = function(slave1, slave2) {
	if (!slave1 || !slave2) {
		return null;
	} else if (slave1.eggType == slave2.ballType) {
		return true;
	} else {
		return false;
	}
};

/* assuming slave1 is fertile, could slave2 impregnate slave1? slave2 must have dick and balls with compatible sperm; both slaves must not be in chastity; slave2 need not achieve erection */
window.canImpreg = function(slave1, slave2) {
	if (!slave1 || !slave2) {
		return null;
	} else if (slave2.dick < 1) {
		return false;
	} else if (slave2.ID === -1) {
		if (slave1.eggType != "human") {
			return false;
		} else if (!canGetPregnant(slave1)) { /* includes chastity checks */
			return false;
		} else {
			return true;
		}
	} else if (slave2.balls < 1) {
		return false;
	} else if (slave2.dickAccessory == "chastity") {
		return false;
	} else if (slave2.dickAccessory == "combined chastity") {
		return false;
	} else if (slave2.pubertyXY == 0) { /* pregmod start */
		return false;
	} else if (slave2.vasectomy == 1) {
		return false;
	} else if (slave1.ID === -1) {
		if (slave2.ballType != "human") {
			return false;
		} else if (!isPlayerFertile(slave1)) {
			return false;
		} else {
			return true;
		}
	} else if (!canBreed(slave1, slave2)) {
		return false; /* pregmod end */
	} else if (!canGetPregnant(slave1)) { /* includes chastity checks */
		return false;
	} else {
		return true;
	}
};

/* contraceptives (.preg == -1) do not negate this function */
window.isFertile = function(slave) {
	if (!slave) {
		return null;
	}

	WombInit(slave);

	if (slave.womb.length > 0 && slave.superfetation < 1 && slave.ovaImplant < 1) { /* currently pregnant without superfetation */
		return false;
	} else if (slave.womb.length > 0) { /* temp failure condition to prevent current double preg bug */
	    return false;
	} else if (slave.broodmother > 0) { /* currently broodmother */
		return false;
	} else if (slave.preg < -1) { /* sterile */
		return false;
	} else if (slave.pregWeek < 0) { /* postpartum */
		return false;
	} else if (slave.pubertyXX == 0) { /* pregmod start */
		return false;
	} else if (slave.ovaryAge >= 47) {
		return false;
	} else if (slave.inflation > 2) {
		return false;
	} else if (slave.bellyImplant != -1) {
		return false;
	} else if (slave.mpreg == 1) {
		return true; /* pregmod end */
	} else if (slave.ovaries == 1) {
		return true;
	} else {
		return false;
	}
};

window.isPlayerFertile = function(PC) {
	if (!PC) {
		return null;
	} else if (PC.preg != 0) { /* currently pregnant, sterile, menopausal or on contraceptives */
		return false;
	} else if (PC.pregWeek < 0) { /* postpartum */
		return false;
	} else if (PC.vagina == 1) {
		return true;
	} else {
		return false;
	}
};

window.canAchieveErection = function(slave) {
	if (!slave) {
		return null;
	} else if (slave.dick < 7 && slave.dick > 0 && slave.drugs !== 'hormone blockers' && (slave.balls > 0 ? slave.hormoneBalance < 100 : slave.hormoneBalance <= -100) && slave.ballType != 'sterile') {
		return true;
	} else {
		return false;
	}
};

window.canPenetrate = function(slave) {
	if (!slave) {
		return null;
	} else if (!canAchieveErection(slave)) {
		return false;
	} else if (slave.dickAccessory == "chastity") {
		return false;
	} else if (slave.dickAccessory == "combined chastity") {
		return false;
	} else if (slave.dick > 7) {
		return false;
	}
	return true;
};

window.canSee = function(slave) {
	if (!slave) {
		return null;
	} else if (slave.eyes > -2) {
		return true;
	} else {
		return false;
	}
};

window.canHear = function(slave) {
	if (!slave) {
		return null;
	} else if ((slave.hears > -2) || (slave.earwear == "deafening ear plugs")) {
		return true;
	} else {
		return false;
	}
};

window.canWalk = function(slave) {
	if (!slave) {
		return null;
	} else if (slave.amp == 1) {
		return false;
	} else if (tooFatSlave(slave)) {
		return false;
	} else if (tooBigBreasts(slave)) {
		return false;
	} else if (tooBigDick(slave)) {
		return false;
	} else if (tooBigBalls(slave)) {
		return false;
	} else if (tooBigButt(slave)) {
		return false;
	} else if (tooBigBelly(slave)) {
		return false;
	} else if (slave.heels == 0) {
		return true;
	} else if (slave.shoes == "heels") {
		return true;
	} else if (slave.shoes == "extreme heels") {
		return true;
	} else if (slave.shoes == "boots") {
		return true;
	} else {
		return false;
	}
};

window.canTalk = function(slave) {
	if (!slave) {
		return null;
	} else if (slave.accent > 2) {
		return false;
	} else if (slave.voice == 0) {
		return false;
	} else if (slave.lips > 95) {
		return false;
	} else if (slave.collar == "dildo gag") {
		return false;
	} else if (slave.collar == "massive dildo gag") {
		return false;
	} else if (slave.collar == "ball gag") {
		return false;
	} else if (slave.collar == "bit gag") {
		return false;
	} else {
		return true;
	}
};

window.canDoAnal = function(slave) {
	if (!slave) {
		return null;
	} else if (slave.vaginalAccessory == "anal chastity") {
		return false;
	} else if (slave.dickAccessory == "anal chastity") {
		return false;
	} else if (slave.vaginalAccessory == "combined chastity") {
		return false;
	} else if (slave.dickAccessory == "combined chastity") {
		return false;
	}
	return true;
};

window.canDoVaginal = function(slave) {
	if (!slave) {
		return null;
	} else if (slave.vagina < 0) {
		return false;
	} else if (slave.vaginalAccessory == "chastity belt") {
		return false;
	} else if (slave.vaginalAccessory == "combined chastity") {
		return false;
	}
	return true;
};

window.tooFatSlave = function(slave){
	if (!slave) {
		return null;
	} else if (slave.weight > 190+(slave.muscles/5) && slave.physicalAge >= 18) {
		return true;
	} else if (slave.weight > 130+(slave.muscles/20) && slave.physicalAge <= 3) {
		return true;
	} else if (slave.weight > 160+(slave.muscles/15) && slave.physicalAge <= 12) {
		return true;
	} else if (slave.weight > 185+(slave.muscles/10) && slave.physicalAge < 18) {
		return true;
	} else {
		return false;
	}
};

window.tooBigBreasts = function(slave){
	if (!slave) {
		return null;
	} else if (slave.boobs > 30000+(slave.muscles*100) && slave.physicalAge >= 18) {
		return true;
	} else if (slave.boobs > 5000+(slave.muscles*10) && slave.physicalAge <= 3) {
		return true;
	} else if (slave.boobs > 10000+(slave.muscles*20) && slave.physicalAge <= 12) {
		return true;
	} else if (slave.boobs > 20000+(slave.muscles*50) && slave.physicalAge < 18) {
		return true;
	} else {
		return false;
	}
};

window.tooBigBelly = function(slave){
	if (!slave) {
		return null;
	} else if (slave.belly >= 450000+(slave.muscles*2000) && slave.physicalAge >= 18) {
		return true;
	} else if (slave.belly >= 350000+(slave.muscles*1000) && slave.physicalAge >= 13) {
		return true;
	} else if (slave.belly >= 30000+(slave.muscles*500) && slave.physicalAge <= 3) {
		return true;
	} else if (slave.belly >= 150000+(slave.muscles*800) && slave.physicalAge <= 12) {
		return true;
	} else {
		return false;
	}
};

window.tooBigBalls = function(slave){
	if (!slave) {
		return null;
	} else if (slave.balls >= 30+(slave.muscles*.3) && slave.physicalAge <= 3) {
		return true;
	} else if (slave.balls >= 60+(slave.muscles*.5) && slave.physicalAge <= 12) {
		return true;
	} else if (slave.balls >= 90+(slave.muscles*.7)) {
		return true;
	} else {
		return false;
	}
};

window.tooBigDick = function(slave){
	if (!slave) {
		return null;
	} else if (slave.dick >= 20+(slave.muscles*.1) && slave.physicalAge <= 3 && slave.dick !== 0) {
		return true;
	} else if (slave.dick >= 45+(slave.muscles*.3) && slave.physicalAge <= 12) {
		return true;
	} else if (slave.dick >= 68+(slave.muscles*.4)) {
		return true;
	} else {
		return false;
	}
};

window.tooBigButt = function(slave){
	if (!slave) {
		return null;
	} else if (slave.butt > 10 && slave.physicalAge <= 3) {
		return true;
	} else if (slave.butt > 14 && slave.physicalAge <= 12) {
		return true;
	} else {
		return false;
	}
};

window.relationTargetWord = function(slave) {
	if (!slave) {
		return null;
	} else if (slave.relation == "daughter") {
		return "mother";
	} else if (slave.relation == "mother") {
		return "daughter";
	}
	return slave.relation;
};

window.expandFacilityAssignments = function(facilityAssignments) {
	var assignmentPairs = {
		"serve in the club": "be the DJ",
		"rest in the spa": "be the Attendant",
		"be a nanny": "be the Matron",
		"work as a nanny": "be the Matron",
		"work in the brothel": "be the Madam",
		"work in the dairy": "be the Milkmaid",
		"work as a servant": "be the Stewardess",
		"get treatment in the clinic": "be the Nurse",
		"live with your Head Girl": "be your Head Girl",
		"serve in the master suite": "be your Concubine",
		"learn in the schoolroom": "be the Schoolteacher",
		"be confined in the cellblock": "be the Wardeness",
	};

	if (!facilityAssignments || !facilityAssignments.length)
		return [];
	var fullList = facilityAssignments.map(function(a) {
		if (a in assignmentPairs)
			return [a, assignmentPairs[a]];
		return a;
	});
	return fullList.flatten();
};

window.milkAmount = function(slave) {
	var milk;
	var calcs;
	if (!slave) {
		return null;
	} else {
		calcs = slave.boobs-slave.boobsImplant
		if (calcs > 40000) {
			milk = (158+((calcs-10000)/600))
		} else if (calcs > 25000) {
			milk = (128+((calcs-10000)/500))
		} else if (calcs > 10000) {
			milk = (78+((calcs-10000)/300))
		} else if (calcs > 5000) {
			milk = (53+((calcs-5000)/200))
		} else if (calcs > 2000) {
			milk = (29+((calcs-2000)/125))
		} else if (calcs > 800) {
			milk = (16+((calcs-800)/80))
		} else {
			milk = (8+((calcs-400)/50))
		}
		if (slave.lactation == 2) {
			milk *= 1.2
		}
		milk += (milk*((slave.devotion-50)/200))
		if (slave.boobsImplant > 200) {
			milk *= 0.9
		}
		calcs = (slave.hormoneBalance/50)
		if (slave.balls != 0 && calcs > -2) {
			calcs -= 1
		} else if (slave.ovaries != 1 && calcs < 2) {
			calcs += 1
		}
		milk *= (1+(calcs*0.1))
		milk *= (1+(slave.preg/100))
		milk *= (1+(slave.health/50))
		milk *= (1+(slave.weight/500))
		milk *= (1+(slave.lactationAdaptation/500))
		milk = Math.trunc(milk)
		milk = Math.clamp(milk,1,1000000000000000000)
		return milk
	}
};

window.cumAmount = function(slave) {
	var cum = 0;
	var calcs = 0;
	if (!slave) {
		return null;
	} else {
		if (slave.drugs == "testicle enhancement") {
			cum = ((slave.balls*3.5)+1)
		} else if (slave.drugs == "hyper testicle enhancement") {
			cum = ((slave.balls*5)+1)
		} else {
			cum = ((slave.balls*2.5)+1)
		}
		if (slave.ballType == "sterile") {
			cum *= 0.8
		}
		if (slave.diet == "cum production") {
			cum *= 1.2
		}
		calcs = (slave.hormoneBalance/50)
		cum *= (1-(calcs*0.1))
		if (slave.scrotum == 0) {
			cum *= 0.8
		}
		if (slave.prostate == 0) {
			cum *= 0.2 // being generous here
		} else if (slave.prostate == 2) {
			cum *= 1.2
		} else if (slave.prostate == 3) {
			cum *= 1.5
		}
		if (slave.devotion > 50) {
			cum += (cum*(slave.devotion/100))
		} else if (slave.devotion < -50) {
			cum += (cum*(slave.devotion/100))
		}
		if (slave.health > 50) {
			cum += (cum*(slave.health/50))
		} else if (slave.health < -50) {
			cum += (cum*(slave.health/50))
		}
		cum = Math.trunc(cum)
		cum = Math.clamp(cum,1,1000000000000000000)
		return cum
	}
};

window.lispReplace = function(text)
{
	text = text.replace(/Sh/g, "Th");
	text = text.replace(/SS/g, "Th");
	text = text.replace(/Ss/g, "Th");
	text = text.replace(/sS/g, "Th");
	text = text.replace(/S/g, "Th");
	text = text.replace(/aX/g, "aKTH");
	text = text.replace(/eX/g, "eKTH");
	text = text.replace(/iX/g, "iKTH");
	text = text.replace(/oX/g, "oKTH");
	text = text.replace(/uX/g, "uKTH");
	text = text.replace(/yX/g, "yKTH");
	text = text.replace(/AX/g, "AKTH");
	text = text.replace(/EX/g, "EKTH");
	text = text.replace(/IX/g, "IKTH");
	text = text.replace(/OX/g, "OKTH");
	text = text.replace(/UX/g, "UKTH");
	text = text.replace(/YX/g, "YKTH");
	text = text.replace(/Xa/g, "Tha");
	text = text.replace(/Xe/g, "The");
	text = text.replace(/Xi/g, "Thi");
	text = text.replace(/Xo/g, "Tho");
	text = text.replace(/Xu/g, "Thu");
	text = text.replace(/Xy/g, "Thy");
	text = text.replace(/XA/g, "THA");
	text = text.replace(/XE/g, "THE");
	text = text.replace(/XI/g, "THI");
	text = text.replace(/XO/g, "THO");
	text = text.replace(/XU/g, "THU");
	text = text.replace(/XY/g, "THY");
	text = text.replace(/X/g, "EKTH");
	text = text.replace(/zZ/g, "Th");
	text = text.replace(/Zz/g, "Th");
	text = text.replace(/ZZ/g, "TH");
	text = text.replace(/Z/g, "Th");
	text = text.replace(/Cia/g, "Tha");
	text = text.replace(/Ci/g, "Thi");
	text = text.replace(/Ce/g, "The");
	text = text.replace(/Cy/g, "Thy");
	text = text.replace(/CIA/g, "THA");
	text = text.replace(/CI/g, "THI");
	text = text.replace(/CE/g, "THE");
	text = text.replace(/CY/g, "THY");
	text = text.replace(/ss/g, "th");
	text = text.replace(/sh/g, "th");
	text = text.replace(/s/g, "th");
	text = text.replace(/zz/g, "th");
	text = text.replace(/z/g, "th");
	text = text.replace(/ax/g, "akth");
	text = text.replace(/ex/g, "ekth");
	text = text.replace(/ix/g, "ikth");
	text = text.replace(/ox/g, "okth");
	text = text.replace(/ux/g, "ukth");
	text = text.replace(/yx/g, "ykth");
	text = text.replace(/Ax/g, "Akth");
	text = text.replace(/Ex/g, "Ekth");
	text = text.replace(/Ix/g, "Ikth");
	text = text.replace(/Ox/g, "Okth");
	text = text.replace(/Ux/g, "Ukth");
	text = text.replace(/Yx/g, "Ykth");
	text = text.replace(/xa/g, "tha");
	text = text.replace(/xe/g, "the");
	text = text.replace(/xi/g, "thi");
	text = text.replace(/xo/g, "tho");
	text = text.replace(/xu/g, "thu");
	text = text.replace(/xy/g, "thy");
	text = text.replace(/xA/g, "thA");
	text = text.replace(/xE/g, "thE");
	text = text.replace(/xI/g, "thI");
	text = text.replace(/xO/g, "thO");
	text = text.replace(/xU/g, "thU");
	text = text.replace(/xY/g, "thY");
	text = text.replace(/x/g, "ekth");
	text = text.replace(/cia/g, "tha");
	text = text.replace(/ci/g, "thi");
	text = text.replace(/ce/g, "the");
	text = text.replace(/cy/g, "thy");
	text = text.replace(/cI/g, "thI");
	text = text.replace(/cE/g, "thE");
	text = text.replace(/cY/g, "thY");
	return text;
}

window.isVegetable = function(slave) {
	slave = slave || State.variables.activeSlave;
	if(!slave) { return false; }
	return (slave.fetish === 'mindbroken');
};

window.repGainSacrifice = function(slave, arcology) {
	slave = slave || State.variables.activeSlave;
	arcology = arcology || State.variables.arcologies[0];
	if(!slave || !arcology || arcology.FSAztecRevivalist === "unset" || arcology.FSAztecRevivalist <= 0) {
		return 0;
	}
	return Math.ceil(
		(Math.min(100, Math.pow(1.0926, State.variables.week - slave.weekAcquired)) + slave.prestige * 30)
			* arcology.FSAztecRevivalist / 100 / ((State.variables.slavesSacrificedThisWeek || 0) + 1));
};

window.bodyguardSuccessorEligible = function(slave) {
	if(!slave) { return false; }
	return (slave.devotion > 50 && slave.muscles >= 0 && slave.weight < 100 && slave.boobs < 8000 && slave.butt < 10 && slave.belly < 5000 && slave.balls < 10 && slave.dick < 10 && slave.preg < 20 && slave.fuckdoll == 0 && slave.fetish != "mindbroken" && canWalk(slave));
};

window.ngUpdateGenePool = function(genePool) {
	var transferredSlaveIds = (State.variables.slaves || [])
	.filter(function(s) { return s.ID >= 1200000; })
	.map(function(s) { return s.ID - 1200000; });
	return (genePool || [])
	.filter(function(s) { return transferredSlaveIds.indexOf(s.ID) >= 0; })
	.map(function(s) {
	var result = jQuery.extend(true, {}, s);
	result.ID += 1200000;
	return result;
	});
}

window.ngUpdateMissingTable = function(missingTable) {
	var newTable = {};

	(State.variables.slaves || [])
	.forEach(s => ([s.pregSource+1200000,s.mother+1200000,s.father+1200000]
	.filter(i => (i in missingTable))
	.forEach(i => { 
	newTable[i-1200000] = missingTable[i];
	newTable[i-1200000].ID -= 1200000;
	})));

	return newTable;
};

window.toJson = function(obj) {
	var jsontext = JSON.stringify(obj);
	jsontext = jsontext.replace(/^{/,"");
	jsontext = jsontext.replace(/}$/,"");
	return jsontext;
};

window.nippleColor = function(slave) {
	slave = slave || State.variables.activeSlave;
	if(slave.skin === 'tanned' || slave.skin === 'fair') {
		if(slave.preg > 10 || (slave.birthsTotal > 0 && slave.lactation > 0)) {
			return 'dark brown';
		} else {
			return 'pink';
		}
	} else if((slave.skin === 'pale' || slave.race === 'white')) {
		if(slave.preg > 10 || (slave.birthsTotal > 0 && slave.lactation > 0)) {
			return 'brown';
		} else {
			return 'pink';
		}
	} else if((slave.skin === 'brown' || slave.race === 'black')) {
		if(slave.preg > 10 || (slave.birthsTotal > 0 && slave.lactation > 0)) {
			return 'black';
		} else {
			return 'dark brown';
		}
	} else {
		if(slave.preg > 10 || (slave.birthsTotal > 0 && slave.lactation > 0)) {
			return 'dark brown';
		} else {
			return 'brown';
		}
	}
}

window.overpowerCheck = function(slave, PC) {
	var strength;

	if(State.variables.arcologies[0].FSPhysicalIdealist != "unset") {
		if(PC.title == 1) {
			strength = 130;
		} else {
			strength = 100;
		}
	} else if(PC.title == 1) {
		strength = 50;
	} else {
		strength = 30;
	}
	strength += (185-slave.height);
	strength -= (PC.belly/1000);

	return strength;
}

window.impregnatedBy = function(slave) { /* returns array of IDs of all characters who impregnated slave */
	var IDArray = [];
	if (!Array.isArray(slave.womb)) {
		WombInit(slave);
	}
	for (var i = 0; i < slave.womb.length; i++) {
		IDArray.push(slave.womb[i].fatherID);
	}
	return IDArray;
}

window.isImpregnatedBy = function(mother, father) { /* returns true if mother was impregnated by father */
	return impregnatedBy(mother).includes(father.ID);
}

window.jsAlert = function(obj)
{
	alert(obj);
}

window.jsConsoleInfo = function(obj)
{
	console.info(obj);
}

window.SoftenBehavioralFlaw = function SoftenBehavioralFlaw(slave) {
	switch (slave.behavioralFlaw) {
		case "arrogant":
			slave.behavioralQuirk = "confident";
			break;
		case "bitchy":
			slave.behavioralQuirk = "cutting";
			break;
		case "odd":
			slave.behavioralQuirk = "funny";
			break;
		case "hates men":
			slave.behavioralQuirk = "adores women";
			break;
		case "hates women":
			slave.behavioralQuirk = "adores men";
			break;
		case "gluttonous":
			slave.behavioralQuirk = "fitness";
			break;
		case "anorexic":
			slave.behavioralQuirk = "insecure";
			break;
		case "devout":
			slave.behavioralQuirk = "sinful";
			break;
		case "liberated":
			slave.behavioralQuirk = "advocate";
			break;
	}
	slave.behavioralFlaw = "none";
};

window.SoftenSexualFlaw = function SoftenSexualFlaw(slave) {
	switch (slave.sexualFlaw) {
		case "hates oral":
			slave.sexualQuirk = "gagfuck queen";
			break;
		case "hates anal":
			slave.sexualQuirk = "painal queen";
			break;
		case "hates penetration":
			slave.sexualQuirk = "strugglefuck queen";
			break;
		case "shamefast":
			slave.sexualQuirk = "tease";
			break;
		case "idealistic":
			slave.sexualQuirk = "romantic";
			break;
		case "repressed":
			slave.sexualQuirk = "perverted";
			break;
		case "apathetic":
			slave.sexualQuirk = "caring";
			break;
		case "crude":
			slave.sexualQuirk = "unflinching";
			break;
		case "judgemental":
			slave.sexualQuirk = "size queen";
			break;
	}
	slave.sexualFlaw = "none";
};
