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

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

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

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

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

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

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

		if (Array.isArray(V.personalAttention)) {
			const _rasi = V.personalAttention.findIndex(function(s) { return s.ID === AS_ID; });
			if (_rasi !== -1) {
				V.personalAttention.deleteAt(_rasi);
				if (V.personalAttention.length === 0) {
					if (V.PC.career === "escort") {
						V.personalAttention = "whoring";
					} else if (V.PC.career === "servant") {
						V.personalAttention = "upkeep";
					} else {
						V.personalAttention = "business";
					}
				}
			}
		}

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

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

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

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

		removeSlave(INDEX);
		LENGTH--;
		V.activeSlave = 0;
	}
};

window.removeNonNGPSlave = function removeNonNGPSlave(removedSlave) {
	"use strict";

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

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

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

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

		removeSlave(INDEX);

	}
};


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

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

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

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

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

/** @param {App.Entity.SlaveState} slave */
window.lastPregRule = function(slave, rules) {
	return rules.some(rule =>
		ruleApplied(slave, rule) && rule.set.preg === -1);
};

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// return whether the rule applies to the slave
/** @param {App.Entity.SlaveState} slave */
window.ruleAppliesP = function ruleAppliesP(cond, slave) {
	let flag;

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

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

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

repo_name: AnonDev/fc