diff --git a/devTools/FC.d.ts b/devTools/FC.d.ts
index 6ceb1585e3b68965398ba5e9ae83d98fa8363d13..186f3b3073f6da8503c8d3f87d1841b1e1f3ee84 100644
--- a/devTools/FC.d.ts
+++ b/devTools/FC.d.ts
@@ -1,184 +1,241 @@
-	interface Window {
+interface Window {
 
-		jsRandom(min: number, max: number): number;
+	jsRandom(min: number, max: number): number;
 
-		SlaveDataSchemeCleanup(slave: App.Entity.SlaveState): void;
+	SlaveDataSchemeCleanup(slave: App.Entity.SlaveState): void;
 
-		walkPasts(slave: App.Entity.SlaveState, seed: any): string;
-		WombInit(actor: any): void;
-		WombImpregnate(actor, fCount, fatherID, age, surrogate?): void;
-		WombSurrogate(actor, fCount, mother, fatherID, age): void;
-		WombSort(actor): void;
+	walkPasts(slave: App.Entity.SlaveState, seed: any): string;
+	WombInit(actor: any): void;
+	WombImpregnate(actor, fCount, fatherID, age, surrogate?): void;
+	WombSurrogate(actor, fCount, mother, fatherID, age): void;
+	WombSort(actor): void;
 
-		capFirstChar(s: string): string;
+	capFirstChar(s: string): string;
 
-		canWalk(slave: App.Entity.SlaveState): boolean;
+	canWalk(slave: App.Entity.SlaveState): boolean;
 
-		rulesAutosurgery: any;
-		ruleApplied: any;
-		clearSummaryCache: any;
-		SlaveSummary: any;
-		SlaveSummaryUncached: any;
-	}
+	rulesAutosurgery: any;
+	ruleApplied: any;
+	clearSummaryCache: any;
+	SlaveSummary: any;
+	SlaveSummaryUncached: any;
+}
 
