App.Desc.family = (function() {
	/** From a list of slaves, return their names, comma-separated and appended with "and" if necessary
	 * @param {Array<App.Entity.SlaveState>} slaveList
	 * @returns {string}
	 */
	function slaveListToText(slaveList) {
		return slaveList.map(s => s.slaveName).reduce((res, ch, i, arr) => res + (i === arr.length - 1 ? ' and ' : ', ') + ch);
	}

	/** See if an ID refers to a valid, active slave.  This will return false for slaves that no longer exist or have not yet been created.
	 * @param {number} slaveID
	 * @returns {boolean}
	 */
	function validSlaveID(slaveID) {
		return slaveID > 0 && _.isObject(getSlave(slaveID));
	}

	/** From a slave ID, return text describing that slave (even if they aren't currently your slave) to use in place of their name
	 * @param {number} slaveID
	 * @returns {string}
	 */
	function knownSlave(slaveID) {
		if (validSlaveID(slaveID)) {
			return getSlave(slaveID).slaveName;
		} else if (slaveID in V.missingTable) {
			return "your former slave " + V.missingTable[slaveID].slaveName;
		} else {
			return "another slave";
		}
	}

	/** Splits an array of slaves by sex (nieces/nephews, aunts/uncles, brothers/sisters, etc)
	 * @param {Array<App.Entity.SlaveState>} slaves
	 * @returns {{m: Array<App.Entity.SlaveState>, f: Array<App.Entity.SlaveState>}}
	 */
	function splitBySex(slaves) {
		let r = {m: [], f: []};
		for (const s of slaves) {
			if (s.genes === "XX") {
				r.f.push(s);
			} else {
				r.m.push(s);
			}
		}
		return r;
	}

	/** Describe the members of a character's family.
	 * @param {App.Entity.SlaveState} character (pass V.PC to get the PC's special family summary)
	 * @returns {string}
	 */
	function familySummary(character) {
		if (character === V.PC) {
			return PCFamilySummary();
		} else {
			return slaveFamilySummary(character);
		}
	}

	/** Describe the members of a slave's family.
	 * @param {App.Entity.SlaveState} slave
	 * @returns {string}
	 */
	function slaveFamilySummary(slave) {
		let r = [];

		const {He, His, he, him, himself, his, sister} = getPronouns(slave);

		/* PC parentage */
		if (slave.ID === V.PC.mother && slave.ID === V.PC.father) {
			r.push(`${He} is <span class="lightgreen">both your mother and father;</span> ${he} impregnated ${himself} with you.`);
		} else if (slave.ID === V.PC.mother) {
			r.push(`${He} is <span class="lightgreen">your mother.</span>`);
		} else if (slave.ID === V.PC.father) {
			r.push(`${He} is <span class="lightgreen">your father.</span>`);
		}

		if (slave.father === -1 && slave.mother === -1) {
			r.push(`${He}'s <span class="lightgreen">your child;</span> you knocked yourself up and gave birth to ${him}.`);
		} else if (slave.father === slave.mother && (slave.father > 0 || (slave.father in V.missingTable && V.showMissingSlaves))) {
			r.push(`${He} was <span class="lightgreen">both fathered and mothered by ${knownSlave(slave.father)}.</span>`);
		}

		if (slave.father === -1 && slave.mother !== -1) {
			r.push(`${He}'s <span class="lightgreen">your child;</span> you knocked ${his} mother up.`);
		} else if ((slave.father > 0 || (slave.father in V.missingTable && V.showMissingSlaves)) && slave.father !== slave.mother) {
			r.push(`${He} was <span class="lightgreen">fathered by ${knownSlave(slave.father)}'s</span> virile dick.`);
		}

		if (slave.father !== -1 && slave.mother === -1) {
			r.push(`${He}'s <span class="lightgreen">your child;</span> you gave birth to ${him}.`);
		} else if ((slave.mother > 0 || (slave.mother in V.missingTable && V.showMissingSlaves)) && slave.father !== slave.mother) {
			r.push(`${He} was <span class="lightgreen">born from ${knownSlave(slave.mother)}'s</span> fertile womb.`);
		}

		let children = V.slaves.filter((s) => slave.ID === s.father);
		if (children.length > 2) {
			r.push(`${He} <span class="lightgreen">fathered ${slaveListToText(children)}.</span>`);
		} else if (children.length > 1) {
			r.push(`${He} <span class="lightgreen">fathered a pair of your slaves: ${slaveListToText(children)}.</span>`);
		} else if (children.length > 0) {
			r.push(`${He} <span class="lightgreen">fathered a single slave of yours: ${slaveListToText(children)}.</span>`);
		}

		children = V.slaves.filter((s) => slave.ID === s.mother);
		if (children.length > 2) {
			r.push(`${He} <span class="lightgreen">gave birth to ${slaveListToText(children)}.</span>`);
		} else if (children.length > 1) {
			r.push(`${He} <span class="lightgreen">gave birth to a pair of your slaves: ${slaveListToText(children)}.</span>`);
		} else if (children.length > 0) {
			r.push(`${He} <span class="lightgreen">gave birth to a single slave of yours: ${slaveListToText(children)}.</span>`);
		}

		function getParentIndices(slaveID) {
			if (slaveID === V.PC.ID) {
				return {mi: V.slaveIndices[V.PC.mother], fi: V.slaveIndices[V.PC.father]};
			} else {
				const target = getSlave(slaveID);
				if (target) {
					return {mi: V.slaveIndices[target.mother], fi: V.slaveIndices[target.father]};
				}
			}
			return {mi: undefined, fi: undefined};
		}

		if (V.showDistantRelatives) {
			/* grandparents */
			const mi = V.slaveIndices[slave.mother];
			const fi = V.slaveIndices[slave.father];
			const {mi: mmi, fi: fmi} = getParentIndices(slave.mother);
			const {mi: mfi, fi: ffi} = getParentIndices(slave.father);
			if ((jsDef(mi) || jsDef(fi)) && !jsDef(mmi) && !jsDef(fmi) && !jsDef(mfi) && !jsDef(ffi)) {
				if (jsDef(mi)) {
					if ((jsDef(fi)) && mi === fi) {
						if (V.PC.ID === V.slaves[mi].mother && V.PC.ID === V.slaves[fi].father) {
							r.push(`${He} is <span class="lightgreen">your grandchild.</span> You impregnated yourself with ${his} sole biological parent.`);
						} else if (V.PC.ID === V.slaves[mi].mother) {
							r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to ${his} sole biological parent.`);
						} else if (V.PC.ID === V.slaves[fi].father) {
							r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered ${his} sole biological parent.`);
						}
					} else if ((jsDef(fi)) && V.PC.ID === V.slaves[mi].mother && V.PC.ID === V.slaves[fi].mother) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to both of ${his} parents.`);
					} else if ((jsDef(fi)) && V.PC.ID === V.slaves[mi].father && V.PC.ID === V.slaves[fi].father) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered both of ${his} parents.`);
					} else if (V.PC.ID === V.slaves[mi].mother) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to ${his} mother.`);
					} else if (V.PC.ID === V.slaves[mi].father) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered ${his} mother.`);
					}
				} else if (jsDef(fi)) {
					if (V.PC.ID === V.slaves[fi].mother) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You gave birth to ${his} father.`);
					} else if (V.PC.ID === V.slaves[fi].father) {
						r.push(`${He} is <span class="lightgreen">your grandchild.</span> You fathered ${his} father.`);
					}
				}
			} else {
				if ((jsDef(mmi)) && (jsDef(ffi)) && mmi === ffi) {
					r.push(`${His} sole <span class="lightgreen">grandparent is ${V.slaves[mmi].slaveName}.</span>`);
				} else {
					if ((jsDef(mmi)) && (jsDef(mfi)) && mmi === mfi) {
						r.push(`${His} sole <span class="lightgreen">grandmother is ${V.slaves[mmi].slaveName}.</span>`);
					} else {
						if (jsDef(mmi)) {
							r.push(`${His} maternal <span class="lightgreen">grandmother is ${V.slaves[mmi].slaveName}.</span>`);
						}
						if (jsDef(mfi)) {
							r.push(`${His} paternal <span class="lightgreen">grandmother is ${V.slaves[mfi].slaveName}.</span>`);
						}
					}
					if ((jsDef(fmi)) && (jsDef(ffi)) && fmi === ffi) {
						r.push(`${His} sole <span class="lightgreen">grandfather is ${V.slaves[ffi].slaveName}.</span>`);
					} else {
						if (jsDef(fmi)) {
							r.push(`${His} maternal <span class="lightgreen">grandfather is ${V.slaves[fmi].slaveName}.</span>`);
						}
						if (ffi) {
							r.push(`${His} paternal <span class="lightgreen">grandfather is ${V.slaves[ffi].slaveName}.</span>`);
						}
					}
				}
			}

			/* PC grandparents - determines if the current slave is your grandparent */
			const pcMother = getSlave(V.PC.mother);
			const pcFather = getSlave(V.PC.father);
			if (jsDef(pcMother)) {
				if ((jsDef(pcFather)) && pcMother === pcFather) {
					if (slave.ID === pcMother.mother && slave.ID === pcFather.father) {
						r.push(`${He} is <span class="lightgreen">your sole grandparent.</span> ${He} impregnated ${himself} with your sole parent ${pcMother.slaveName} who in turn impregnated themselves with you.`);
					} else if (slave.ID === pcMother.mother) {
						r.push(`${He} is <span class="lightgreen">your sole grandmother.</span> ${He} gave birth to ${pcMother.slaveName} who in turn impregnated themselves with you.`);
					} else if (slave.ID === pcFather.father) {
						r.push(`${He} is <span class="lightgreen">your sole grandfather.</span> ${He} fathered ${pcFather.slaveName} who in turn impregnated themselves with you.`);
					}
				} else if ((jsDef(pcFather)) && slave.ID === pcMother.mother && slave.ID === pcFather.mother) {
					r.push(`${He} is <span class="lightgreen">your sole grandmother.</span> ${He} gave birth to both of your parents, ${pcMother.slaveName} and ${pcFather.slaveName}.`);
				} else if ((jsDef(pcFather)) && slave.ID === pcMother.father && slave.ID === pcFather.father) {
					r.push(`${He} is <span class="lightgreen">your sole grandfather.</span> ${He} fathered both of your parents, ${pcFather.slaveName} and ${pcMother.slaveName}.`);
				} else if (slave.ID === pcMother.mother) {
					r.push(`${He} is <span class="lightgreen">your maternal grandmother.</span>`);
				} else if (slave.ID === pcMother.father) {
					r.push(`${He} is <span class="lightgreen">your maternal grandfather.</span>`);
				}
			} else if (jsDef(pcFather)) {
				if (slave.ID === pcFather.mother) {
					r.push(`${He} is <span class="lightgreen">your paternal grandmother.</span>`);
				} else if (slave.ID === pcFather.father) {
					r.push(`${He} is <span class="lightgreen">your paternal grandfather.</span>`);
				}
			}

			/* grandchild - determines how many grandchildren the current slave has */
			children = V.slaves.filter((s) => isGrandparentP(s, slave));
			if (children.length > 0) {
				r.push(`${He} has`);
				if (children.length > 2) {
					r.push(`<span class="lightgreen">many grandchildren, ${slaveListToText(children)}, amongst your slaves.</span>`);
				} else if (children.length > 1) {
					r.push(`<span class="lightgreen">two grandchildren, ${slaveListToText(children)}, amongst your slaves.</span>`);
				} else {
					r.push(`a <span class="lightgreen">grandchild, ${slaveListToText(children)}, as your slave.</span>`);
				}
			}

			/* PC aunt and uncle - determines how many aunts and uncles you have */
			if (isAunt(V.PC, slave)) {
				const {m: uncles, f: aunts} = splitBySex(V.slaves.filter((s) => s.ID !== slave.ID && isAunt(V.PC, s)));

				r.push(`${He} is`);
				if (slave.genes === "XX") {
					if (aunts.length > 0) {
						r.push(`<span class="lightgreen">your aunt along with ${slaveListToText(aunts)}.</span>`);
					} else {
						r.push(`<span class="lightgreen">your aunt.</span>`);
					}
				} else {
					if (uncles.length > 0) {
						r.push(`<span class="lightgreen">your uncle along with ${slaveListToText(uncles)}.</span>`);
					} else {
						r.push(`<span class="lightgreen">your uncle.</span>`);
					}
				}
			}

			/* aunt and uncle - determines how many aunts and uncles a slave has*/
			const {m: uncles, f: aunts} = splitBySex(V.slaves.filter((s) => isAunt(slave, s)));

			if (aunts.length > 0) {
				r.push(`${He} has`);
				if (aunts.length > 2) {
					r.push(`<span class="lightgreen">many aunts, ${slaveListToText(aunts)}.</span>`);
				} else if (aunts.length > 1) {
					r.push(`<span class="lightgreen">two aunts, ${slaveListToText(aunts)}.</span>`);
				} else {
					r.push(`<span class="lightgreen">an aunt, ${slaveListToText(aunts)}.</span>`);
				}
			}
			if (uncles.length > 0) {
				r.push(`${He} has`);
				if (uncles.length > 2) {
					r.push(`<span class="lightgreen">many uncles, ${slaveListToText(uncles)}.</span>`);
				} else if (uncles.length > 1) {
					r.push(`<span class="lightgreen">two uncles, ${slaveListToText(uncles)}.</span>`);
				} else {
					r.push(`<span class="lightgreen">an uncle, ${slaveListToText(uncles)}.</span>`);
				}
			}

			/* PC niece and nephew - determines how many nieces and nephews you have*/
			if (isAunt(slave, V.PC)) {
				const {m: nephews, f: nieces} = splitBySex(V.slaves.filter((s) => s.ID !== slave.ID && isAunt(s, V.PC)));

				r.push(`${He} is`);
				if (slave.genes === "XX") {
					if (nieces.length > 0) {
						r.push(`<span class="lightgreen">your niece along with ${slaveListToText(nieces)}.</span>`);
					} else {
						r.push(`<span class="lightgreen">your niece.</span>`);
					}
				} else {
					if (nephews.length > 0) {
						r.push(`<span class="lightgreen">your nephew along with ${slaveListToText(nephews)}.</span>`);
					} else {
						r.push(`<span class="lightgreen">your nephew.</span>`);
					}
				}
			}

			/* niece and nephew - determines how many nieces and nephews a slave has*/
			const {m: nephews, f: nieces} = splitBySex(V.slaves.filter((s) => isAunt(s, slave)));

			if (nieces.length > 0) {
				r.push(`${He} has`);
				if (nieces.length > 2) {
					r.push(`<span class="lightgreen">many nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
				} else if (nieces.length > 1) {
					r.push(`<span class="lightgreen">two nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
				} else {
					r.push(`<span class="lightgreen">a niece, ${slaveListToText(nieces)}, who is your slave.</span>`);
				}
			}
			if (nephews.length > 0) {
				r.push(`${He} has`);
				if (nephews.length > 2) {
					r.push(`<span class="lightgreen">many nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
				} else if (nephews.length > 1) {
					r.push(`<span class="lightgreen">two nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
				} else {
					r.push(`<span class="lightgreen">a nephew, ${slaveListToText(nephews)}, who is your slave.</span>`);
				}
			}
		} /* end distant relatives toggle check */

		let	twins = [];
		let sisters = [];
		let brothers = [];
		let halfSisters = [];
		let halfBrothers = [];
		let cousins = [];

		for (const s of V.slaves) {
			let sisterCheck = areSisters(s, slave);
			if (sisterCheck === 1) {
				twins.push(s);
			}
			if (sisterCheck === 2) {
				(s.genes === "XX" ? sisters : brothers).push(s);
			}
			if (sisterCheck === 3) {
				(s.genes === "XX" ? halfSisters : halfBrothers).push(s);
			}
			if (V.showDistantRelatives) {
				if (areCousins(s, slave)) {
					cousins.push(s);
				}
			}
		}

		/* PC twin - determines how many twins you have */
		if (areSisters(slave, V.PC) === 1) {
			r.push(He);
			if (twins.length > 1) {
				r.push(`<span class="lightgreen">shared a cramped womb with you, ${slaveListToText(twins)}.</span>`);
			} else if (twins.length > 0) {
				r.push(`is <span class="lightgreen">your twin along with ${slaveListToText(twins)}.</span>`);
			} else {
				r.push(`is <span class="lightgreen">your twin.</span>`);
			}
			twins = []; // clear it so we don't output it a second time
		}

		/* PC sister - determines how many sisters you have*/
		if (areSisters(slave, V.PC) === 2 && slave.genes === "XX") {
			r.push(`${He} is`);
			if (sisters.length > 0) {
				r.push(`<span class="lightgreen">your ${sister} along with ${slaveListToText(sisters)}.</span>`);
			} else {
				r.push(`<span class="lightgreen">your ${sister}.</span>`);
			}
			sisters = []; // clear it so we don't output it a second time
		}

		/* PC brother - determines how many brothers you have*/
		if (areSisters(slave, V.PC) === 2 && slave.genes === "XY") {
			r.push(`${He} is`);
			if (brothers.length > 0) {
				r.push(`<span class="lightgreen">your ${sister} along with ${slaveListToText(brothers)}.</span>`);
			} else {
				r.push(`<span class="lightgreen">your ${sister}.</span>`);
			}
			brothers = []; // clear it so we don't output it a second time
		}

		/* PC half-sister - determines how many half-sisters you have*/
		if (areSisters(slave, V.PC) === 3 && slave.genes === "XX") {
			r.push(`${He} is`);
			if (halfSisters.length > 0) {
				r.push(`<span class="lightgreen">is your half-${sister} along with ${slaveListToText(halfSisters)}.</span>`);
			} else {
				r.push(`<span class="lightgreen">your half-${sister}.</span>`);
			}
			halfSisters = []; // clear it so we don't output it a second time
		}

		/* PC half-brother - determines how many half-brothers you have*/
		if (areSisters(slave, V.PC) === 3 && slave.genes === "XY") {
			r.push(`${He} is`);
			if (halfBrothers.length > 0) {
				r.push(`<span class="lightgreen">is your half-${sister} along with ${slaveListToText(halfBrothers)})>>.</span>`);
			} else {
				r.push(`<span class="lightgreen">your half-${sister}.</span>`);
			}
			halfBrothers = []; // clear it so we don't output it a second time
		}

		/* twins? - determines how many twins a slave has*/
		if (twins.length > 0) {
			r.push(`${He}`);
			if (twins.length > 2) {
				r.push(`<span class="lightgreen">shared a cramped womb with ${slaveListToText(twins)}.</span>`);
			} else if (twins.length > 1) {
				r.push(`is <span class="lightgreen">one of a set of triplets; ${slaveListToText(twins)}</span> complete the trio.`);
			} else {
				r.push(`is <span class="lightgreen">twins with ${twins[0].slaveName}.</span>`);
			}
		}

		/* sister - determines how many sisters a slave has*/
		if (sisters.length > 0) {
			const sister2 = getPronouns(sisters[0]).sister;
			if (sisters.length > 1) {
				r.push(`<span class="lightgreen">${slaveListToText(sisters)} are ${his} ${sister2}s.</span>`);
			} else {
				r.push(`<span class="lightgreen">${sisters[0].slaveName} is ${his} ${sister2}.</span>`);
			}
		}

		/* brother - determines how many brothers a slave has*/
		if (brothers.length > 0) {
			const sister2 = getPronouns(brothers[0]).sister;
			if (brothers.length > 1) {
				r.push(`<span class="lightgreen">${slaveListToText(brothers)} are ${his} ${sister2}s.</span>`);
			} else {
				r.push(`<span class="lightgreen">${brothers[0].slaveName} is ${his} ${sister2}.</span>`);
			}
		}

		/* half-sister - determines how many half-sisters a slave has*/
		if (halfSisters.length > 0) {
			const sister2 = getPronouns(halfSisters[0]).sister;
			if (halfSisters.length > 1) {
				r.push(`<span class="lightgreen">${slaveListToText(halfSisters)} are half-${sister2}s to ${him}.</span>`);
			} else {
				r.push(`<span class="lightgreen">${halfSisters[0].slaveName} is a half-${sister2} to ${him}.</span>`);
			}
		}

		/* half-brother - determines how many half-brothers a slave has*/
		if (halfBrothers.length > 0) {
			const sister2 = getPronouns(halfBrothers[0]).sister;
			if (halfBrothers.length > 1) {
				r.push(`<span class="lightgreen">${slaveListToText(halfBrothers)} are half-${sister2}s to ${him}.</span>`);
			} else if (halfBrothers.length > 0) {
				r.push(`<span class="lightgreen">${halfBrothers[0].slaveName} is a half-${sister2} to ${him}.</span>`);
			}
		}

		if (V.showDistantRelatives) {
			/* PC cousin - determines how many cousins you have*/
			if (areCousins(slave, V.PC)) {
				const PCcousins = V.slaves.filter((s) => s.ID !== slave.ID && areCousins(V.PC, s));
				r.push(`${He} is`);
				if (PCcousins.length > 0) {
					r.push(`<span class="lightgreen">your cousin along with ${slaveListToText(PCcousins)}.</span>`);
				} else {
					r.push(`<span class="lightgreen">your cousin.</span>`);
				}
			}

			/* cousin - determines how many cousins a slave has*/
			if (cousins.length > 1) {
				r.push(`<span class="lightgreen">${slaveListToText(cousins)} are cousins to ${him}.</span>`);
			} else if (cousins.length > 0) {
				r.push(`<span class="lightgreen">${cousins[0].slaveName} is a cousin to ${him}.</span>`);
			}
		}

		if (slave.clone) {
			r.push(`${He} is`);
			if (slave.cloneID === -1) {
				r.push(`your clone.`);
			} else {
				r.push(`a clone of ${slave.clone}.`);
			}
		}

		if (V.cheatMode) {
			r.push(`${He} has ${numberWithPlural(slave.sisters, "sister")} and ${numberWithPlural(slave.daughters, "daughter")}.`);
		}

		return r.join(" ");
	}

	/** Describe the members of the PC's family.
	 * @returns {string}
	 */
	function PCFamilySummary() {
		let r = [];

		r.push(`<br>Your family records show that:`);

		/* Player parents, lists both your parents, or just one. */
		let parents = [];
		if (V.showMissingSlaves) {
			if (V.PC.mother in V.missingTable) {
				parents.push(V.missingTable[V.PC.mother]);
			}
			if (V.PC.father in V.missingTable && (V.PC.father !== V.PC.mother)) {
				parents.push(V.missingTable[V.PC.father]);
			}
		}
		parents.concat(V.slaves.filter((s) => isParentP(V.PC, s)));

		if (parents.length > 1) {
			r.push(`<br>Your parents are <span class="lightgreen">${knownSlave(parents[0].ID)} and ${knownSlave(parents[1].ID)}.</span>`);
		} else if (parents.length > 0) {
			if (V.PC.father === V.PC.mother) {
				/* apparently we don't keep pronoun records in the missing parents table??? */
				const himself = jsDef(parents[0].pronoun) ? getPronouns(parents[0]).himself : "herself";
				r.push(`<br>Your parent is <span class="lightgreen">${knownSlave(parents[0].ID)},</span> who impregnated ${himself} with you.`);
			} else {
				r.push(`<br>You know one of your parents, <span class="lightgreen">${knownSlave(parents[0].ID)}.</span>`);
			}
		}

		/* Player aunts and uncles */
		if (V.showDistantRelatives) {
			const {m: uncles, f: aunts} = splitBySex(V.slaves.filter((s) => isAunt(V.PC, s)));

			if (aunts.length > 0) {
				r.push(`<br>You have`);
				if (aunts.length > 2) {
					r.push(`<span class="lightgreen">many aunts, ${slaveListToText(aunts)}.</span>`);
				} else if (aunts.length > 1) {
					r.push(`<span class="lightgreen">two aunts, ${slaveListToText(aunts)}.</span>`);
				} else {
					r.push(`<span class="lightgreen">an aunt, ${slaveListToText(aunts)}.</span>`);
				}
			}
			if (uncles.length > 0) {
				r.push(`<br>You have`);
				if (uncles.length > 2) {
					r.push(`<span class="lightgreen">many uncles, ${slaveListToText(uncles)}.</span>`);
				} else if (uncles.length > 1) {
					r.push(`<span class="lightgreen">two uncles, ${slaveListToText(uncles)}.</span>`);
				} else {
					r.push(`<span class="lightgreen">an uncle, ${slaveListToText(uncles)}.</span>`);
				}
			}
		}

		let	twins = [];
		let sisters = [];
		let brothers = [];
		let halfSisters = [];
		let halfBrothers = [];
		let cousins = [];

		for (const s of V.slaves) {
			let sisterCheck = areSisters(s, V.PC);
			if (sisterCheck === 1) {
				twins.push(s);
			}
			if (sisterCheck === 2) {
				(s.genes === "XX" ? sisters : brothers).push(s);
			}
			if (sisterCheck === 3) {
				(s.genes === "XX" ? halfSisters : halfBrothers).push(s);
			}
			if (V.showDistantRelatives) {
				if (areCousins(s, V.PC)) {
					cousins.push(s);
				}
			}
		}

		if (twins.length > 1) {
			r.push(`<br>You are <span class="lightgreen">twins with ${slaveListToText(twins)}.</span>`);
		} else if (twins.length > 0) {
			r.push(`<br>Your twin is <span class="lightgreen">${twins[0].slaveName}.</span>`);
		}

		if (sisters.length > 1) {
			r.push(`<br><span class="lightgreen">${slaveListToText(sisters)}</span> are your sisters.`);
		} else if (sisters.length > 0) {
			const {sister} = getPronouns(sisters[0]);
			r.push(`<br>Your ${sister} is <span class="lightgreen">${sisters[0].slaveName}.</span>`);
		}

		if (brothers.length > 1) {
			r.push(`<br><span class="lightgreen">${slaveListToText(brothers)}</span> are your brothers.`);
		} else if (brothers.length > 0) {
			const {sister} = getPronouns(brothers[0]);
			r.push(`<br>Your ${sister} is <span class="lightgreen">${brothers[0].slaveName}.</span>`);
		}

		if (halfSisters.length > 1) {
			r.push(`<br><span class="lightgreen">${slaveListToText(halfSisters)}</span> are your half-sisters.`);
		} else if (halfSisters.length > 0) {
			const {sister} = getPronouns(halfSisters[0]);
			r.push(`<br>You have one half-${sister}, <span class="lightgreen">${halfSisters[0].slaveName}.</span>`);
		}

		if (halfBrothers.length > 1) {
			r.push(`<br><span class="lightgreen">${slaveListToText(halfBrothers)}</span> are your half-brothers.`);
		} else if (halfBrothers.length > 0) {
			const {sister} = getPronouns(halfBrothers[0]);
			r.push(`<br>You have one half-${sister}, <span class="lightgreen">${halfBrothers[0].slaveName}.</span>`);
		}

		if (V.showDistantRelatives) {
			if (cousins.length > 1) {
				r.push(`<br><span class="lightgreen">${slaveListToText(cousins)}</span> are your cousins.`);
			} else if (cousins.length > 0) {
				r.push(`<br>You have one cousin, <span class="lightgreen">${cousins[0].slaveName}.</span>`);
			}
		}

		/* Player nieces and nephews */
		if (V.showDistantRelatives) {
			const {m: nephews, f: nieces} = splitBySex(V.slaves.filter((s) => isAunt(s, V.PC)));

			if (nieces.length > 0) {
				r.push(`<br>You have`);
				if (nieces.length > 2) {
					r.push(`<span class="lightgreen">many nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
				} else if (nieces.length > 1) {
					r.push(`<span class="lightgreen">two nieces, ${slaveListToText(nieces)}, who are your slaves.</span>`);
				} else {
					r.push(`<span class="lightgreen">a niece, ${slaveListToText(nieces)}, who is your slave.</span>`);
				}
			}
			if (nephews.length > 0) {
				r.push(`<br>You have`);
				if (nephews.length > 2) {
					r.push(`<span class="lightgreen">many nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
				} else if (nephews.length > 1) {
					r.push(`<span class="lightgreen">two nephews, ${slaveListToText(nephews)}, who are your slaves.</span>`);
				} else {
					r.push(`<span class="lightgreen">a nephew, ${slaveListToText(nephews)}, who is your slave.</span>`);
				}
			}
		}

		/* Player is Father, lists children you fathered */
		let children = V.slaves.filter((s) => s.father === V.PC.ID);
		if (children.length > 0) {
			r.push(`<br>You fathered ${num(children.length)} of your slaves, <span class="lightgreen">${slaveListToText(children)}.</span>`);
		}

		/* Player is Mother, lists birthed children */
		children = V.slaves.filter((s) => s.mother === V.PC.ID);
		if (children.length > 0) {
			r.push(`<br>You gave birth to ${num(children.length)} of your slaves, <span class="lightgreen">${slaveListToText(children)}.</span>`);
		}

		/* Player is grandparent */
		if (V.showDistantRelatives) {
			children = V.slaves.filter((s) => isGrandparentP(s, V.PC));
			if (children.length > 0) {
				r.push(`<br>You have ${num(children.length)} grandchildren as your slaves, <span class="lightgreen">${slaveListToText(children)}.</span>`);
			}
		}

		if (V.cheatMode) {
			r.push(`<br>You have ${numberWithPlural(V.PC.sisters, "sister")} and ${numberWithPlural(V.PC.daughters, "daughter")}.`);
		}

		return r.join(" ");
	}

	return familySummary;
})();

src/descriptions/familySummaries.js