diff --git a/src/js/extendedFamilyModeJS.js b/src/js/extendedFamilyModeJS.js
index 7477d6885a68e7bb72d3bdc2cd9a4a9f5f651def..039b4afeb1144756326ac87bf4a50c881fd68d95 100644
--- a/src/js/extendedFamilyModeJS.js
+++ b/src/js/extendedFamilyModeJS.js
@@ -1,17 +1,48 @@
 /* see documentation for details /devNotes/Extended Family Mode Explained.txt */
 
+/** @typedef Relative
+ * An object that represents a entity in a family tree. Represents a group of common properties shared by SlaveState, InfantState, and PlayerState, as well as genepool objects.
+ * @type {object}
+ * @property {number} ID
+ * @property {number} mother
+ * @property {number} father
+ * @property {number} actualAge
+ * @property {number} birthWeek
+ * @property {string} genes
+ */
+
+/** Returns true if mother is the mother of daughter
+ * @param {Relative} daughter
+ * @param {Relative} mother
+ * @returns {boolean}
+ */
 globalThis.isMotherP = function(daughter, mother) {
 	return daughter.mother === mother.ID;
 };
 
+/** Returns true if father is the father of daughter
+ * @param {Relative} daughter
+ * @param {Relative} father
+ * @returns {boolean}
+ */
 globalThis.isFatherP = function(daughter, father) {
 	return daughter.father === father.ID;
 };
 
+/** Returns true if parent is either the father or mother of daughter
+ * @param {Relative} daughter
+ * @param {Relative} parent
+ * @returns {boolean}
+ */
 globalThis.isParentP = function(daughter, parent) {
 	return isMotherP(daughter, parent) || isFatherP(daughter, parent);
 };
 