-	declare namespace App {
-		namespace RA {
-			class NumericTarget {
-				cond: string;
-				val: number;
-			}
+declare namespace App {
+	namespace RA {
+		class NumericTarget {
+			cond: string;
+			val: number;
+		}
 
-			class RuleConditions {
-				function: boolean | string;
-				data: any;
-				specialSlaves: number;
-				assignment: string[];
-				selectedSlaves: number[];
-				excludedSlaves: number[];
-			}
+		class RuleConditions {
+			function: boolean | string;
+			data: any;
+			specialSlaves: number;
+			assignment: string[];
+			selectedSlaves: number[];
+			excludedSlaves: number[];
+		}
 
-			class RuleSurgerySettings {
-				eyes: number;
-				hears: number;
-				smells: number;
-				tastes: number;
-				lactation: number;
-				prostate: number;
-				cosmetic: number;
-				accent: number;
-				shoulders: number;
-				shouldersImplant: number;
-				boobs: NumericTarget;
-				hips: number;
-				hipsImplant: number;
-				butt: NumericTarget;
-				faceShape: string;
-				lips: NumericTarget;
-				holes: number;
-				hair: number;
-				bodyhair: number;
-				vasectomy: boolean;
-				bellyImplant: string;
-				tummy: number;
-			}
+		class RuleSurgerySettings {
+			eyes: number;
+			hears: number;
+			smells: number;
+			tastes: number;
+			lactation: number;
+			prostate: number;
+			cosmetic: number;
+			accent: number;
+			shoulders: number;
+			shouldersImplant: number;
+			boobs: NumericTarget;
+			hips: number;
+			hipsImplant: number;
+			butt: NumericTarget;
+			faceShape: string;
+			lips: NumericTarget;
+			holes: number;
+			hair: number;
+			bodyhair: number;
+			vasectomy: boolean;
+			bellyImplant: string;
+			tummy: number;
+		}
 
-			class RuleSetters {
-				releaseRules: string;
-				toyHole: string;
-				clitSetting: string;
-				clitSettingXY: number;
-				clitSettingXX: number;
-				clitSettingEnergy: number;
-				speechRules: string;
-				clothes: string;
-				collar: string;
-				shoes: string;
-				legAccessory: string;
-				chastityVagina: number;
-				chastityAnus: number;
-				chastityPenis: number;
-				virginAccessory: string;
-				aVirginAccessory: string;
-				vaginalAccessory: string;
-				aVirginDickAccessory: string;
-				dickAccessory: string;
-				bellyAccessory: string;
-				aVirginButtplug: string;
-				buttplug: string;
-				vaginalAttachment: string;
-				buttplugAttachment: string;
-				eyeColor: string;
-				makeup: string;
-				nails: string;
-				hColor: string;
-				hLength: number;
-				haircuts: number;
-				hStyle: string;
-				eyebrowHColor: string;
-				eyebrowHStyle: string;
-				eyebrowFullness: string;
-				markings: string;
-				pubicHColor: string;
-				pubicHStyle: string;
-				nipplesPiercing: number;
-				areolaePiercing: number;
-				clitPiercing: number;
-				vaginaLube: number;
-				vaginaPiercing: number;
-				dickPiercing: number;
-				anusPiercing: number;
-				lipsPiercing: number;
-				tonguePiercing: number;
-				earPiercing: number;
-				nosePiercing: number;
-				eyebrowPiercing: number;
-				navelPiercing: number;
-				corsetPiercing: number;
-				boobsTat: string | number;
-				buttTat: string | number;
-				vaginaTat: string | number;
-				dickTat: string | number;
-				lipsTat: string | number;
-				anusTat: string | number;
-				shouldersTat: string | number;
-				armsTat: string | number;
-				legsTat: string | number;
-				backTat: string | number;
-				stampTat: string | number;
-				curatives: number;
-				livingRules: string;
-				relationshipRules: string;
-				standardPunishment: string;
-				standardReward: string;
-				diet: string | number;
-				dietCum: number;
-				dietMilk: number;
-				onDiet: number;
-				muscles: NumericTarget;
-				XY: number;
-				XX: number;
-				gelding: number;
-				preg: boolean;
-				abortion: string;
-				growth: {
-					boobs: NumericTarget;
-					butt: NumericTarget;
-					lips: NumericTarget;
-					dick: NumericTarget;
-					balls: NumericTarget;
-					intensity: number;
-				}
-				hyper_drugs: number;
-				aphrodisiacs: number;
-				autoSurgery: number;
-				autoBrand: number;
-				pornFeed: number;
-				pornFameSpending: number;
-				dietGrowthSupport: number;
-				eyewear: string;
-				earwear: string;
-				setAssignment: string;
-				facilityRemove: boolean;
-				removalAssignment: string;
-				surgery: RuleSurgerySettings;
-				underArmHColor: string;
-				underArmHStyle: string;
-				drug: string;
-				eyes: string;
-				pregSpeed: string;
-				bellyImplantVol: number;
-				teeth: string;
+		class RuleGrowthSetters {
+			boobs: NumericTarget;
+			butt: NumericTarget;
+			lips: NumericTarget;
+			dick: NumericTarget;
+			balls: NumericTarget;
+			intensity: number;
+		}
+
+		class RuleSetters {
+			releaseRules: string;
+			toyHole: string;
+			clitSetting: string;
+			clitSettingXY: number;
+			clitSettingXX: number;
+			clitSettingEnergy: number;
+			speechRules: string;
+			clothes: string;
+			collar: string;
+			shoes: string;
+			legAccessory: string;
+			chastityVagina: number;
+			chastityAnus: number;
+			chastityPenis: number;
+			virginAccessory: string;
+			aVirginAccessory: string;
+			vaginalAccessory: string;
+			aVirginDickAccessory: string;
+			dickAccessory: string;
+			bellyAccessory: string;
+			aVirginButtplug: string;
+			buttplug: string;
+			vaginalAttachment: string;
+			buttplugAttachment: string;
+			eyeColor: string;
+			makeup: string;
+			nails: string;
+			hColor: string;
+			hLength: number;
+			haircuts: number;
+			hStyle: string;
+			eyebrowHColor: string;
+			eyebrowHStyle: string;
+			eyebrowFullness: string;
+			markings: string;
+			pubicHColor: string;
+			pubicHStyle: string;
+			nipplesPiercing: number;
+			areolaePiercing: number;
+			clitPiercing: number;
+			vaginaLube: number;
+			vaginaPiercing: number;
+			dickPiercing: number;
+			anusPiercing: number;
+			lipsPiercing: number;
+			tonguePiercing: number;
+			earPiercing: number;
+			nosePiercing: number;
+			eyebrowPiercing: number;
+			navelPiercing: number;
+			corsetPiercing: number;
+			boobsTat: string | number;
+			buttTat: string | number;
+			vaginaTat: string | number;
+			dickTat: string | number;
+			lipsTat: string | number;
+			anusTat: string | number;
+			shouldersTat: string | number;
+			armsTat: string | number;
+			legsTat: string | number;
+			backTat: string | number;
+			stampTat: string | number;
+			curatives: number;
+			livingRules: string;
+			relationshipRules: string;
+			standardPunishment: string;
+			standardReward: string;
+			diet: string | number;
+			dietCum: number;
+			dietMilk: number;
+			onDiet: number;
+			muscles: NumericTarget;
+			XY: number;
+			XX: number;
+			gelding: number;
+			preg: boolean;
+			abortion: string;
+			growth: RuleGrowthSetters;
+			hyper_drugs: number;
+			aphrodisiacs: number;
+			autoSurgery: number;
+			autoBrand: number;
+			pornFeed: number;
+			pornFameSpending: number;
+			dietGrowthSupport: number;
+			eyewear: string;
+			earwear: string;
+			setAssignment: string;
+			facilityRemove: boolean;
+			removalAssignment: string;
+			surgery: RuleSurgerySettings;
+			underArmHColor: string;
+			underArmHStyle: string;
+			drug: string;
+			eyes: string;
+			pregSpeed: string;
+			bellyImplantVol: number;
+			teeth: string;
+			label: string;
+			removeLabel: string;
+			skinColor: string;
+			inflationType: string;
+		}
+
+		class Rule {
+			ID: string;
+			name: string;
+			condition: RuleConditions;
+			set: RuleSetters;
+		}
+	}
+
+	namespace Medicine {
+		namespace Surgery {
+			/**
+			 * Describes surgical procedure
+			 */
+			class Procedure {
+				/**
+				 * Type code that identifies this kind of procedure.
+				 * Currently unused, but planned for future use by RA for prioritizing procedures
+				 */
+				typeId: string;
+				/**
+				 * Short label for the procedure. Can be used as a link text.
+				 */
 				label: string;
-				removeLabel: string;
-				skinColor: string;
-				inflationType: string;
+				/**
+				 * If procedure is targeted at changing object characteristic, this is the net change (signed)
+				 */
+				targetEffect: number;
+				/**
+				 * Description of the procedure, more or less detailed
+				 */
+				description: string;
+				/**
+				 * Money costs (positive when you pay for it)
+				 */
+				costs: number;
+				/**
+				 * Projected health loss (positive when health decreases)
+				 */
+				healthCosts: number;
+				/**
+				 * Function to perform the procedure
+				 * If action is undefined, the procedure can't be applied (and .description contains the reason)
+				 */
+				action: slaveOperation;
+				/**
+				 * surgery type for passages like "Surgery Degradation"
+				 */
+				surgeryType: string;
 			}
 
-			class Rule {
-				ID: string;
-				name: string;
-				condition: RuleConditions;
-				set: RuleSetters;
-			}
+			class SizingOptions {
+				/** include possible augmentation procedures */
+				augmentation?: boolean;
+				/** include possible reduction procedures */
+				reduction?: boolean;
+				/** include option to install string implants */
+				strings?: boolean;
+				/** include implant change options */
+				replace?: boolean;
+			};
 		}
 	}
+}
diff --git a/src/002-config/fc-js-init.js b/src/002-config/fc-js-init.js
index b1af84f565502168e513b75b68802f25687de0dc..f72c839f781d59d8ab0bd4132a07806d460af06b 100644
--- a/src/002-config/fc-js-init.js
+++ b/src/002-config/fc-js-init.js
@@ -33,5 +33,6 @@ App.Facilities = {
 	Arcade: {},
 	HGSuite: {}
 };
+App.Medicine = {};
 App.RA = {};
 App.SF = {};
diff --git a/src/js/rulesAssistant.js b/src/js/rulesAssistant.js
index 260edbf6bf01da0e5de5df84bc71cde51e181edd..5ff2a48f841b0c1eb33e814fdb207a11cc0ce7ef 100644
--- a/src/js/rulesAssistant.js
+++ b/src/js/rulesAssistant.js
@@ -232,24 +232,41 @@ window.ruleAppliesP = function ruleAppliesP(cond, slave) {
 	return flag;
 };
 
-/**
- * @returns {App.RA.Rule}
- */
-window.emptyDefaultRule = function emptyDefaultRule() {
-	const id = generateNewID();
-	const rule = {
-		ID: id,
-		name: `Rule ${id}`,
-		condition: {
+App.RA.newRule = function() {
+	return {
+		rule: emptyRule,
+		conditions: emptyConditions,
+		setters: emptySetters,
+		growth: emptyGrowth,
+		surgery: emptySurgery
+	};
+
+	/** @returns {App.RA.Rule} */
+	function emptyRule() {
+		const id = generateNewID();
+		return {
+			ID: id,
+			name: `Rule ${id}`,
+			condition: emptyConditions(),
+			// TODO: rename properties in snake_case to camelCase?
+			set: emptySetters()
+		};
+	}
+
+	/** @returns {App.RA.RuleConditions} */
+	function emptyConditions() {
+		return {
 			function: false,
 			data: {},
 			specialSlaves: -1,
 			assignment: [],
 			selectedSlaves: [],
 			excludedSlaves: [],
-		},
-		// TODO: rename properties in snake_case to camelCase?
-		set: {
+		};
+	}
+	/** @returns {App.RA.RuleSetters} */
+	function emptySetters() {
+		return {
 			releaseRules: null,
 			toyHole: null,
 			clitSetting: null,
@@ -327,14 +344,7 @@ window.emptyDefaultRule = function emptyDefaultRule() {
 			gelding: null,
 			preg: null,
 			abortion: null,
-			growth: {
-				boobs: null,
-				butt: null,
-				lips: null,
-				dick: null,
-				balls: null,
-				intensity: 0
-			},
+			growth: emptyGrowth(),
 			hyper_drugs: 0,
 			aphrodisiacs: null,
 			autoSurgery: 0,
@@ -347,30 +357,7 @@ window.emptyDefaultRule = function emptyDefaultRule() {
 			setAssignment: null,
 			facilityRemove: false,
 			removalAssignment: "rest",
-			surgery: {
-				eyes: null,
-				hears: null,
-				smells: null,
-				tastes: null,
-				lactation: null,
-				prostate: null,
-				cosmetic: null,
-				accent: null,
-				shoulders: null,
-				shouldersImplant: null,
-				boobs: null,
-				hips: null,
-				hipsImplant: null,
-				butt: null,
-				faceShape: null,
-				lips: null,
-				holes: null,
-				tummy: null,
-				hair: null,
-				bodyhair: null,
-				vasectomy: null,
-				bellyImplant: null
-			},
+			surgery: emptySurgery(),
 			underArmHColor: null,
 			underArmHStyle: null,
 			drug: null,
@@ -382,10 +369,54 @@ window.emptyDefaultRule = function emptyDefaultRule() {
 			removeLabel: null,
 			skinColor: null,
 			inflationType: null,
-		}
-	};
-	return rule;
-};
+		};
+	}
+
+	/** @returns {App.RA.RuleGrowthSetters} */
+	function emptyGrowth() {
+		return {
+			boobs: null,
+			butt: null,
+			lips: null,
+			dick: null,
+			balls: null,
+			intensity: 0
+		};
+	}
+
+	/** @returns {App.RA.RuleSurgerySettings} */
+	function emptySurgery() {
+		return {
+			eyes: null,
+			hears: null,
+			smells: null,
+			tastes: null,
+			lactation: null,
+			prostate: null,
+			cosmetic: null,
+			accent: null,
+			shoulders: null,
+			shouldersImplant: null,
+			boobs: null,
+			hips: null,
+			hipsImplant: null,
+			butt: null,
+			faceShape: null,
+			lips: null,
+			holes: null,
+			tummy: null,
+			hair: null,
+			bodyhair: null,
+			vasectomy: null,
+			bellyImplant: null
+		};
+	}
+}();
+
+/**
+ * @returns {App.RA.Rule}
+ */
+window.emptyDefaultRule = App.RA.newRule.rule;
 
 /**
  * Saves the slave, silently fires the RA, saves the slave's after-RA state, and then reverts the slave.
diff --git a/src/js/rulesAutosurgery.js b/src/js/rulesAutosurgery.js
index aa2f9b9dbe61d0fab36ae092784c362f7363fe3d..d7413c56fbd0a66938d0b1b3be32947f76894496 100644
--- a/src/js/rulesAutosurgery.js
+++ b/src/js/rulesAutosurgery.js
@@ -29,7 +29,7 @@ window.rulesAutosurgery = (function() {
 	 * @returns {App.RA.RuleSurgerySettings}
 	 */
 	function autoSurgerySelector(slave, ruleset) {
-		const surgery = {};
+		const surgery = App.RA.newRule.surgery();
 		ruleset.forEach(rule => {
 			Object.keys(rule.surgery)
 				.filter(key => rule.surgery[key] !== null)
@@ -45,71 +45,63 @@ window.rulesAutosurgery = (function() {
 	 * @returns {App.RA.RuleSurgerySettings}
 	 */
 	function ProcessHGTastes(slave) {
-		let thisSurgery;
+		let thisSurgery = App.RA.newRule.surgery();
 		switch (V.HGTastes) {
 			case 1:
-				thisSurgery = {
-					lactation: 0,
-					cosmetic: 1,
-					faceShape: "cute",
-					lips: App.RA.makeTarget('==', 10),
-					hips: 0,
-					hipsImplant: 0,
-					butt: App.RA.makeTarget('==', 0),
-					accent: 0,
-					shoulders: 0,
-					shouldersImplant: 0,
-					boobs: App.RA.makeTarget('==', 0),
-					holes: 0
-				};
+				thisSurgery.lactation = 0;
+				thisSurgery.cosmetic = 1;
+				thisSurgery.faceShape = "cute";
+				thisSurgery.lips = App.RA.makeTarget('==', 10);
+				thisSurgery.hips = 0;
+				thisSurgery.hipsImplant = 0;
+				thisSurgery.butt = App.RA.makeTarget('==', 0);
+				thisSurgery.accent = 0;
+				thisSurgery.shoulders = 0;
+				thisSurgery.shouldersImplant = 0;
+				thisSurgery.boobs = App.RA.makeTarget('==', 0);
+				thisSurgery.holes = 0;
 				break;
 			case 2:
-				thisSurgery = {
-					lactation: 0,
-					cosmetic: 1,
-					faceShape: "cute",
-					lips: App.RA.makeTarget('==', 60),
-					hips: 0,
-					hipsImplant: 0,
-					butt: App.RA.makeTarget('==', 4),
-					accent: 0,
-					shoulders: 0,
-					shouldersImplant: 0,
-					boobs: App.RA.makeTarget('==', 1200),
-					holes: 0
-				};
+				thisSurgery.lactation = 0;
+				thisSurgery.cosmetic = 1;
+				thisSurgery.faceShape = "cute";
+				thisSurgery.lips = App.RA.makeTarget('==', 60);
+				thisSurgery.hips = 0;
+				thisSurgery.hipsImplant = 0;
+				thisSurgery.butt = App.RA.makeTarget('==', 4);
+				thisSurgery.accent = 0;
+				thisSurgery.shoulders = 0;
+				thisSurgery.shouldersImplant = 0;
+				thisSurgery.boobs = App.RA.makeTarget('==', 1200);
+				thisSurgery.holes = 0;
 				break;
 			case 3:
-				thisSurgery = {
-					lactation: 0,
-					cosmetic: 1,
-					faceShape: "cute",
-					lips: App.RA.makeTarget('==', 95),
-					hips: 0,
-					hipsImplant: 0,
-					butt: App.RA.makeTarget('==', 8),
-					accent: 0,
-					shoulders: 0,
-					shouldersImplant: 0,
-					boobs: App.RA.makeTarget('==', 10000),
-					holes: 2
-				};
+				thisSurgery.lactation = 0;
+				thisSurgery.cosmetic = 1;
+				thisSurgery.faceShape = "cute";
+				thisSurgery.lips = App.RA.makeTarget('==', 95);
+				thisSurgery.hips = 0;
+				thisSurgery.hipsImplant = 0;
+				thisSurgery.butt = App.RA.makeTarget('==', 8);
+				thisSurgery.accent = 0;
+				thisSurgery.shoulders = 0;
+				thisSurgery.shouldersImplant = 0;
+				thisSurgery.boobs = App.RA.makeTarget('==', 10000);
+				thisSurgery.holes = 2;
 				break;
 			case 4:
-				thisSurgery = {
-					lactation: 1,
-					cosmetic: 1,
-					faceShape: "cute",
-					lips: App.RA.makeTarget('==', 10),
-					hips: 3,
-					hipsImplant: 0,
-					butt: App.RA.makeTarget('==', 0),
-					accent: 0,
-					shoulders: 0,
-					shouldersImplant: 0,
-					boobs: App.RA.makeTarget('==', 0),
-					holes: 0
-				};
+				thisSurgery.lactation = 1;
+				thisSurgery.cosmetic = 1;
+				thisSurgery.faceShape = "cute";
+				thisSurgery.lips = App.RA.makeTarget('==', 10);
+				thisSurgery.hips = 3;
+				thisSurgery.hipsImplant = 0;
+				thisSurgery.butt = App.RA.makeTarget('==', 0);
+				thisSurgery.accent = 0;
+				thisSurgery.shoulders = 0;
+				thisSurgery.shouldersImplant = 0;
+				thisSurgery.boobs = App.RA.makeTarget('==', 0);
+				thisSurgery.holes = 0;
 				break;
 			default:
 				thisSurgery = autoSurgerySelector(
@@ -162,22 +154,63 @@ window.rulesAutosurgery = (function() {
 			slave.health -= (V.PC.medicine >= 100) ? Math.round(healthCost / 2) : healthCost;
 		}
 
+		/**
+		 *
+		 * @param {string} bodyPart
+		 * @param {!App.RA.NumericTarget} target
+		 */
+		function bodyPartSizing(bodyPart, target) {
+			const shallShrink = App.RA.shallShrink(slave[`${bodyPart}Implant`], target);
+			let shallGrow = false;
+			let options;
+			let sorter;
+			if (shallShrink) {
+				if (target.val === 0) {
+					commitProcedure(`surgery to remove ${slave.possessive} ${bodyPart} implants`, slave => {
+						slave[bodyPart] -= slave[`${bodyPart}Implant`];
+						slave[`${bodyPart}Implant`] = 0;
+						slave[`${bodyPart}ImplantType`] = 0;
+					});
+					return;
+				}
+				options = {reduction: true, replace: true};
+				sorter = (left, right) => -right.targetEffect / right.costs + left.targetEffect / left.costs;
+			} else if (App.RA.shallGrow(slave[`${bodyPart}Implant`], target)) {
+				shallGrow = true;
+				options = {augmentation: true, replace: true};
+				sorter = (left, right) => right.targetEffect / right.costs - left.targetEffect / left.costs;
+			}
+			if (!shallShrink && !shallGrow) { return; }
+
+			const surgeryOptions = App.Medicine.Surgery.sizingProcedures.bodyPart(bodyPart, slave, options)
+				.filter(surgery => surgery.action !== undefined)
+				.sort(sorter);
+			for (const so of surgeryOptions) {
+				if ((shallShrink && App.RA.shallShrink(slave[`${bodyPart}Implant`], target, so.targetEffect)) ||
+					(shallGrow && App.RA.shallGrow(slave[`${bodyPart}Implant`], target, so.targetEffect))) {
+					surgeries.push(`surgery to ${so.description}`);
+					App.Medicine.Surgery.commit(so, slave);
+					break;
+				}
+			}
+		}
+
 		// NOTE: App.RA.shallShrink() and App.RA.shallGrow() return 'false' when target is 'null'
 		// Hence they have to be first conditions in the '&&' chains to avoid type errors
 		// (reading properties of the 'null' object)
 		if (slave.health > 20 && surgeries.length < 3) {
 			if (slave.eyes === -1 && thisSurgery.eyes === 1) {
-				commitProcedure(`surgery to correct ${slave.possessive} vision`, s => { s.eyes = 1 });
+				commitProcedure(`surgery to correct ${slave.possessive} vision`, s => { s.eyes = 1; });
 			} else if (slave.eyes === 1 && thisSurgery.eyes === -1) {
-				commitProcedure(`surgery to blur ${slave.possessive} vision`, s => { s.eyes = -1 });
+				commitProcedure(`surgery to blur ${slave.possessive} vision`, s => { s.eyes = -1; });
 			} else if (slave.hears === -1 && thisSurgery.hears === 0) {
-				commitProcedure(`surgery to correct ${slave.possessive} hearing`, s => { s.hears = 0 });
+				commitProcedure(`surgery to correct ${slave.possessive} hearing`, s => { s.hears = 0; });
 			} else if (slave.hears === 0 && thisSurgery.hears === -1) {
-				commitProcedure(`surgery to muffle ${slave.possessive} hearing`, s => { s.hears = -1 });
+				commitProcedure(`surgery to muffle ${slave.possessive} hearing`, s => { s.hears = -1; });
 			} else if (slave.smells === -1 && thisSurgery.smells === 0) {
-				commitProcedure(`surgery to correct ${slave.possessive} sense of smell`, s => { s.smells = 0 });
+				commitProcedure(`surgery to correct ${slave.possessive} sense of smell`, s => { s.smells = 0; });
 			} else if (slave.smells === 0 && thisSurgery.smells === -1) {
-				commitProcedure(`surgery to muffle ${slave.possessive} sense of smell`, s => { s.smells = -1 });
+				commitProcedure(`surgery to muffle ${slave.possessive} sense of smell`, s => { s.smells = -1; });
 			} else if (slave.tastes === -1 && thisSurgery.tastes === 0) {
 				commitProcedure(`surgery to correct ${slave.possessive} sense of taste`, s => { s.tastes = 0; });
 			} else if (slave.tastes === 0 && thisSurgery.tastes === -1) {
@@ -199,57 +232,12 @@ window.rulesAutosurgery = (function() {
 						slave.boobShape = "perky";
 					}
 				});
-			} else if (App.RA.shallShrink(slave.boobsImplant, thisSurgery.boobs) && thisSurgery.boobs.val === 0) {
-				commitProcedure(`surgery to remove ${slave.possessive} boob implants`, slave => {
-					slave.boobs -= slave.boobsImplant;
-					slave.boobsImplant = 0;
-					slave.boobsImplantType = 0;
-				});
-			} else if (App.RA.shallGrow(slave.boobs, thisSurgery.boobs, 400) && slave.boobs <= 600 && slave.lactation < 2) {
-				commitProcedure("bigger boobs", slave => {
-					slave.boobsImplant += 400;
-					slave.boobs += 400;
-				});
-			} else if (App.RA.shallGrow(slave.boobs, thisSurgery.boobs, 200) && slave.boobs <= 600 && slave.lactation < 2) {
-				commitProcedure("modestly bigger boobs", slave => {
-					slave.boobsImplant += 200;
-					slave.boobs += 200;
-				});
-			} else if (App.RA.shallGrow(slave.boobs, thisSurgery.boobs, 400) && slave.boobs <= 2000 && slave.lactation < 2) {
-				commitProcedure("bigger boobs", slave => {
-					slave.boobsImplant += 400;
-					slave.boobs += 400;
-				});
-			} else if (App.RA.shallGrow(slave.boobs, thisSurgery.boobs) && slave.boobs <= 9000 && slave.lactation < 2) {
-				commitProcedure("bigger boobs", slave => {
-					slave.boobsImplant += 200;
-					slave.boobs += 200;
-				});
+			} else if (thisSurgery.boobs) {
+				bodyPartSizing("boobs", thisSurgery.boobs);
 			}
 		}
 		if (thisSurgery.butt !== null && slave.health > 20 && surgeries.length < 3) {
-			if (App.RA.shallShrink(slave.buttImplant, thisSurgery.butt) && thisSurgery.butt.val === 0) {
-				commitProcedure(`surgery to remove ${slave.possessive} butt implants`, slave => {
-					slave.butt -= slave.buttImplant;
-					slave.buttImplant = 0;
-					slave.buttImplantType = 0;
-				});
-			} else if (App.RA.shallGrow(slave.butt, thisSurgery.butt) && slave.butt <= 3) {
-				commitProcedure("a bigger butt", slave => {
-					slave.buttImplant = 1; // FIXME: +=1?
-					slave.butt += 1;
-				});
-			} else if (App.RA.shallGrow(slave.butt, thisSurgery.butt) && slave.butt <= 5) {
-				commitProcedure("a bigger butt", slave => {
-					slave.buttImplant = 1; // FIXME: +=1?
-					slave.butt += 1;
-				});
-			} else if (App.RA.shallGrow(slave.butt, thisSurgery.butt) && slave.butt <= 8) {
-				commitProcedure("a bigger butt", slave => {
-					slave.buttImplant = 1; // FIXME: +=1?
-					slave.butt += 1;
-				});
-			}
+			bodyPartSizing("butt", thisSurgery.butt);
 		}
 		if (slave.health > 20 && surgeries.length < 3) {
 			if (slave.anus > 3 && thisSurgery.cosmetic > 0) {
diff --git a/src/js/surgery.js b/src/js/surgery.js
new file mode 100644
index 0000000000000000000000000000000000000000..f8c6c2d3b62df1581205c70d0019315cf874647c
--- /dev/null
+++ b/src/js/surgery.js
@@ -0,0 +1,453 @@
+
+App.Medicine.Surgery = {};
+/**
+ * Composes the Procedure object from its parts
+ *
+ * This function has the only purpose to ensure the result object has all required properties
+ * @param {string} typeId
+ * @param {string} label
+ * @param {number} effect
+ * @param {string} desc
+ * @param {slaveOperation} [action]
+ * @param {number} [costs] money costs
+ * @param {number} [hCosts] health costs
+ * @param {string} [surgeryType]
+ * @returns {App.Medicine.Surgery.Procedure}
+ */
+App.Medicine.Surgery.makeOption = function(typeId, label, effect, desc, action, costs, hCosts, surgeryType) {
+	return {
+		typeId: typeId,
+		label: label,
+		targetEffect: effect,
+		description: desc,
+		costs: costs,
+		healthCosts: hCosts,
+		action: action,
+		surgeryType: surgeryType
+	};
+};
+
+/**
+ * Composes the procedure option with empty .action, i.e. a procedure that can't be applied
+ * @param {string} typeId
+ * @param {string} label
+ * @param {string} desc
+ * @returns {App.Medicine.Surgery.Procedure}
+ */
+App.Medicine.Surgery.makeImpossibleOption = function(typeId, label, desc) {
+	return this.makeOption(typeId, label, 0, desc);
+};
+
+/**
+ * Various constants for procedures
+ */
+App.Medicine.Keys = {
+	Surgery: {
+		Target: {
+			/**
+			 * Type id's for breast-related procedures
+			 */
+			breast: {
+				installImplant: "breast.implant.install",
+				removeImplant: "breast.implant.remove",
+				fillUp: "breast.implant.fill",
+				drain: "breast.implant.drain",
+				changeImplant: "breast.implant.replace",
+				reduction: "breast.tissue.reduce",
+			},
+			/**
+			 * Type id's for butt-related procedures
+			 */
+			butt: {
+				installImplant: "butt.implant.install",
+				removeImplant: "butt.implant.remove",
+				fillUp: "butt.implant.fill",
+				drain: "butt.implant.drain",
+				changeImplant: "but.implant.replace",
+				reduction: "butt.tissue.reduce",
+			}
+		}
+	}
+};
+
+/**
+ * Commit procedure, executing its action and subtracting its costs
+ * @param {App.Medicine.Surgery.Procedure} surgery
+ * @param {App.Entity.SlaveState} slave
+ */
+App.Medicine.Surgery.commit = function(surgery, slave) {
+	const V = State.variables;
+	V.surgeryType = surgery.surgeryType;
+	surgery.action(slave);
+	cashX(forceNeg(surgery.costs), "slaveSurgery", slave);
+	slave.health -= (V.PC.medicine >= 100) ? Math.round(surgery.healthCosts / 2) : surgery.healthCosts;
+};
+
+/**
+ * Returns markup for a link to execute the given procedure
+ * @param {string} passage Passage to go after the surgery
+ * @param {App.Medicine.Surgery.Procedure} surgery
+ * @param {App.Entity.SlaveState} slave
+ * @returns {string}
+ */
+App.Medicine.Surgery.makeLink = function(passage, surgery, slave) {
+	if (surgery.action === undefined) {
+		return App.UI.disabledLink(surgery.label, [surgery.description]);
+	}
+
+	function healthCosts() {
+		const hc = (State.variables.PC.medicine >= 100) ? Math.round(surgery.healthCosts / 2) : surgery.healthCosts;
+		if (hc > 30) {
+			return 'substantial';
+		} else if (hc > 20) {
+			return 'significant';
+		} else if (hc > 10) {
+			return 'moderate';
+		} else if (hc > 5) {
+			return 'light';
+		}
+		return 'insignificant';
+	}
+
+	return App.UI.link(surgery.label, App.Medicine.Surgery.commit, [surgery, slave], passage,
+		`${capFirstChar(surgery.description)}.\nSurgery costs: ${cashFormat(surgery.costs)}.\nProjected health damage: ${healthCosts()}.`);
+};
+
+/**
+ * Helpers for composing procedure descriptions
+ */
+App.Medicine.Surgery.ListHelpers = class {
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @param {string} bodyPart
+	 * @param {Object.<string, string>} keys
+	 * @param {App.Utils.Pronouns} pronouns
+	 * @param {boolean} showCCs
+	*/
+	constructor(slave, bodyPart, keys, pronouns, showCCs) {
+		/** @private */
+		this._slave = slave;
+		/** @private */
+		this._bodyPart = bodyPart;
+		/** @private */
+		this._keys = keys;
+		/** @private */
+		this._pronouns = pronouns;
+		/** @private */
+		this._V = State.variables;
+		this._showCCs = showCCs;
+	}
+	/**
+	 * @param {string} name
+	 * @param {number} implantType
+	 * @param {number} size
+	 * @returns {App.Medicine.Surgery.Procedure}
+	 */
+	installImplants(name, implantType, size) {
+		return App.Medicine.Surgery.makeOption(this._keys.installImplant, `${capFirstChar(name)} implants`, size,
+			`place ${name}${this._showCCs ? ` ${size}cc` : ''} implants into ${this._pronouns.his} ${this._bodyPart}`,
+			slave => {
+				slave[`${this._bodyPart}Implant`] = size;
+				slave[`${this._bodyPart}ImplantType`] = implantType;
+				slave[this._bodyPart] += size;
+			}, this._V.surgeryCost, 10, this._bodyPart
+		);
+	}
+
+	removeImplants() {
+		return App.Medicine.Surgery.makeOption(this._keys.removeImplant, "Remove implants",
+			-this._slave[`${this._bodyPart}Implant`],
+			`remove ${this._pronouns.his} ${this._bodyPart} implants`,
+			slave => {
+				slave[`${this._bodyPart}`] -= slave[`${this._bodyPart}Implant`];
+				slave[`${this._bodyPart}Implant`] = 0;
+				slave[`${this._bodyPart}ImplantType`] = 0;
+			}, this._V.surgeryCost, 5, `${this._bodyPart}Loss`
+		);
+	}
+
+	/**
+	 * @param {string} name
+	 * @param {number} implantType
+	 * @param {number} size
+	 * @returns {App.Medicine.Surgery.Procedure}
+	 */
+	replaceImplants(name, implantType, size) {
+		return App.Medicine.Surgery.makeOption(this._keys.changeImplant, `${capFirstChar(name)} implants`,
+			size - this._slave.boobsImplant,
+			`replace ${this._pronouns.his} ${this._bodyPart} implants with ${name}${this._showCCs ? ` (${size}cc)` : ''} ones`,
+			slave => {
+				slave[this._bodyPart] += size - slave[`${this._bodyPart}Implant`];
+				slave[`${this._bodyPart}Implant`] = size;
+				slave[`${this._bodyPart}ImplantType`] = implantType;
+			}, this._V.surgeryCost, 10, this._bodyPart
+		);
+	}
+
+	/**
+	 * @param {number} volume
+	 * @returns {App.Medicine.Surgery.Procedure}
+	 */
+	fillUp(volume) {
+		return App.Medicine.Surgery.makeOption(this._keys.fillUp, "Add inert filler", volume,
+			`add${this._showCCs ? ` ${volume}cc of` : 'some'} inert filler to each of ${this._pronouns.his} ${this._bodyPart} implants`,
+			slave => {
+				slave[`${this._bodyPart}Implant`] += volume;
+				slave[this._bodyPart] += volume;
+			},
+			this._V.surgeryCost, 10, this._bodyPart
+		);
+	}
+
+	/**
+	 * @param {number} volume
+	 * @returns {App.Medicine.Surgery.Procedure}
+	 */
+	drain(volume) {
+		return App.Medicine.Surgery.makeOption(this._keys.drain, `Drain ${volume}cc`, -volume,
+			`drain${this._showCCs ? ` ${volume}cc of` : 'some'} inert filler from ${this._pronouns.his} ${this._bodyPart} implants`,
+			slave => {
+				slave[`${this._bodyPart}Implant`] -= volume;
+				slave[this._bodyPart] -= volume;
+			}, this._V.surgeryCost, 5, `${this._bodyPart}Loss`
+		);
+	}
+
+	/**
+	 * @param {string} procedureName
+	 * @param {number} sizeChange
+	 * @returns {App.Medicine.Surgery.Procedure}
+	 */
+	reduce(procedureName, sizeChange) {
+		return App.Medicine.Surgery.makeOption(this._keys.reduction,
+			`${capFirstChar(procedureName)} ${this._bodyPart}`, -200,
+			`${procedureName} ${this._pronouns.his} ${this._bodyPart}`,
+			slave => {
+				slave[this._bodyPart] -= sizeChange;
+			}, this._V.surgeryCost, 5, `${this._bodyPart}Loss`
+		);
+	}
+};
+
+/**
+ * Returns options to accept all possible surgeries
+ * @returns {App.Medicine.Surgery.SizingOptions}
+ */
+App.Medicine.Surgery.allSizingOptions = function() {
+	return {
+		augmentation: true,
+		reduction: true,
+		strings: true,
+		replace: true
+	};
+};
+
+App.Medicine.Surgery.sizingProcedures = function() {
+	return {
+		bodyPart: bodyPart,
+		boobs: boobSizingProcedures,
+		butt: buttSizingProcedures
+	};
+
+	/**
+	 * Returns list of available surgeries targeted at changing size of the given body part
+	 * @param {string} bodyPart
+	 * @param {App.Entity.SlaveState} slave
+	 * @param {App.Medicine.Surgery.SizingOptions} [options]
+	 * @returns {App.Medicine.Surgery.Procedure[]}
+	 */
+	function bodyPart(bodyPart, slave, options) {
+		switch (bodyPart) {
+			case "boob":
+			case "boobs":
+			case "breast":
+			case "breasts":
+				return boobSizingProcedures(slave, options);
+			case "ass":
+			case "booty":
+			case "butt":
+				return buttSizingProcedures(slave, options);
+			default:
+				throw `No sizing procedures for ${bodyPart}`;
+		}
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @param {App.Medicine.Surgery.SizingOptions} [options]
+	 * @returns {App.Medicine.Surgery.Procedure[]}
+	 */
+	function boobSizingProcedures(slave, options = {}) {
+		const V = State.variables;
+		const thisArcology = V.arcologies[0];
+		const largeImplantsAvailable = thisArcology.FSTransformationFetishistResearch === 1;
+		const advancedFillableImplantsAvailable = V.ImplantProductionUpgrade === 1;
+		const pronouns = getPronouns(slave);
+		const {he, His} = pronouns;
+
+		const types = App.Medicine.Keys.Surgery.Target.breast; // shortcuts
+		const helper = new App.Medicine.Surgery.ListHelpers(slave, "boobs", types, pronouns, V.showBoobCCs);
+
+		let r = [];
+		if (options.augmentation) {
+			if (slave.boobs > 50000) {
+				r.push(App.Medicine.Surgery.makeImpossibleOption(types.fillUp, "Increase boobs", `<em>${His} breasts are as large as ${he} can physically support</em>`));
+			} else if (slave.boobsImplant > 10000 && !largeImplantsAvailable && slave.boobsImplantType !== 1) {
+				r.push(App.Medicine.Surgery.makeImpossibleOption(types.fillUp, "Increase boobs", `<em>${His} implants are filled to capacity</em>`));
+			} else if (slave.indentureRestrictions >= 2) {
+				r.push(App.Medicine.Surgery.makeImpossibleOption(types.installImplant, "Change boob size", `<em>${His} indenture forbids elective surgery</em>`));
+			} else if (slave.breastMesh === 1) {
+				r.push(App.Medicine.Surgery.makeImpossibleOption(types.installImplant, "Put implants", `<em>${His} supportive mesh implant blocks implantation</em>`));
+			} else if (slave.boobsImplant === 0) {
+				if (options.strings) {
+					r.push(helper.installImplants("string", 1, 400));
+				}
+				if (V.surgeryUpgrade === 1) {
+					r.push(helper.installImplants("large", 1, 600));
+				}
+				r.push(helper.installImplants("standard", 1, 400));
+				r.push(helper.installImplants("small", 1, 200));
+			} else if (slave.boobsImplant > 10000 && slave.boobsImplantType !== 1 && advancedFillableImplantsAvailable) {
+				r.push(helper.fillUp(1000));
+			} else if (slave.boobsImplant > 9800 && slave.boobsImplantType !== 1 && advancedFillableImplantsAvailable) {
+				r.push(helper.replaceImplants("hyper fillable", 0, 11000));
+			} else if (slave.boobsImplant > 2000 && slave.boobsImplantType !== 1) {
+				r.push(helper.fillUp(400));
+			} else if (slave.boobsImplant > 1800 && slave.boobsImplantType !== 1) {
+				r.push(App.Medicine.Surgery.makeImpossibleOption(types.fillUp, "Add inert filler", `<em>${His} implants are filled to capacity</em>`));
+
+				const advancedFillable = helper.replaceImplants("advanced fillable", 0, 2200);
+				if (!advancedFillableImplantsAvailable) {
+					advancedFillable.costs += 10000;
+					advancedFillable.label += " (special order)";
+					advancedFillable.description += " (special order)";
+				}
+				r.push(advancedFillable);
+			} else if (slave.boobsImplant > 600 && slave.boobsImplantType !== 1) {
+				r.push(helper.fillUp(200));
+			} else if (slave.boobsImplant > 400 && slave.boobsImplantType !== 1) {
+				r.push(helper.replaceImplants("fillable", 0, 800));
+			} else if (slave.boobsImplant > 200 && slave.boobsImplantType !== 1) {
+				r.push(helper.replaceImplants("large", 0, 600));
+			} else if (slave.boobsImplant > 0 && slave.boobsImplantType !== 1) {
+				r.push(helper.replaceImplants("standard", 0, 400));
+				r.push(helper.replaceImplants("large", 0, 600));
+			}
+		}
+
+		if (options.reduction && (slave.boobs > 300 || slave.boobsImplant > 0)) {
+			if (slave.boobsImplant > 0) {
+				if (slave.boobsImplantType === 1 && slave.boobsImplant > 400) {
+					if (slave.boobsImplant > 8000) {
+						r.push(helper.drain(1000));
+					} else if (slave.boobsImplant > 5000) {
+						r.push(helper.drain(750));
+					} else if (slave.boobsImplant > 2000) {
+						r.push(helper.drain(500));
+					} else if (slave.boobsImplant > 1000) {
+						r.push(helper.drain(250));
+					} else if (slave.boobsImplant > 500) {
+						r.push(helper.drain(100));
+					}
+				}
+				r.push(helper.removeImplants());
+			}
+			if ((slave.boobs > 300) && (slave.boobsImplant === 0) && slave.indentureRestrictions < 2) {
+				r.push(helper.reduce("reduce", 200));
+				if (slave.boobs < 675) {
+					r.push(helper.reduce("slightly reduce", 25));
+				}
+			}
+			if ((slave.boobsImplant === 0) && slave.indentureRestrictions < 2 && (slave.breedingMark !== 1 || V.propOutcome !== 1)) {
+				if (slave.boobs >= 7000) {
+					r.push(App.Medicine.Surgery.makeOption(types.reduction, "Mastectomy", 300 - slave.boobs,
+						"perform mastectomy",
+						slave => {
+							slave.boobs = 300;
+						},
+						V.surgeryCost, 30, "mastectomy+"
+					));
+				} else if (slave.boobs >= 2000) {
+					r.push(App.Medicine.Surgery.makeOption(types.reduction, "Mastectomy", 300 - slave.boobs,
+						"perform mastectomy",
+						slave => {
+							slave.boobs = 300;
+						},
+						V.surgeryCost, 30, "mastectomy"
+					));
+				}
+			}
+		}
+		return r;
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @param {App.Medicine.Surgery.SizingOptions} [options]
+	 * @returns {App.Medicine.Surgery.Procedure[]}
+	 */
+	function buttSizingProcedures(slave, options = {}) {
+		const V = State.variables;
+		const thisArcology = V.arcologies[0];
+		const largeImplantsAvailable = thisArcology.FSTransformationFetishistResearch === 1;
+		const advancedFillableImplantsAvailable = V.ImplantProductionUpgrade === 1;
+		const pronouns = getPronouns(slave);
+		const {he, His} = pronouns;
+
+		const types = App.Medicine.Keys.Surgery.Target.butt; // shortcuts
+		const helper = new App.Medicine.Surgery.ListHelpers(slave, "butt", types, pronouns, false);
+
+		let r = [];
+
+		if (options.augmentation) {
+			if (slave.indentureRestrictions >= 2) {
+				r.push(App.Medicine.Surgery.makeImpossibleOption(types.installImplant, "Change butt size", `<em>${His} indenture forbids elective surgery</em>`));
+			} else if (slave.butt > 19) {
+				r.push(App.Medicine.Surgery.makeImpossibleOption(types.fillUp, "Increase butt", `<em>${His} butt is as large as it can possibly get</em>`));
+			} else if (slave.butt > 7 && !largeImplantsAvailable && thisArcology.FSAssetExpansionist === "unset" && slave.buttImplantType !== 1) {
+				r.push(App.Medicine.Surgery.makeImpossibleOption(types.installImplant, "Increase butt", `<em>${His} butt is as large as $${he} can physically support</em>`));
+			} else if (slave.buttImplant > 7 && !largeImplantsAvailable && slave.buttImplantType !== 1) {
+				r.push(App.Medicine.Surgery.makeImpossibleOption(types.installImplant, "Increase butt", `<em>${His} butt implants are filled to capacity</em>`));
+			} else if (slave.buttImplant === 0) {
+				r.push(helper.installImplants("standard", 0, 1));
+				if (options.strings) {
+					r.push(helper.installImplants("string", 1, 1));
+				}
+			} else if (slave.buttImplant === 1 && slave.buttImplantType !== 1) {
+				r.push(helper.replaceImplants("bigger", 0, 2));
+			} else if (slave.buttImplant === 2 && slave.buttImplantType !== 1) {
+				r.push(helper.replaceImplants("fillable", 0, 3));
+			} else if (slave.buttImplant === 4 && slave.buttImplantType !== 1) {
+				r.push(App.Medicine.Surgery.makeImpossibleOption(types.fillUp, "Increase size", `<em>${His} implants are filled to capacity</em>`));
+				const advancedFillable = helper.replaceImplants("advanced fillable", 0, 5);
+				if (!advancedFillableImplantsAvailable) {
+					advancedFillable.costs += 10000;
+					advancedFillable.label += " (special order)";
+					advancedFillable.description += " (special order)";
+				}
+				r.push(advancedFillable);
+			} else if (slave.buttImplant === 8 && slave.buttImplantType !== 1 && advancedFillableImplantsAvailable) {
+				r.push(helper.replaceImplants("hyper fillable", 0, 9));
+			} else if (slave.buttImplant > 2 && slave.buttImplantType !== 1) {
+				r.push(helper.fillUp(1));
+			}
+		}
+
+		if (options.reduction) {
+			if (slave.buttImplant > 0) {
+				if (slave.indentureRestrictions < 2) {
+					if (slave.buttImplantType === 1 && slave.buttImplant > 1) {
+						r.push(helper.drain(1));
+					}
+					r.push(helper.removeImplants());
+				}
+			}
+			if ((slave.butt > 1) && (slave.buttImplant === 0)) {
+				if (slave.indentureRestrictions < 2) {
+					r.push(helper.reduce("reduce", 1));
+				}
+			}
+		}
+		return r;
+	}
+}();
diff --git a/src/js/utilJS.js b/src/js/utilJS.js
index 5f66ee8b4a470c3bb8dbb79061fbdc777904dfa8..5962f8d7a24ea7cc9c35423bc77be8ff779d825f 100644
--- a/src/js/utilJS.js
+++ b/src/js/utilJS.js
@@ -2347,6 +2347,7 @@ App.UI.link = function() {
 	// reset all handlers for each passage
 	$(document).on(':passageinit', function() {
 		State.temporary.linkHandlers = {};
+		counter = 0;
 	});
 
 	return makeLink;
diff --git a/src/uncategorized/remoteSurgery.tw b/src/uncategorized/remoteSurgery.tw
index 2a0d5d99598bcfbb2af36145a19f0b466752d175..c8da587b6fcc043ab45f5ef8f07026e1b1bdf99a 100644
--- a/src/uncategorized/remoteSurgery.tw
+++ b/src/uncategorized/remoteSurgery.tw
@@ -544,78 +544,10 @@ $He has
 <<else>>
 	no implants.
 <</if>>
-<<if $activeSlave.boobs > 50000>>
-	//$His breasts are as large as $he can physically support//
-<<elseif $activeSlave.boobsImplant > 10000 && $arcologies[0].FSTransformationFetishistResearch != 1 && $activeSlave.boobsImplantType != 1>>
-	//$His implants are filled to capacity//
-<<elseif $activeSlave.indentureRestrictions >= 2>>
-	//$His indenture forbids elective surgery//
-<<elseif $activeSlave.breastMesh == 1>>
-	//$His supportive mesh implant blocks implantation//
-<<elseif $activeSlave.boobsImplant == 0>>
-	[[String implants|Surgery Degradation][$activeSlave.boobsImplant = 400, $activeSlave.boobsImplantType = 1,$activeSlave.boobs += 400,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] |
-	<<if $surgeryUpgrade == 1>>[[Large implants|Surgery Degradation][$activeSlave.boobsImplant = 600,$activeSlave.boobs += 600,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] |<</if>>
-	[[Standard implants|Surgery Degradation][$activeSlave.boobsImplant = 400,$activeSlave.boobs += 400,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] |
-	[[Small implants|Surgery Degradation][$activeSlave.boobsImplant = 200,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]]
-<<elseif $activeSlave.boobsImplant > 10000 && $activeSlave.boobsImplantType != 1 && $ImplantProductionUpgrade == 1>>
-	[[Add inert filler|Surgery Degradation][$activeSlave.boobsImplant += 1000,$activeSlave.boobs += 1000,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]]
-<<elseif $activeSlave.boobsImplant > 9800 && $activeSlave.boobsImplantType != 1 && $ImplantProductionUpgrade == 1>>
-	[[Hyper fillable implants|Surgery Degradation][$activeSlave.boobsImplant = 11000,$activeSlave.boobs += 800,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]]
-<<elseif $activeSlave.boobsImplant > 2000 && $activeSlave.boobsImplantType != 1>>
-	[[Add inert filler|Surgery Degradation][$activeSlave.boobsImplant += 400,$activeSlave.boobs += 400,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]]
-<<elseif $activeSlave.boobsImplant > 1800 && $activeSlave.boobsImplantType != 1>>
-	$His implants are filled to capacity.
-	<<if $ImplantProductionUpgrade == 1>>
-		[[Advanced fillable implants|Surgery Degradation][$activeSlave.boobsImplant = 2200,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]]
-	<<else>>
-		[[Special order advanced fillable implants|Surgery Degradation][$activeSlave.boobsImplant = 2200,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave)+10000, $activeSlave.health -= 10,$surgeryType = "boobs"]] //Will cost an additional <<= cashFormat(10000)>>//
-	<</if>>
-<<elseif $activeSlave.boobsImplant > 600 && $activeSlave.boobsImplantType != 1>>
-	[[Add inert filler|Surgery Degradation][$activeSlave.boobsImplant += 200,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]]
-<<elseif $activeSlave.boobsImplant > 400 && $activeSlave.boobsImplantType != 1>>
-	[[Fillable implants|Surgery Degradation][$activeSlave.boobsImplant = 800,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]]
-<<elseif $activeSlave.boobsImplant > 200 && $activeSlave.boobsImplantType != 1>>
-	[[Large implants|Surgery Degradation][$activeSlave.boobsImplant = 600,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]]
-<<elseif $activeSlave.boobsImplant > 0 && $activeSlave.boobsImplantType != 1>>
-	[[Standard implants|Surgery Degradation][$activeSlave.boobsImplant = 400,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] | [[Large implants|Surgery Degradation][$activeSlave.boobsImplant = 600,$activeSlave.boobs += 400,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]]
-<</if>>
 
-<<if $activeSlave.boobsImplant != 0>>
-	<<if $activeSlave.boobsImplantType == 1 && $activeSlave.boobsImplant > 400>>
-		<<if $activeSlave.boobsImplant > 8000>>
-			| [[Drain 1000cc|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-1000),$activeSlave.boobsImplant = ($activeSlave.boobsImplant-1000), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]]
-		<<elseif $activeSlave.boobsImplant > 5000>>
-			| [[Drain 750cc|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-750),$activeSlave.boobsImplant = ($activeSlave.boobsImplant-750), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]]
-		<<elseif $activeSlave.boobsImplant > 2000>>
-			| [[Drain 500cc|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-500),$activeSlave.boobsImplant = ($activeSlave.boobsImplant-500), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]]
-		<<elseif $activeSlave.boobsImplant > 1000>>
-			| [[Drain 250cc|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-250),$activeSlave.boobsImplant = ($activeSlave.boobsImplant-250), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]]
-		<<elseif $activeSlave.boobsImplant > 500>>
-			| [[Drain 100cc|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-100),$activeSlave.boobsImplant = ($activeSlave.boobsImplant-100), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]]
-		<</if>>
-	<</if>>
-	| [[Remove breast implants|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-$activeSlave.boobsImplant),$activeSlave.boobsImplant = 0,$activeSlave.boobsImplantType = 0, $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]]
-<</if>>
-<<if ($activeSlave.boobs > 300) && ($activeSlave.boobsImplant == 0)>>
-	<<if $activeSlave.indentureRestrictions >= 2>>
-	<<else>>
-		| [[Reduce breasts|Surgery Degradation][$activeSlave.boobs -= 200, $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]]
-		<<if $activeSlave.boobs < 675>>
-			| [[Slightly reduce breasts|Surgery Degradation][$activeSlave.boobs -= 25, $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]]
-		<</if>>
-	<</if>>
-<</if>>
-<<if ($activeSlave.boobs >= 7000) && ($activeSlave.boobsImplant == 0)>>
-	<<if $activeSlave.indentureRestrictions >= 2 || ($activeSlave.breedingMark == 1 && $propOutcome == 1)>>
-	<<else>>
-		| [[Mastectomy|Surgery Degradation][$activeSlave.boobs = 300, $activeSlave.breastMesh = 0, $activeSlave.health -= 30,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "mastectomy+"]]
-	<</if>>
-<<elseif ($activeSlave.boobs >= 2000) && ($activeSlave.boobsImplant == 0)>>
-	<<if $activeSlave.indentureRestrictions >= 2 || ($activeSlave.breedingMark == 1 && $propOutcome == 1)>>
-	<<else>>
-		| [[Mastectomy|Surgery Degradation][$activeSlave.boobs = 300, $activeSlave.breastMesh = 0, $activeSlave.health -= 30,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "mastectomy"]]
-	<</if>>
-<</if>>
+<<set _surgeries = App.Medicine.Surgery.sizingProcedures.boobs($activeSlave, App.Medicine.Surgery.allSizingOptions())>>
+<<set _surgeryLinks = _surgeries.map(s => App.Medicine.Surgery.makeLink("Surgery Degradation", s, $activeSlave))>>
+<<= _surgeryLinks.join('&thinsp;|&thinsp;')>>
 
 <br>&nbsp;&nbsp;&nbsp;&nbsp;
 <<if $activeSlave.boobsImplant != 0>>
@@ -959,46 +891,9 @@ $He's got a
 	<</if>>
 <</if>>
 
-<<if $activeSlave.indentureRestrictions >= 2>>
-	//$His indenture forbids elective surgery//
-<<elseif $activeSlave.butt > 19>>
-	//$His butt is as large as it can possibly get//
-<<elseif $activeSlave.butt > 7 && $arcologies[0].FSTransformationFetishistResearch != 1 && $arcologies[0].FSAssetExpansionist == "unset" && $activeSlave.buttImplantType != 1>>
-	//$His butt is as large as $he can physically support//
-<<elseif $activeSlave.buttImplant > 7 && $arcologies[0].FSTransformationFetishistResearch != 1 && $activeSlave.buttImplantType != 1>>
-	//$His butt implants are filled to capacity//
-<<elseif $activeSlave.buttImplant == 0>>
-	[[Implants|Surgery Degradation][$activeSlave.buttImplant = 1,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]]
-	| [[String implants|Surgery Degradation][$activeSlave.buttImplant = 1,$activeSlave.butt += 1,$activeSlave.buttImplantType = 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]]
-<<elseif $activeSlave.buttImplant == 1 && $activeSlave.buttImplantType != 1>>
-	[[Bigger implants|Surgery Degradation][$activeSlave.buttImplant = 2,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]]
-<<elseif $activeSlave.buttImplant == 2 && $activeSlave.buttImplantType != 1>>
-	[[Fillable implants|Surgery Degradation][$activeSlave.buttImplant = 3,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]]
-<<elseif $activeSlave.buttImplant == 4 && $activeSlave.buttImplantType != 1>>
-	$His implants are filled to capacity.
-	<<if $ImplantProductionUpgrade == 1>>
-		[[Advanced fillable implants|Surgery Degradation][$activeSlave.buttImplant = 5,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]]
-	<<else>>
-		[[Special order advanced fillable implants|Surgery Degradation][$activeSlave.buttImplant = 5,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave)+10000, $activeSlave.health -= 10,$surgeryType = "butt"]] //Will cost an additional <<= cashFormat(10000)>>//
-	<</if>>
-<<elseif $activeSlave.buttImplant == 8 && $activeSlave.buttImplantType != 1 && $ImplantProductionUpgrade == 1>>
-	[[Hyper fillable implants|Surgery Degradation][$activeSlave.buttImplant = 9,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]]
-<<elseif $activeSlave.buttImplant > 2 && $activeSlave.buttImplantType != 1>>
-	[[Add inert filler|Surgery Degradation][$activeSlave.buttImplant += 1,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]]
-<</if>>
-<<if $activeSlave.buttImplant != 0>>
-	<<if $activeSlave.indentureRestrictions < 2>>
-		<<if $activeSlave.buttImplantType == 1 && $activeSlave.buttImplant > 1>>
-			| [[Drain implants|Surgery Degradation][$activeSlave.butt = ($activeSlave.butt-1),$activeSlave.buttImplant = ($activeSlave.buttImplant-1), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "buttLoss"]]
-		<</if>>
-		| [[Remove implants|Surgery Degradation][$activeSlave.butt = ($activeSlave.butt-$activeSlave.buttImplant),$activeSlave.buttImplant = 0, $activeSlave.health -= 10,$activeSlave.buttImplantType = 0,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "buttLoss"]]
-	<</if>>
-<</if>>
-<<if ($activeSlave.butt > 1) && ($activeSlave.buttImplant == 0)>>
-	<<if $activeSlave.indentureRestrictions < 2>>
-		| [[Reduce ass|Surgery Degradation][$activeSlave.butt -= 1, $activeSlave.health -= 10,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "buttLoss"]]
-	<</if>>
-<</if>>
+<<set _surgeries = App.Medicine.Surgery.sizingProcedures.butt($activeSlave, App.Medicine.Surgery.allSizingOptions())>>
+<<set _surgeryLinks = _surgeries.map(s => App.Medicine.Surgery.makeLink("Surgery Degradation", s, $activeSlave))>>
+<<= _surgeryLinks.join('&thinsp;|&thinsp;')>>
 
 <br><br>
 Work on $his sex: