diff --git a/js/rulesAssistant/conditionEvaluation.js b/js/rulesAssistant/conditionEvaluation.js
index ff4027c6ffa1deea680e65b33094b05a8eb7feba..82d7dfc6976184bcd37d5678def1fe6b7f0817e3 100644
--- a/js/rulesAssistant/conditionEvaluation.js
+++ b/js/rulesAssistant/conditionEvaluation.js
@@ -235,6 +235,10 @@ App.RA.Activation.populateGetters = function() {
 		name: "Is Fertile?", description: "Whether or not the slave is fertile.",
 		val: c => isFertile(c.slave)
 	});
+	gm.addBoolean("isvirile", {
+		name: "Is Virile?", description: "Whether or not the slave is virile, has fertile sperm.",
+		val: c => isVirile(c.slave)
+	});
 	gm.addBoolean("isamputee", {
 		name: "Is Amputee?", description: "Whether or not the slave has no limbs.",
 		val: c => isAmputee(c.slave)
diff --git a/src/events/RESS/languageLesson.js b/src/events/RESS/languageLesson.js
index 72d0b296228ccad3256eb9da71625677c0bdee0e..6d85ce53514244c7be39d93ee2f706bf01ef9169 100644
--- a/src/events/RESS/languageLesson.js
+++ b/src/events/RESS/languageLesson.js
@@ -182,7 +182,7 @@ App.Events.RESSLanguageLesson = class RESSLanguageLesson extends App.Events.Base
 					? new App.Events.Result(`Cover some anal vocabulary, and make sure ${he} doesn't forget it`, anal, eventSlave.anus === 0 ? `This option will take ${his} anal virginity` : null)
 					: new App.Events.Result(),
 				canPenetrate(eventSlave) && (eventSlave.toyHole === "dick" || V.policies.sexualOpenness === 1)
-					? new App.Events.Result(`Cover some extra curricular vocabulary, and see if ${he} retains it`, fuckMe, `This option will penetrate you`)
+					? new App.Events.Result(`Cover some extra curricular vocabulary, and see if ${he} retains it`, fuckMe, PCPenetrationWarning())
 					: new App.Events.Result(),
 			]);
 
diff --git a/src/events/RESS/muscles.js b/src/events/RESS/muscles.js
index dfa6ba8bb605dca52973cd1ae912a67065a1e868..54ded560ae42a582489aa9a4914f28691d54bac6 100644
--- a/src/events/RESS/muscles.js
+++ b/src/events/RESS/muscles.js
@@ -57,7 +57,7 @@ App.Events.RESSMuscles = class RESSMuscles extends App.Events.BaseEvent {
 			new App.Events.Result(`Reward ${him} for ${his} gains`, reward, fuckNote()),
 			new App.Events.Result(`Take advantage of ${his} gains with a powerfuck`, powerfuck, fuckNote()),
 			((eventSlave.toyHole === "dick" || V.policies.sexualOpenness === 1) && canPenetrate(eventSlave) && eventSlave.belly < 100000)
-				? new App.Events.Result(`See if ${he} can put those gains to good use`, penetration, "This option will penetrate you")
+				? new App.Events.Result(`See if ${he} can put those gains to good use`, penetration, PCPenetrationWarning())
 				: new App.Events.Result(),
 			new App.Events.Result(`Compliment ${his} gains and send ${him} on ${his} way`, compliment),
 		]);
diff --git a/src/events/RESS/plimbHelp.js b/src/events/RESS/plimbHelp.js
index ed379411f9af0b9fe7bb1b9550184ab0c2f06177..bc1574f880b42c913286c3df9d222d8ffee3e7b6 100644
--- a/src/events/RESS/plimbHelp.js
+++ b/src/events/RESS/plimbHelp.js
@@ -80,7 +80,7 @@ App.Events.RESSPlimbHelp = class RESSPlimbHelp extends App.Events.BaseEvent {
 				? new App.Events.Result(`Fuck ${him} before you help ${him}`, fuck, ((eventSlave.vagina === 0 && canDoVaginal(eventSlave)) || (eventSlave.anus === 0 && canDoAnal(eventSlave))) && V.PC.dick !== 0 ? `This option will take ${his} virginity` : null)
 				: new App.Events.Result(),
 			(canPenetrate(eventSlave) && (V.PC.vagina > 0 || V.PC.anus > 0) && (eventSlave.toyHole === "dick" || V.policies.sexualOpenness === 1))
-				? new App.Events.Result(`Ride ${him} before you help ${him}`, ride, `This option will penetrate you`)
+				? new App.Events.Result(`Ride ${him} before you help ${him}`, ride, (V.PC.vagina > 0 ? PCPenetrationWarning("vaginal") : PCPenetrationWarning("anal")))
 				: new App.Events.Result(),
 		]);
 