+/** Returns true if grandmother is the grandmother of granddaughter
+ * @param {Relative} granddaughter
+ * @param {Relative} grandmother
+ * @returns {boolean}
+ */
 globalThis.isGrandmotherP = function(granddaughter, grandmother) {
 	let father;
 	let mother;
@@ -21,6 +52,11 @@ globalThis.isGrandmotherP = function(granddaughter, grandmother) {
 	return false;
 };
 
+/** Returns true if grandfather is the grandfather of granddaughter
+ * @param {Relative} granddaughter
+ * @param {Relative} grandfather
+ * @returns {boolean}
+ */
 globalThis.isGrandfatherP = function(granddaughter, grandfather) {
 	let father;
 	let mother;
@@ -30,10 +66,20 @@ globalThis.isGrandfatherP = function(granddaughter, grandfather) {
 	return false;
 };
 
+/** Returns true if grandparent is the either the grandmother or grandfather of granddaughter
+ * @param {Relative} granddaughter
+ * @param {Relative} grandparent
+ * @returns {boolean}
+ */
 globalThis.isGrandparentP = function(granddaughter, grandparent) {
 	return isGrandmotherP(granddaughter, grandparent) || isGrandfatherP(granddaughter, grandparent);
 };
 
+/** Returns true if slave1 and slave2 share the same father
+ * @param {Relative} slave1
+ * @param {Relative} slave2
+ * @returns {boolean}
+ */
 globalThis.sameDad = function(slave1, slave2) {
 	if ((slave1.father === slave2.father) && (specificDad(slave1))) {
 		return true;
@@ -41,6 +87,11 @@ globalThis.sameDad = function(slave1, slave2) {
 	return false;
 };
 
+/** Returns true if slave1 and slave2 share the same mother
+ * @param {Relative} slave1
+ * @param {Relative} slave2
+ * @returns {boolean}
+ */
 globalThis.sameMom = function(slave1, slave2) {
 	if ((slave1.mother === slave2.mother) && (specificMom(slave1))) {
 		return true;
@@ -48,21 +99,45 @@ globalThis.sameMom = function(slave1, slave2) {
 	return false;
 };
 
+/** Returns true if slave1 and slave2 have at least one common parent
+ * @param {Relative} slave1
+ * @param {Relative} slave2
+ * @returns {boolean}
+ */
 globalThis.sameParent = function(slave1, slave2) {
 	return sameMom(slave1, slave2) || sameDad(slave1, slave2);
 };
 
+/** Returns true if ID represents a unique, specific, and traceable character; false if it represents a nonspecific or group ID.
+ * @param {number} ID
+ * @returns {boolean}
+ */
+globalThis.specificCharacterID = function(ID) {
+	return (ID > 0		// active slave
+		 || ID < -20	// missing slave
+		 || ID === -1	// player
+		 || ID === -3);	// player's old master
+};
+
+/** Returns true if the father of slave is a specific, unique character (current or former slave, or the PC)
+ * @param {Relative} slave
+ * @returns {boolean}
+ */
 globalThis.specificDad = function(slave) {
-	return (slave.father !== 0 && slave.father !== -2 && slave.father !== -4 && slave.father !== -5 && slave.father !== -6 && slave.father !== -7 && slave.father !== -8 && slave.father !== -9);
+	return specificCharacterID(slave.father);
 };
 
+/** Returns true if the mother of slave is a specific, unique character (current or former slave, or the PC)
+ * @param {Relative} slave
+ * @returns {boolean}
+ */
 globalThis.specificMom = function(slave) {
-	return (slave.mother !== 0 && slave.mother !== -2 && slave.mother !== -4 && slave.mother !== -5 && slave.mother !== -6 && slave.mother !== -7 && slave.mother !== -8 && slave.mother !== -9);
+	return specificCharacterID(slave.mother);
 };
 
-/**
- * @param {App.Entity.SlaveState} niece
- * @param {App.Entity.SlaveState} aunt
+/** Returns true if aunt is the aunt of niece
+ * @param {Relative} niece
+ * @param {Relative} aunt
  * @returns {boolean}
  */
 globalThis.isAunt = function(niece, aunt) {
@@ -96,31 +171,10 @@ globalThis.sameTParent = function(slave1, slave2) {
 	return 0;
 };
 
-/*
-globalThis.sameTParent = function(slave1, slave2) {
-	if ((slave1.mother === slave2.father || slave1.father === slave2.mother) && (slave1.mother !== 0 && slave1.mother !== -2 && slave1.father !== 0 && slave1.father !== -2)) {
-		return true; //testtest catches the case if a mother is a father or a father a mother
-	} else {
-		return false;
-	}
-};
-*/
-
-globalThis.areTwins = function(slave1, slave2) {
-	if (!sameDad(slave1, slave2)) {
-		return false;
-	} else if (!sameMom(slave1, slave2)) {
-		return false;
-	} else if (slave1.actualAge === slave2.actualAge && slave1.birthWeek === slave2.birthWeek) {
-		return true;
-	}
-	return false;
-};
-
-/**
- * @param {App.Entity.SlaveState} slave1
- * @param {App.Entity.SlaveState} slave2
- * @returns {number}
+/** Returns the degree of siblinghood shared by two entities
+ * @param {Relative} slave1
+ * @param {Relative} slave2
+ * @returns {number} - 0: not siblings; 1: twins; 2: full siblings; 3: half-siblings
  */
 globalThis.areSisters = function(slave1, slave2) {
 	if (slave1.ID === slave2.ID) {
@@ -148,9 +202,9 @@ globalThis.areSisters = function(slave1, slave2) {
 	}
 };
 
-/**
- * @param {App.Entity.SlaveState} slave1
- * @param {App.Entity.SlaveState} slave2
+/** Returns true if two entities are simple first cousins (i.e. at least one parent of one slave is a full sibling of at least one parent of the other slave)
+ * @param {Relative} slave1
+ * @param {Relative} slave2
  * @returns {boolean}
  */
 globalThis.areCousins = function(slave1, slave2) {
@@ -180,18 +234,17 @@ globalThis.areCousins = function(slave1, slave2) {
 	return false;
 };
 
-/**
- * Returns whether two slaves are *closely* related (i.e. siblings or parent/child).
+/** Returns whether two entities are *closely* related (i.e. siblings or parent/child).
  * Distant relatives are not checked by this function.
- * @param {App.Entity.SlaveState} slave1
- * @param {App.Entity.SlaveState} slave2
+ * @param {Relative} slave1
+ * @param {Relative} slave2
  * @returns {boolean}
  */
 globalThis.areRelated = function(slave1, slave2) {
 	return (slave1.father === slave2.ID || slave1.mother === slave2.ID || slave2.father === slave1.ID || slave2.mother === slave1.ID || areSisters(slave1, slave2) > 0);
 };
 
-/**
+/** Returns the total number of relatives that a slave has
  * @param {App.Entity.SlaveState} slave
  * @returns {number}
  */
@@ -212,9 +265,9 @@ globalThis.totalRelatives = function(slave) {
 	return relatives;
 };
 
-/**
- * @param {App.Entity.SlaveState} slave1
- * @param {App.Entity.SlaveState} slave2
+/** Returns the slaves which are mutual children of two entities
+ * @param {Relative} slave1
+ * @param {Relative} slave2
  * @param {App.Entity.SlaveState[]} slaves
  * @returns {number}
  */
@@ -224,123 +277,88 @@ globalThis.mutualChildren = function(slave1, slave2, slaves) {
 	}).length;
 };
 
-/**
- * @param {App.Entity.SlaveState} slave
+/** Returns a random slave related to a given entity
+ * @param {Relative} slave
  * @param {function(App.Entity.SlaveState): boolean} filterFunction
  * @returns {App.Entity.SlaveState}
  */
 globalThis.randomRelatedSlave = function(slave, filterFunction) {
-	if (!slave || !SugarCube) {
+	if (!slave) {
 		return undefined;
 	}
 	if (typeof filterFunction !== 'function') {
-		filterFunction = function( /* s, index, array*/ ) {
-			return true;
-		};
+		filterFunction = () => true;
 	}
-	const arr = V.slaves.filter(filterFunction);
-	arr.shuffle();
-	return arr.find(function(s) {
-		return areSisters(slave, s) ||
-			slave.ID === s.mother ||
-			slave.ID === s.father ||
-			s.ID === slave.mother ||
-			s.ID === slave.father;
-	});
+	const arr = V.slaves.filter((s) => areRelated(slave, s) && filterFunction(s));
+	return arr.random();
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {Relative} slave
  * @returns {App.Entity.SlaveState}
  */
 globalThis.randomRelatedAvailableSlave = function(slave) {
-	return randomRelatedSlave(slave, function(s) {
-		return isSlaveAvailable(s);
-	});
+	return randomRelatedSlave(slave, (s) => isSlaveAvailable(s));
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {Relative} slave
  * @returns {App.Entity.SlaveState}
  */
 globalThis.randomSister = function(slave) {
-	return randomRelatedSlave(slave, function(s) {
-		return areSisters(slave, s);
-	});
+	return randomRelatedSlave(slave, (s) => areSisters(slave, s) > 0);
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {Relative} slave
  * @returns {App.Entity.SlaveState}
  */
 globalThis.randomTwinSister = function(slave) {
-	return randomRelatedSlave(slave, function(s) {
-		return areSisters(slave, s);
-	});
+	return randomRelatedSlave(slave, (s) => areSisters(slave, s) === 1);
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {Relative} slave
  * @returns {App.Entity.SlaveState}
  */
 globalThis.randomAvailableSister = function(slave) {
-	return randomRelatedSlave(slave, function(s) {
-		return isSlaveAvailable(s) && areSisters(slave, s);
-	});
-};
-
-/**
- * @param {App.Entity.SlaveState} slave
- * @returns {App.Entity.SlaveState}
- */
-globalThis.randomAvailableTwinSister = function(slave) {
-	return randomRelatedSlave(slave, function(s) {
-		return isSlaveAvailable(s) && areSisters(slave, s);
-	});
+	return randomRelatedSlave(slave, (s) => isSlaveAvailable(s) && areSisters(slave, s) > 0);
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {Relative} slave
  * @returns {App.Entity.SlaveState}
  */
 globalThis.randomDaughter = function(slave) {
-	return randomRelatedSlave(slave, function(s) {
-		return s.mother === slave.ID || s.father === slave.ID;
-	});
+	return randomRelatedSlave(slave, (s) => isParentP(s, slave));
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {Relative} slave
  * @returns {App.Entity.SlaveState}
  */
 globalThis.randomAvailableDaughter = function(slave) {
-	return randomRelatedSlave(slave, function(s) {
-		return isSlaveAvailable(s) && (s.mother === slave.ID || s.father === slave.ID);
-	});
+	return randomRelatedSlave(slave, (s) => isSlaveAvailable(s) && isParentP(s, slave));
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {Relative} slave
  * @returns {App.Entity.SlaveState}
  */
 globalThis.randomParent = function(slave) {
-	return randomRelatedSlave(slave, function(s) {
-		return s.ID === slave.mother || s.ID === slave.father;
-	});
+	return randomRelatedSlave(slave, (s) => isParentP(slave, s));
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {Relative} slave
  * @returns {App.Entity.SlaveState}
  */
 globalThis.randomAvailableParent = function(slave) {
-	return randomRelatedSlave(slave, function(s) {
-		return isSlaveAvailable(s) && (s.ID === slave.mother || s.ID === slave.father);
-	});
+	return randomRelatedSlave(slave, (s) => isSlaveAvailable(s) && isParentP(slave, s));
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {Relative} slave
  * @returns {object}
  */
 globalThis.availableRelatives = function(slave) {
@@ -400,8 +418,8 @@ globalThis.totalPlayerRelatives = function(pc) {
 /**
  * Returns the term for slave2's relationship to slave1 (i.e. "daughter" if slave2 is slave1's daughter).
  * Performs distant relative checking if enabled.
- * @param {App.Entity.SlaveState} slave1
- * @param {App.Entity.SlaveState} slave2
+ * @param {Relative} slave1
+ * @param {Relative} slave2
  * @returns {string|null} - returns null if the slaves are not related, even distantly.
  */
 globalThis.relativeTerm = function(slave1, slave2) {
@@ -492,17 +510,15 @@ globalThis.resetFamilyCounters = function() {
 	}
 };
 
-/** Set any missing parents to a known ID for the given slave (usually so that a sibling can be safely generated)
- * @param {App.Entity.SlaveState} slave
+/** Set any missing parents to a known ID for the given entity (usually so that a sibling can be safely generated)
+ * @param {Relative} slave
  */
 globalThis.setMissingParents = function(slave) {
-	function untraceableParentID(ID) { return ID === 0 || (ID < -1 && ID >= -20 && ID !== -3); }
-
-	if (untraceableParentID(slave.mother)) {
+	if (!specificMom(slave)) {
 		slave.mother = V.missingParentID;
 		V.missingParentID--;
 	}
-	if (untraceableParentID(slave.father)) {
+	if (!specificDad(slave)) {
 		slave.father = V.missingParentID;
 		V.missingParentID--;
 	}