From b60aa493db17422b0439e3abb1854b3f4698f41e Mon Sep 17 00:00:00 2001
From: ezsh <ezsh.junk@gmail.com>
Date: Tue, 31 May 2022 15:15:07 +0200
Subject: [PATCH] RA: add condition to test slave phenotype for sexual
 categorization

---
 js/rulesAssistant/conditionEvaluation.js |  8 +++++-
 src/futureSocieties/futureSociety.js     | 11 ++++++++
 src/js/statsChecker/statsChecker.js      | 36 +++++++++++++-----------
 src/js/utilsAssessSlave.js               |  4 +--
 src/js/utilsSlave.js                     | 14 +++++++++
 5 files changed, 54 insertions(+), 19 deletions(-)

diff --git a/js/rulesAssistant/conditionEvaluation.js b/js/rulesAssistant/conditionEvaluation.js
index c2c2afca4d6..197e137736b 100644
--- a/js/rulesAssistant/conditionEvaluation.js
+++ b/js/rulesAssistant/conditionEvaluation.js
@@ -656,9 +656,15 @@ App.RA.Activation.populateGetters = function() {
 	// Strings
 	gm.addString("label", {name: "Label", description: "Assigned Label", val: c => c.slave.custom.label});
 	gm.addString("genes", {
-		name: "Sex", description: "Genetic sex: Male: XX, Female: XY",
+		name: "Genetic sex", description: "Genetic sex: Female: XX, Male: XY",
 		val: c => c.slave.genes
 	});
+	gm.addString("phenotypesex", {
+		name: "Phenotype sex",
+		description: "A three-character string that encodes state of sexual organs" +
+			" as female('X'), male('Y'), both ('H'), or absent ('-'): vagina/dick, ovaries/balls, tits",
+		val: c => phenotypeSex(c.slave)
+	});
 	gm.addString("fetish", {
 		name: "Fetish",
 		description: "One of 'buttslut', 'cumslut', 'masochist', 'sadist', 'dom', 'submissive', 'boobs', " +
diff --git a/src/futureSocieties/futureSociety.js b/src/futureSocieties/futureSociety.js
index ef28cb60a6c..a6245aa4d73 100644
--- a/src/futureSocieties/futureSociety.js
+++ b/src/futureSocieties/futureSociety.js
@@ -28,6 +28,7 @@ globalThis.FutureSocieties = (function() {
 		HighestDecoration: FSHighestDecoration,
 		arcSupport: arcSupport,
 		researchAvailable,
+		isActive,
 	};
 
 	/** get the list of FSes active for a particular arcology
@@ -810,4 +811,14 @@ globalThis.FutureSocieties = (function() {
 	function researchAvailable(fs, arcology) {
 		return (arcology || V.arcologies[0])[`FS${fs}Research`] === 1;
 	}
+
+	/**
+	 * Checks if the given FS active (i.e. not "unset")
+	 * @param {FC.FutureSociety} fs
+	 * @param {FC.ArcologyState} [arcology] Arcology to test, defaults to the PC's arcology
+	 * @returns {boolean}
+	 */
+	function isActive(fs, arcology) {
+		return (arcology || V.arcologies[0])[fs] !== "unset";
+	}
 })();
diff --git a/src/js/statsChecker/statsChecker.js b/src/js/statsChecker/statsChecker.js
index 781a6287e8d..c1c4133cd75 100644
--- a/src/js/statsChecker/statsChecker.js
+++ b/src/js/statsChecker/statsChecker.js
@@ -628,7 +628,7 @@ globalThis.isFertile = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState | App.Entity.PlayerState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.canAchieveErection = function(slave) {
@@ -653,7 +653,7 @@ globalThis.canAchieveErection = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.canPenetrate = function(slave) {
@@ -674,7 +674,7 @@ globalThis.canPenetrate = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.canSee = function(slave) {
@@ -686,7 +686,7 @@ globalThis.canSee = function(slave) {
 
 /**
  *
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.canSeePerfectly = function(slave) {
@@ -705,7 +705,7 @@ globalThis.canSeePerfectly = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.canHear = function(slave) {
@@ -716,7 +716,7 @@ globalThis.canHear = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.canSmell = function(slave) {
@@ -727,7 +727,7 @@ globalThis.canSmell = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.canTaste = function(slave) {
@@ -738,7 +738,7 @@ globalThis.canTaste = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.canHold = function(slave) {
@@ -751,7 +751,7 @@ globalThis.canHold = function(slave) {
 };
 
 /** If a slave can walk, she can move and stand.
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.canWalk = function(slave) {
@@ -780,7 +780,7 @@ globalThis.canWalk = function(slave) {
 };
 
 /** If a slave can stand, she can move, but not necessarily walk.
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.canStand = function(slave) {
@@ -968,7 +968,7 @@ globalThis.canDoVaginal = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.tooFatSlave = function(slave) {
@@ -987,7 +987,7 @@ globalThis.tooFatSlave = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.tooBigBreasts = function(slave) {
@@ -1006,7 +1006,7 @@ globalThis.tooBigBreasts = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.tooBigBelly = function(slave) {
@@ -1025,7 +1025,7 @@ globalThis.tooBigBelly = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.tooBigBalls = function(slave) {
@@ -1042,7 +1042,7 @@ globalThis.tooBigBalls = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.tooBigDick = function(slave) {
@@ -1059,7 +1059,7 @@ globalThis.tooBigDick = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {boolean}
  */
 globalThis.tooBigButt = function(slave) {
@@ -1131,6 +1131,10 @@ globalThis.canBeReceptrix = function(slave) {
 	);
 };
 
+/**
+ * @param {FC.HumanState} slave
+ * @returns {string}
+ */
 globalThis.milkFlavor = function(slave) {
 	if (slave.milkFlavor === "none") {
 		return ``;
diff --git a/src/js/utilsAssessSlave.js b/src/js/utilsAssessSlave.js
index 39bf59bcf3e..d3233de8c6d 100644
--- a/src/js/utilsAssessSlave.js
+++ b/src/js/utilsAssessSlave.js
@@ -120,7 +120,7 @@ globalThis.maxHeight = function(slave) {
 	if (slave.geneticQuirks.neoteny === 2 && slave.physicalAge > 12) { /* Limit neoteny slaves to 12 year old max height */
 		max = Math.clamp(((Height.mean(slave.nationality, slave.race, slave.genes, 12) * 1.25) + slave.heightImplant * 10), 0, 274);
 	}
-	
+
 	if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2) {
 		max = Math.min(max, 160);
 	}
@@ -249,7 +249,7 @@ globalThis.canMoveToRoom = function(slave) {
 };
 
 /**
- * @param {App.Entity.SlaveState} slave
+ * @param {FC.HumanState} slave
  * @returns {0|1|2|3} 0: No heel boost at all. 1: Pumps, slight boost. 2: High heels. 3: Painfully/extreme high heels
  */
 globalThis.shoeHeelCategory = function(slave) {
diff --git a/src/js/utilsSlave.js b/src/js/utilsSlave.js
index 1b13711a4f9..38f5ca555e7 100644
--- a/src/js/utilsSlave.js
+++ b/src/js/utilsSlave.js
@@ -2548,6 +2548,20 @@ globalThis.SlaveTitle = function(slave) {
 	return r;
 };
 
+/**
+ * Phenotype sex: a three-character string that encodes state of sexual organs
+ * as female('X'), male('Y'), both ('H'), or absent ('-'): vagina/dick, ovaries/balls, tits
+ * @param {FC.HumanState} human
+ * @returns {string}
+ */
+globalThis.phenotypeSex = function(human) {
+	const encode = (haveFemale, haveMale) =>
+		'-XYH'[haveFemale + haveMale * 2];
+	return encode(human.vagina > -1, human.dick > 0) +
+		encode(human.ovaries > 0, human.balls > 0) +
+		encode(human.boobs > 0, false);
+};
+
 /**
  * @param {App.Entity.SlaveState} slave
  */
-- 
GitLab