From f40192d464830e2960f0eb9e0f3393d0e030785e Mon Sep 17 00:00:00 2001
From: PresidentConvert
 <temp-email-for-oauth-presidentconvert@gitlab.localhost>
Date: Tue, 26 Mar 2024 12:26:37 -0700
Subject: [PATCH] Make the effects of surgeries completed through Rules
 Assistant more closely match surgeries initiated manually by the player.

---
 cspell.json                |   3 +-
 src/js/rulesAutosurgery.js | 119 ++++++++++++++++---------------------
 2 files changed, 53 insertions(+), 69 deletions(-)

diff --git a/cspell.json b/cspell.json
index f47a083b498..ea2ee7a071b 100644
--- a/cspell.json
+++ b/cspell.json
@@ -155,7 +155,8 @@
         "xmax",
         "xmin",
         "ymax",
-        "ymin"
+        "ymin",
+		"detaste"
     ],
     "words": [
         "abaya",
diff --git a/src/js/rulesAutosurgery.js b/src/js/rulesAutosurgery.js
index 2102bd078db..2e213325d66 100644
--- a/src/js/rulesAutosurgery.js
+++ b/src/js/rulesAutosurgery.js
@@ -81,13 +81,22 @@ globalThis.rulesAutosurgery = (function() {
 		/**
 		 * Performs an individual surgery procedure
 		 * @param {string} desc
-		 * @param {slaveOperation} proc
+		 * @param {slaveOperation | App.Medicine.Surgery.Procedure} proc
 		 * @param {number} [healthCost=10] normal health cost
 		 */
 		function commitProcedure(desc, proc, healthCost = 10) {
 			if (slave.health.health >= -20) {
 				surgeries.push(desc);
-				proc(slave);
+				if ( (typeof proc) === "function" ) {
+					// @ts-ignore
+					proc(slave);
+				} else {
+					// @ts-ignore
+					const result = App.Medicine.Surgery.apply(proc, V.cheatMode);
+					const [diff, ] = result;
+					App.Utils.Diff.applyDiff(slave, diff);
+				}
+
 				cashX(forceNeg(V.surgeryCost), "slaveSurgery", slave);
 				surgeryDamage(slave, healthCost);
 			}
@@ -101,7 +110,7 @@ globalThis.rulesAutosurgery = (function() {
 		function geneModProcedure(desc, procedure) {
 			if (slave.health.health >= 0) {
 				surgeries.push(desc);
-				const [diff, reaction] = App.Medicine.Surgery.apply(procedure, V.cheatMode === 1);
+				const [diff, ] = App.Medicine.Surgery.apply(procedure, V.cheatMode === 1);
 				App.Utils.Diff.applyDiff(slave, diff);
 			}
 		}
@@ -252,21 +261,21 @@ globalThis.rulesAutosurgery = (function() {
 				commitProcedure(`surgery to blur ${his} right vision`, s => { eyeSurgery(s, "right", "blur"); }, 5);
 			}
 		} else if (slave.heels === 1 && thisSurgery.heels === 1) {
-			commitProcedure(`surgery to repair ${his} tendons`, s => { s.heels = 0; });
+			commitProcedure(`surgery to repair ${his} tendons`, new App.Medicine.Surgery.Procedures.ReplaceTendons(slave));
 		} else if (slave.heels === 0 && thisSurgery.heels === -1) {
-			commitProcedure(`surgery to shorten ${his} tendons`, s => { s.heels = 1; });
+			commitProcedure(`surgery to shorten ${his} tendons`, new App.Medicine.Surgery.Procedures.ShortenTendons(slave));
 		} else if (slave.hears === -1 && thisSurgery.hears === 0) {
-			commitProcedure(`surgery to correct ${his} hearing`, s => { s.hears = 0; });
+			commitProcedure(`surgery to correct ${his} hearing`, new App.Medicine.Surgery.Procedures.EarFix(slave));
 		} else if (slave.hears === 0 && thisSurgery.hears === -1) {
-			commitProcedure(`surgery to muffle ${his} hearing`, s => { s.hears = -1; });
+			commitProcedure(`surgery to muffle ${his} hearing`, new App.Medicine.Surgery.Procedures.EarMuffle(slave));
 		} else if (slave.smells === -1 && thisSurgery.smells === 0) {
-			commitProcedure(`surgery to correct ${his} sense of smell`, s => { s.smells = 0; });
+			commitProcedure(`surgery to correct ${his} sense of smell`, new App.Medicine.Surgery.Procedures.Resmell(slave));
 		} else if (slave.smells === 0 && thisSurgery.smells === -1) {
-			commitProcedure(`surgery to muffle ${his} sense of smell`, s => { s.smells = -1; });
+			commitProcedure(`surgery to muffle ${his} sense of smell`, new App.Medicine.Surgery.Procedures.Desmell(slave));
 		} else if (slave.tastes === -1 && thisSurgery.tastes === 0) {
-			commitProcedure(`surgery to correct ${his} sense of taste`, s => { s.tastes = 0; });
+			commitProcedure(`surgery to correct ${his} sense of taste`, new App.Medicine.Surgery.Procedures.Retaste(slave));
 		} else if (slave.tastes === 0 && thisSurgery.tastes === -1) {
-			commitProcedure(`surgery to muffle ${his} sense of taste`, s => { s.tastes = -1; });
+			commitProcedure(`surgery to muffle ${his} sense of taste`, new App.Medicine.Surgery.Procedures.Detaste(slave));
 		} else if (_.isNumber(thisSurgery.voice) && slave.voice !== thisSurgery.voice) {
 			const voiceDifference = thisSurgery.voice - slave.voice;
 			commitProcedure(`surgery to ${(voiceDifference < 0) ? "lower" : "raise"} ${his} voice`, s => {
@@ -305,26 +314,11 @@ globalThis.rulesAutosurgery = (function() {
 		}
 
 		if (slave.anus > 3 && thisSurgery.cosmetic > 0) {
-			commitProcedure("a restored anus", () => {
-				slave.anus = 3;
-				if (slave.skill.anal > 10) {
-					slave.skill.anal -= 10;
-				}
-			});
+			commitProcedure("a restored anus", new App.Medicine.Surgery.Procedures.RepairAnus(slave));
 		} else if (slave.vagina > 3 && thisSurgery.cosmetic > 0) {
-			commitProcedure("a restored pussy", () => {
-				slave.vagina = 3;
-				if (slave.skill.vaginal > 10) {
-					slave.skill.vaginal -= 10;
-				}
-			});
+			commitProcedure("a restored pussy", new App.Medicine.Surgery.Procedures.RepairVagina(slave));
 		} else if (slave.anus > 0 && V.surgeryUpgrade === 1 && thisSurgery.holes === 2) {
-			commitProcedure("a virgin anus", () => {
-				slave.anus = 0;
-				if (slave.skill.anal > 10) {
-					slave.skill.anal -= 10;
-				}
-			});
+			commitProcedure("a virgin anus", new App.Medicine.Surgery.Procedures.RestoreAnalVirginity(slave));
 		} else if (slave.vagina > 0 && V.surgeryUpgrade === 1 && thisSurgery.holes === 2) {
 			commitProcedure("a virgin pussy", () => {
 				slave.vagina = 0;
@@ -351,13 +345,13 @@ globalThis.rulesAutosurgery = (function() {
 		}
 
 		if (slave.prostate === 2 && thisSurgery.prostate === 1) {
-			commitProcedure(`surgery to remove ${his} prostate implant`, s => { s.prostate = 1; });
+			commitProcedure(`surgery to remove ${his} prostate implant`, new App.Medicine.Surgery.Procedures.RemoveProstate(slave));
 		} else if (slave.prostate === 1 && thisSurgery.prostate === 2) {
-			commitProcedure("a precum production enhancing drug implant", s => { s.prostate = 2; });
+			commitProcedure("a precum production enhancing drug implant", new App.Medicine.Surgery.Procedures.Precum(slave));
 		} else if (slave.balls > 0 && slave.vasectomy === 0 && thisSurgery.vasectomy === true) {
 			commitProcedure("vasectomy", s => { s.vasectomy = 1; });
 		} else if (slave.balls > 0 && slave.vasectomy === 1 && thisSurgery.vasectomy === false) {
-			commitProcedure("undo vasectomy", s => { s.vasectomy = 0; });
+			commitProcedure("undo vasectomy", new App.Medicine.Surgery.Procedures.VasectomyUndo(slave));
 		}
 
 		// Since currently there's no way of changing the autosurgery cost, when replacing, the cost is 300 instead of 600
@@ -409,17 +403,11 @@ globalThis.rulesAutosurgery = (function() {
 				slave.bald = 1;
 			}, 0);
 		} else if (slave.weight >= 60 && thisSurgery.cosmetic > 0) {
-			commitProcedure("liposuction", s => { s.weight = 10; });
+			commitProcedure("liposuction", new App.Medicine.Surgery.Procedures.Liposuction(slave));
 		} else if ((slave.bellySagPreg > 0 || slave.bellySag > 0) && (thisSurgery.cosmetic > 0 || thisSurgery.tummy > 0 )) {
-			commitProcedure("a tummy tuck", () => {
-				slave.bellySag = 0;
-				slave.bellySagPreg = 0;
-			}, 20);
+			commitProcedure("a tummy tuck", new App.Medicine.Surgery.Procedures.TummyTuck(slave), 20);
 		} else if (slave.voice === 1 && slave.voiceImplant === 0 && thisSurgery.cosmetic > 0) {
-			commitProcedure("a feminine voice", () => {
-				slave.voice += 1;
-				slave.voiceImplant += 1;
-			});
+			commitProcedure("a feminine voice", new App.Medicine.Surgery.Procedures.VoiceRaise(slave));
 		} else if (slave.scar.hasOwnProperty("belly") && slave.scar.belly["c-section"] > 0 && thisSurgery.cosmetic > 0) {
 			commitProcedure("surgery to remove a c-section scar", s => { App.Medicine.Modification.removeScar(s, "belly", "c-section"); });
 		} else if (slave.faceImplant <= 45 && slave.face <= 95 && thisSurgery.cosmetic === 2) {
@@ -434,21 +422,15 @@ globalThis.rulesAutosurgery = (function() {
 				slave.faceImplant += 25 - 5 * Math.trunc(V.PC.skill.medicine / 50) - 5 * V.surgeryUpgrade;
 			});
 		} else if (slave.voice < 3 && slave.voiceImplant === 0 && thisSurgery.cosmetic === 2) {
-			commitProcedure("a bimbo's voice", () => {
-				slave.voice += 1;
-				slave.voiceImplant += 1;
-			});
+			commitProcedure("a bimbo's voice", new App.Medicine.Surgery.Procedures.VoiceRaise(slave));
 		}
 
 		if (slave.waist >= -10 && thisSurgery.cosmetic > 0) {
-			commitProcedure("a narrower waist", s => { s.waist -= 20; });
+			commitProcedure("a narrower waist", new App.Medicine.Surgery.Procedures.WaistReduction(slave));
 		} else if (slave.waist >= -95 && V.seeExtreme === 1 && thisSurgery.cosmetic === 2) {
 			commitProcedure("a narrower waist", s => { s.waist = Math.clamp(s.waist - 20, -100, 100); });
 		} else if (thisSurgery.hips !== null && slave.hips < 3 && V.surgeryUpgrade === 1 && (slave.hips < thisSurgery.hips)) {
-			commitProcedure("wider hips", () => {
-				slave.hips++;
-				slave.hipsImplant++;
-			});
+			commitProcedure("wider hips", new App.Medicine.Surgery.Procedures.BroadenPelvis(slave));
 		}
 
 		if (slave.bellyImplant < 0 && V.bellyImplants > 0 && thisSurgery.bellyImplant === "install" && slave.womb.length === 0 && slave.broodmother === 0) {
@@ -470,30 +452,31 @@ globalThis.rulesAutosurgery = (function() {
 			});
 		}
 
-		if (slave.horn !== "none" && thisSurgery.horn === 1) {
-			commitProcedure(`surgery to remove ${his} implanted horns`, s => { s.horn = "none"; });
-		} else if (slave.horn !== "curved succubus horns" && thisSurgery.horn === 2) {
-			commitProcedure(`surgery to implant ${him} with curved succubus horns`, s => { s.horn = "curved succubus horns"; s.hornColor = "white"; });
-		} else if (slave.horn !== "backswept horns" && thisSurgery.horn === 3) {
-			commitProcedure(`surgery to implant ${him} with backswept horns`, s => { s.horn = "backswept horns"; s.hornColor = "white"; });
-		} else if (slave.horn !== "cow horns" && thisSurgery.horn === 4) {
-			commitProcedure(`surgery to implant ${him} with cow horns`, s => { s.horn = "cow horns"; s.hornColor = "white"; });
-		} else if (slave.horn !== "one long oni horn" && thisSurgery.horn === 5) {
-			commitProcedure(`surgery to implant ${him} with one long oni horn`, s => { s.horn = "one long oni horn"; s.hornColor = "white"; });
-		} else if (slave.horn !== "two long oni horns" && thisSurgery.horn === 6) {
-			commitProcedure(`surgery to implant ${him} with two long oni horns`, s => { s.horn = "two long oni horns"; s.hornColor = "white"; });
-		} else if (slave.horn !== "small horns" && thisSurgery.horn === 7) {
-			commitProcedure(`surgery to implant ${him} with small horns`, s => { s.horn = "small horns"; s.hornColor = "white"; });
+		/**
+		 * @type {FC.HornType[]}
+		 */
+		const hornTypes = [ "none", "curved succubus horns", "backswept horns", "cow horns", "one long oni horn", "two long oni horns", "small horns" ];
+		/**
+		 * @type {FC.HornType}
+		 */
+		const hornType = hornTypes[thisSurgery.horn - 1];
+
+		if (slave.horn !== hornType){
+			if (hornType === "none") {
+				commitProcedure(`surgery to remove ${his} implanted horns`, new App.Medicine.Surgery.Procedures.HornGone(slave));
+			} else {
+				commitProcedure(`surgery to implant ${him} with ${hornType}`, new App.Medicine.Surgery.Procedures.Horn(slave, hornType, hornType, "white"));
+			}
 		}
 
 		if (slave.earShape !== "normal" && thisSurgery.earShape === 1) {
-			commitProcedure(`surgery to restore ${his} modified ears`, s => { s.earShape = "normal"; });
+			commitProcedure(`surgery to restore ${his} modified ears`, new App.Medicine.Surgery.Procedures.EarRestore(slave));
 		} else if (slave.earShape !== "pointy" && thisSurgery.earShape === 2) {
-			commitProcedure(`surgery to modify ${his} ears into a pair of small pointy ears`, s => { s.earShape = "pointy"; });
+			commitProcedure(`surgery to modify ${his} ears into a pair of small pointy ears`, new App.Medicine.Surgery.Procedures.EarMinorReshape(slave, "pointy", "pointy"));
 		} else if (slave.earShape !== "elven" && thisSurgery.earShape === 3) {
-			commitProcedure(`surgery to modify ${his} ears into a pair of elven ears`, s => { s.earShape = "elven"; });
+			commitProcedure(`surgery to modify ${his} ears into a pair of elven ears`, new App.Medicine.Surgery.Procedures.EarMajorReshape(slave, "elven", "elven"));
 		} else if (slave.earShape !== "cow" && thisSurgery.earShape === 4) {
-			commitProcedure(`surgery to modify ${his} ears into a pair of bovine-like ears`, s => { s.earShape = "cow"; });
+			commitProcedure(`surgery to modify ${his} ears into a pair of bovine-like ears`, new App.Medicine.Surgery.Procedures.EarMajorReshape(slave, "cow", "cow"));
 		}
 	}
 
-- 
GitLab