diff --git a/src/events/RESS/review/shiftDoorframe.js b/src/events/RESS/review/shiftDoorframe.js
index b8f2cc604728b68f05d15bca243193fdce1e77dd..a4887e103e689e6d397d027166f776ec3b7da36e 100644
--- a/src/events/RESS/review/shiftDoorframe.js
+++ b/src/events/RESS/review/shiftDoorframe.js
@@ -243,7 +243,7 @@ App.Events.RESSShiftDoorframe = class RESSShiftDoorframe extends App.Events.Base
 			choices.push(new App.Events.Result(`Pound that ass`, poundButt, (eventSlave.anus === 0 && canDoAnal(eventSlave)) ? `This option will take ${his} anal virginity` : null));
 		}
 		if ((eventSlave.toyHole === "dick" || V.policies.sexualOpenness === 1) && canPenetrate(eventSlave)) {
-			choices.push(new App.Events.Result(`Invite ${him} 'in'`, invitation, `This option will penetrate you${V.PC.vagina === 0 ? ". This option will take your virginity" : ""}${V.PC.anus === 0 && V.PC.vagina < 0? ". This option will take your anal virginity" : ""}`)); // TODO: This response needs to be reviewed (or gated) after PC body is implemented
+			choices.push(new App.Events.Result(`Invite ${him} 'in'`, invitation, PCPenetrationWarning())); // TODO: This response needs to be reviewed (or gated) after PC body is implemented
 		}
 		App.Events.addResponses(node, choices);
 
diff --git a/src/events/eventUtils.js b/src/events/eventUtils.js
index c3245d1ea5014fa985ba628de0604478113edcf9..6c902c9e2bc6dc8c65a05d8766f2f4526bf401af 100644
--- a/src/events/eventUtils.js
+++ b/src/events/eventUtils.js
@@ -221,7 +221,7 @@ App.Events.Result = class {
 	 * @param {string} [text] - the link text for the response
 	 * @param {resultHandler} [handler] - the function to call to generate the result when the link is clicked
 	 * @param {string|HTMLElement|DocumentFragment} [note] - a note to provide alongside the link (for example, a cost or virginity loss warning)
-	 * To mark an option as disabled, construct the result with only the note. String may NOT contain HTML.
+	 * To mark an option as disabled, construct the result with only the note. String may NOT contain HTML, but a WARNING# tag may be included in the note string to add a warning text ("This is the information note. WARNING# This is a warning text.").
 	 */
 	constructor(text, handler, note) {
 		this.text = text;
@@ -256,7 +256,20 @@ App.Events.Result = class {
 			node.append(" ");
 		}
 		if (this.note) {
-			node.appendChild(App.UI.DOM.makeElement("span", this.note, ["detail"]));
+			if (typeof this.note === "string" && this.note.includes("WARNING#")) {
+				let warning = "";
+				let subnote = "";
+				warning = this.note.substring(this.note.indexOf("WARNING#") + 8);
+				subnote = this.note.substring(0, this.note.indexOf("WARNING#"));
+				if (subnote.length) {
+					node.appendChild(App.UI.DOM.makeElement("span", subnote, ["detail"]));
+				}
+				if (warning.length) {
+					node.appendChild(App.UI.DOM.makeElement("span", warning, ["detail", "warning"]));
+				}
+			} else {
+				node.appendChild(App.UI.DOM.makeElement("span", this.note, ["detail"]));
+			}
 			wrote = true;
 		}
 		return wrote;
diff --git a/src/js/utilsPC.js b/src/js/utilsPC.js
index 2a3eb99e4361bfb83fcf58247d6e4206335adbf7..9e88a1c2bfc351b6aaab597580c10f91743f9dfa 100644
--- a/src/js/utilsPC.js
+++ b/src/js/utilsPC.js
@@ -1057,3 +1057,81 @@ globalThis.PCCareerCategory = function(career = V.PC.career) {
 	console.log(`"${career}" not found in App.Data.player.career`);
 	return career;
 };
+
+/** Returns warning text for the player being penetrated and also warns about loosing virginities.
+ * @param {string} [holes = "vaginal first"] (vaginal | anal | both | either | vaginal first)
+ * @param {boolean} [escape = false] (true | false) is there a way to escape the penetration or it is unavoidable
+ * @returns {string}
+ */
+globalThis.PCPenetrationWarning = function(holes = "vaginal first", escape = false) {
+	let targets = [];
+	let virgins = [];
+	let result = "";
+	let action = escape ? "can" : "will";
+	if (holes === "vaginal" || holes === "both" || holes === "either" || holes === "vaginal first") {
+		if (V.PC.vagina >= 0) {
+			targets.push("vagina");
+			if (V.PC.vagina === 0) {
+				virgins.push("vaginal");
+			}
+		}
+	}
+	if (holes === "anal" || holes === "both" || holes === "either" || (holes === "vaginal first" && targets.length === 0)) {
+		if (V.PC.anus >= 0) {
+			targets.push("anus");
+			if (V.PC.anus === 0) {
+				virgins.push("anal");
+			}
+		}
+	}
+	if (targets.length === 0) {
+		return result;
+	} else if (targets.length === 2) {
+		if (holes === "either") {
+			result = `This option ${action} penetrate your vagina or anus.`;
+		} else {
+			result = `This option ${action} penetrate your vagina and anus.`;
+		}
+	} else {
+		result = `This option ${action} penetrate your ${targets[0]}.`;
+	}
+	if (virgins.length === 0) {
+		return result;
+	} else if (virgins.length === 2) {
+		if (holes === "either") {
+			result += `WARNING# This option ${action} take your vaginal or anal virginities.`;
+		} else {
+			result += `WARNING# This option ${action} take your vaginal and anal virginities.`;
+		}
+	} else {
+		result += `WARNING# This option ${action} take your ${virgins[0]} virginity.`;
+	}
+	return result;
+}
+
+/** Returns "true" if the player can be receptive to penetration, even if the sexualOpenness policy is not adopted. This function should only be used to offer options to the player, it does not imply true willingness.
+ * @param {any} [penetrator = null]  If a slave is passed as an argument, it also takes into account if slave.toyHole is "dick".
+ * @returns {boolean}
+*/
+globalThis.isPlayerReceptive = function(penetrator = null) {
+	if (penetrator && penetrator.toyHole && penetrator.toyHole === "dick") {
+		return true; // if argument is passed, it is a slave and toyHole is dick
+	} else if (V.policies.sexualOpenness === 1) {
+		return true; // penetrative campaign
+	} else if (V.PC.drugs.includes("fertility") || V.PC.diet.includes("fertility") || V.PC.refreshment.includes("fertility")) {
+		return true; // PC wants to be pregnant, even if not fertile
+	} else if (V.slaves.filter(s => s.toyHole === "dick").length * 4 > V.slaves.filter(s => s.dick > 0).length || V.slaves.filter(s => s.toyHole === "dick").length * 10 > V.slaves.length || V.slaves.filter(s => s.toyHole === "dick").length >= 8) {
+		return true; // at least 8 slaves, or 25% of the slaves with penises, or 10% of all the slaves, have dick as toyHole
+	} else if (V.PC.counter.anal * 2 > V.week) {
+		return true; // player is used to anal penetration
+	/** } else if (V.PC.counter.vaginal * 2 V.week) {
+		return true; // vaginal isn't only increased by penetration, but it's also increased by tribbing and cunnilingus */
+	} else if (isPlayerLusting() && (V.PC.anus > 0 || V.PC.vagina > 0)) {
+		return true; // player needs sex and has some penetrative experience
+	} else if (V.PC.preg > V.PC.pregData.normalBirth / 2 && V.PC.pregMood === 2) {
+		return true; // player's pregnancy increases libido
+	} else if (isFertile(V.PC) && V.PC.forcedFertDrugs > 0) {
+		return true; // forcedFertDrugs influence the behavior of the player, who unconsciously wants to be fertilized
+	}
+	return false;
+}
\ No newline at end of file