diff --git a/src/interaction/prostheticConfig.tw b/src/interaction/prostheticConfig.tw
index 7a732cfbff4c4bc42de8a75e58878723887f004d..6ab665cbe8c1c61220bbcbdd69ddfdd56ad0e4c9 100644
--- a/src/interaction/prostheticConfig.tw
+++ b/src/interaction/prostheticConfig.tw
@@ -148,67 +148,7 @@ This room is lined with shelves and cabinets, it could be easily mistaken for a
 	<</if>>
 <</if>>
 
-<<if $activeSlave.readyProsthetics.length > 0>>
-	<br><br>
-	<<if $activeSlave.fuckdoll != 0>>
-		// A Fuckdoll can't use prosthetic limbs. //
-	<<elseif hasAnyNaturalLimbs($activeSlave)>>
-		// $He must be a quadruple amputee to attach prosthetic limbs. //
-	<<elseif $activeSlave.PLimb == 0>>
-		// $He must have a prosthetic interface installed to attach prosthetic limbs. //
-	<<else>>
-		/* Currently prosthetics are all or nothing; will be changed */
-		<<if getLeftArmID($activeSlave) > 1>>
-			//$He currently has
-			<<switch getLeftArmID($activeSlave)>>
-			<<case 2>> <<= addA(setup.prosthetics.basicL.name)>>
-			<<case 3>> <<= addA(setup.prosthetics.sexL.name)>>
-			<<case 4>> <<= addA(setup.prosthetics.beautyL.name)>>
-			<<case 5>> <<= addA(setup.prosthetics.combatL.name)>>
-			<<case 6>> <<= addA(setup.prosthetics.cyberneticL.name)>>
-			<</switch>>
-			installed.//<br>
-			<<link "Detach <<= $his>> limbs" "Prosthetics Configuration">>
-				<<set removeLimbs($activeSlave, "all"), $prostheticsConfig = "removeLimbs">>
-			<</link>>
-			<br><br>
-		<</if>>
-		/* TODO save .legsTat and .armsTat / link them to prosthetic*/
-		<<if getLeftArmID($activeSlave) !== 2 && $activeSlave.readyProsthetics.findIndex(function(p) {return p.id == "basicL"}) != -1>>
-			<<link "Attach <<= addA(setup.prosthetics.basicL.name)>>" "Prosthetics Configuration">>
-				<<set removeLimbs($activeSlave, "all"), attachLimbs($activeSlave, "all", 2), $prostheticsConfig = "basicPLimbs">>
-			<</link>>
-			<br>
-		<</if>>
-		<<if getLeftArmID($activeSlave) !== 3 && $activeSlave.readyProsthetics.findIndex(function(p) {return p.id == "sexL"}) != -1>>
-			<<link "Attach <<= addA(setup.prosthetics.sexL.name)>>" "Prosthetics Configuration">>
-				<<set removeLimbs($activeSlave, "all"), attachLimbs($activeSlave, "all", 3), $prostheticsConfig = "sexPLimbs">>
-			<</link>>
-			<br>
-		<</if>>
-		<<if getLeftArmID($activeSlave) !== 4 && $activeSlave.readyProsthetics.findIndex(function(p) {return p.id == "beautyL"}) != -1>>
-			<<link "Attach <<= addA(setup.prosthetics.beautyL.name)>>" "Prosthetics Configuration">>
-				<<set removeLimbs($activeSlave, "all"), attachLimbs($activeSlave, "all", 4), $prostheticsConfig = "beautyPLimbs">>
-			<</link>>
-			<br>
-		<</if>>
-		<<if getLeftArmID($activeSlave) !== 5 && $activeSlave.readyProsthetics.findIndex(function(p) {return p.id == "combatL"}) != -1>>
-			<<link "Attach <<= addA(setup.prosthetics.combatL.name)>>" "Prosthetics Configuration">>
-				<<set removeLimbs($activeSlave, "all"), attachLimbs($activeSlave, "all", 5), $prostheticsConfig = "combatPLimbs">>
-			<</link>>
-			<br>
-		<</if>>
-		<<if getLeftArmID($activeSlave) !== 6 && $activeSlave.readyProsthetics.findIndex(function(p) {return p.id == "cyberneticL"}) != -1>>
-			<<if $activeSlave.PLimb == 2>>
-				<<link "Attach <<= addA(setup.prosthetics.cyberneticL.name)>>" "Prosthetics Configuration">>
-					<<set removeLimbs($activeSlave, "all"), attachLimbs($activeSlave, "all", 6), $prostheticsConfig = "cyberPLimbs">>
-				<</link>>
-			<<else>>
-				// $He must have <<= addA(setup.prosthetics.interfaceP2.name)>> installed to attach <<= addA(setup.prosthetics.cyberneticL.name)>>. //
-			<</if>>
-		<</if>>
-	<</if>>
-<</if>>
+<<= App.Desc.limbChange().selector($activeSlave, App.Desc.limbChange().currentLimbs($activeSlave))>>
 
 <<if $activeSlave.PTail == 1>><br><br>
 	$He has a neural tail interface installed. You can assign and adjust $his tail here.
@@ -342,6 +282,12 @@ Fit prosthetics to $him:
 		$He has a panicked expression when $his vision suddenly goes out.
 	<</if>>
 
+<<case "limbs">>
+	<<set $prostheticsConfig = "main", $nextButton = "Continue", $nextLink = "Prosthetics Configuration">>
+	<<= App.Desc.limbChange().reaction($activeSlave, $oldLimbs)>>
+	<<unset $oldLimbs>>
+
+/*
 <<case "basicPLimbs">>
 	<<set $prostheticsConfig = "main", $nextButton = "Continue", $nextLink = "Prosthetics Configuration">>
 	Attaching $his limbs is a simple procedure, you simply push a connector on each limb into the socket in $his implants until the lock engages.<<if $activeSlave.PLimb == 2>> $He jumps a bit as limbs connect to $his nerves.<</if>>
@@ -416,6 +362,7 @@ Fit prosthetics to $him:
 	<<else>>
 		You order $him to lie down on the table and proceed to remove $his limbs. $He <<if canSee($activeSlave)>>watches<<elseif canHear($activeSlave)>>listens<<else>>waits<</if>> with a bitter expression as you work.
 	<</if>>
+*/
 
 <<case "hearing">>
 	<<set $prostheticsConfig = "main", $nextButton = "Continue", $nextLink = "Prosthetics Configuration">>
@@ -459,11 +406,12 @@ Fit prosthetics to $him:
 	<<else>>admires $his new tail.
 	<</if>>
 
+/*
 <<case "interface">>
 	<span id="attach">
 	<<set _first = 1>>
 	/*TODO save .legsTat and .armsTat / link them to prosthetic*/
-	<<if getLeftArmID($activeSlave) !== 2 && $activeSlave.readyProsthetics.findIndex(function(p) {return p.id == "basicL"}) != -1>>
+/*	<<if getLeftArmID($activeSlave) !== 2 && $activeSlave.readyProsthetics.findIndex(function(p) {return p.id == "basicL"}) != -1>>
 		<<if _first>>
 			<br><br>Since you already have prepared limbs for $him you might as well attach them while you are working on $him:<br>
 			<<set _first = 0>>
@@ -520,5 +468,5 @@ Fit prosthetics to $him:
 		<</if>>
 	<</if>>
 	</span>
-
+*/
 <</switch>>
diff --git a/src/js/itemAvailability.js b/src/js/itemAvailability.js
index 745ab63bda8def3556d0ce4fe20131075b0d6cc2..36923b4fe5a7c570b4acf37d16c9efc76058d301 100644
--- a/src/js/itemAvailability.js
+++ b/src/js/itemAvailability.js
@@ -169,3 +169,7 @@ window.isItemAccessible = function(string) {
 			return true;
 	}
 };
+
+window.isProstheticAvailable = function(slave, prosthetic) {
+	return slave.readyProsthetics.findIndex(function(p) { return p.id === prosthetic; }) !== -1;
+};
diff --git a/src/js/slaveStatsChecker.js b/src/js/slaveStatsChecker.js
index 06f253d191daa9d06af349157ad6fac6d00eca77..0e52cc0a74f98ed23accf0a747991072f924acdb 100644
--- a/src/js/slaveStatsChecker.js
+++ b/src/js/slaveStatsChecker.js
@@ -1262,7 +1262,3 @@ window.armsAndLegs = function(slave, arms = "arms", arm = "arm", legs = "legs",
 
 	return r;
 };
-
-window.isProstheticAvailable = function(slave, prosthetic) {
-	return slave.readyProsthetics.findIndex(function(p) { return p.id === prosthetic; }) !== -1;
-};
diff --git a/src/npc/descriptions/limbs.js b/src/npc/descriptions/limbs.js
new file mode 100644
index 0000000000000000000000000000000000000000..798c9ec42a1e5cbb7afe2b990e82da78990f8b99
--- /dev/null
+++ b/src/npc/descriptions/limbs.js
@@ -0,0 +1,258 @@
+App.Desc.limbChange = function() {
+	return {
+		currentLimbs: currentLimbs,
+		amputate: amputate,
+		prosthetic: prosthetic,
+		selector: selector,
+		applySelector: applySelector,
+		reaction: reaction
+	};
+
+	/**
+	 * Generates an object usable with the standard limb check functions.
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {{}}
+	 */
+	function currentLimbs(slave) {
+		let s = {arm: {left: {type: 1}, right: {type: 1}}, leg: {left: {type: 1}, right: {type: 1}}, PLimb: 0};
+		if (hasLeftArm(slave)) {
+			s.arm.left.type = getLeftArmID(slave);
+		} else {
+			s.arm.left = null;
+		}
+		if (hasRightArm(slave)) {
+			s.arm.right.type = getRightArmID(slave);
+		} else {
+			s.arm.right = null;
+		}
+		if (hasLeftLeg(slave)) {
+			s.leg.left.type = getLeftLegID(slave);
+		} else {
+			s.leg.left = null;
+		}
+		if (hasRightLeg(slave)) {
+			s.leg.right.type = getRightLegID(slave);
+		} else {
+			s.leg.right = null;
+		}
+		s.PLimb = slave.PLimb;
+		return s;
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @param {{}} oldLimbs
+	 * @param {string} returnTo
+	 * @returns {string}
+	 */
+	function amputate(slave, oldLimbs, returnTo) {
+		const {his} = getPronouns(slave);
+		let implant = false;
+		let r = "";
+
+		if (slave.PLimb < 1 && isProstheticAvailable(slave, "interfaceP1")) {
+			implant = true;
+			r += `<<link "Install basic interface">>` +
+				`<<set $activeSlave.PLimb = 1, $activeSlave.health -= 10>>` +
+				`<<replace "#amputate">><<= App.Desc.limbChange().prosthetic($activeSlave, ${JSON.stringify(oldLimbs)}, "${returnTo}")>><</replace>>` +
+				`<</link>>`;
+		}
+		if (slave.PLimb < 2 && isProstheticAvailable(slave, "interfaceP2")) {
+			if (implant) {
+				r += "<br>";
+			}
+			implant = true;
+			r += `<<link "Install advanced interface">>` +
+				`<<set $activeSlave.PLimb = 2, $activeSlave.health -= 10>>` +
+				`<<replace "#amputate">><<= App.Desc.limbChange().prosthetic($activeSlave, ${JSON.stringify(oldLimbs)}, "${returnTo}")>><</replace>>` +
+				`<</link>>`;
+		}
+
+		if (implant) {
+			return `<span id="amputate">
+					Since you already have a prosthetic interface prepared for this slave, you can install it during the operation.
+					The procedure will put additional strain on ${his} health but less so than if you were to perform the procedures separately.
+
+					${r}
+					<<link "Do not install">>
+					<<replace "#amputate">><<= App.Desc.limbChange().reaction($activeSlave, ${JSON.stringify(oldLimbs)}, "${returnTo}")>><</replace>>
+					<</link>>
+					</span>`;
+		}
+
+		if (slave.PLimb > 0) {
+			return prosthetic(slave, oldLimbs, returnTo);
+		}
+		return reaction(slave, oldLimbs, returnTo);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @param {{}} oldLimbs
+	 * @param {string} returnTo
+	 * @returns {string}
+	 */
+	function prosthetic(slave, oldLimbs, returnTo) {
+		if (!(isProstheticAvailable(slave, "basicL") || isProstheticAvailable(slave, "sexL")
+			|| isProstheticAvailable(slave, "beautyL") || isProstheticAvailable(slave, "combatL")
+			|| (isProstheticAvailable(slave, "cyberneticL") && slave.PLimb > 1))) {
+			return reaction(slave, oldLimbs, returnTo);
+		}
+		const {him} = getPronouns(slave);
+
+		let r = `<br>Since you already have limbs prepared for ${him} you might as well attach them while you are working on ${him}:` +
+			selector(slave, oldLimbs, returnTo);
+
+		return `<span id="selector">${r}</span>`;
+	}
+
+	/**
+	 * Displays a selector for prosthetic limbs of $activeSlave
+	 * @param {App.Entity.SlaveState} slave
+	 * @param {{}} oldLimbs
+	 * @param {string} [returnTo]
+	 * @returns {string}
+	 */
+	function selector(slave, oldLimbs, returnTo = "") {
+		if (hasAllNaturalLimbs((slave))) {
+			return "//You must amputate your slaves limbs before you can attach prosthetics.//";
+		}
+		if (slave.PLimb < 1) {
+			return "//You must install a prosthetic interface before you can attach prosthetics.//";
+		}
+		const state = currentState(slave);
+
+		/**
+		 * Generates an array with the current limbs of a slave.
+		 * @param {App.Entity.SlaveState} slave
+		 * @returns {[number]}
+		 */
+		function currentState(slave) {
+			let a = [];
+			a[0] = getLeftArmID(slave);
+			a[1] = getRightArmID(slave);
+			a[2] = getLeftLegID(slave);
+			a[3] = getRightLegID(slave);
+			return a;
+		}
+
+		/**
+		 * @param {number} pos
+		 * @param {number} id
+		 * @returns {string}
+		 */
+		function entry(pos, id) {
+			if (state[pos] === 1) {
+				return "<div></div>";
+			}
+			return `<div><<radiobutton "_newState[${pos}]" ${id}${state[pos] === id ? " checked" : ""}>></div>`;
+		}
+
+		/**
+		 * @param {string} title
+		 * @param {number} id
+		 * @returns {string}
+		 */
+		function row(title, id) {
+			return `<div>${title}</div>${entry(0, id)}${entry(1, id)}${entry(2, id)}${entry(3, id)}`;
+		}
+
+		let r = "<div></div><div>Left Arm</div><div>Right Arm</div><div>Left Leg</div><div>Right Leg</div>";
+
+		r += row("None", 0);
+		if (isProstheticAvailable(slave, "basicL")) {
+			r += row("Basic prosthetic", 2);
+		}
+		if (isProstheticAvailable(slave, "sexL")) {
+			r += row("Advanced sex limb", 3);
+		}
+		if (isProstheticAvailable(slave, "beautyL")) {
+			r += row("Advanced beauty limb", 4);
+		}
+		if (isProstheticAvailable(slave, "combatL")) {
+			r += row("Advanced combat limb", 5);
+		}
+		if (isProstheticAvailable(slave, "cyberneticL")) {
+			if (slave.PLimb > 1) {
+				r += row("Cybernetic limb", 6);
+			} else {
+				r += "<div class='cyber' style='text-align: center;'>//Install an advanced interface to attach cybernetic limbs.//</div>";
+			}
+		}
+
+		r = `<br><br><<set _newState = [${state}]>>` +
+			"<style> .selector{display: grid; grid-template-columns: 200px 100px 100px 100px 100px;}" +
+			".cyber {grid-column-start: 1; grid-column-end: 6;</style>" +
+			`<div class='selector'>${r}</div>${apply()}`;
+
+		return r;
+
+		function apply() {
+			let s;
+			if (!returnTo) {
+				s = `<<set $prostheticsConfig = "limbs", $oldLimbs = ${JSON.stringify(oldLimbs)}>>` +
+					'<<goto "Prosthetics Configuration">>';
+			} else {
+				s = `<<replace "#selector">><<= App.Desc.limbChange().reaction($activeSlave, ${JSON.stringify(oldLimbs)}, "${returnTo}")>><</replace>>`;
+			}
+
+			return `<<link "Apply">><<run App.Desc.limbChange().applySelector($activeSlave, _newState)>>${s}<</link>>`;
+		}
+	}
+
+	/**
+	 *
+	 * @param {App.Entity.SlaveState} slave
+	 * @param {[number]} newState
+	 */
+	function applySelector(slave, newState) {
+		if (getLeftArmID(slave) !== newState[0]) {
+			if (getLeftArmID(slave) > 1) {
+				removeLimbs(slave, "left arm");
+			}
+			if (newState[0] > 1) {
+				attachLimbs(slave, "left arm", newState[0]);
+			}
+		}
+		if (getRightArmID(slave) !== newState[1]) {
+			if (getRightArmID(slave) > 1) {
+				removeLimbs(slave, "right arm");
+			}
+			if (newState[1] > 1) {
+				attachLimbs(slave, "right arm", newState[1]);
+			}
+		}
+		if (getLeftLegID(slave) !== newState[2]) {
+			if (getLeftLegID(slave) > 1) {
+				removeLimbs(slave, "left leg");
+			}
+			if (newState[2] > 1) {
+				attachLimbs(slave, "left leg", newState[2]);
+			}
+		}
+		if (getRightLegID(slave) !== newState[3]) {
+			if (getRightLegID(slave) > 1) {
+				removeLimbs(slave, "right leg");
+			}
+			if (newState[3] > 1) {
+				attachLimbs(slave, "right leg", newState[3]);
+			}
+		}
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @param {{}} oldLimbs
+	 * @param {string} returnTo
+	 * @returns {string}
+	 */
+	function reaction(slave, oldLimbs, returnTo = "") {
+		let r = "//Slave's reaction//";
+		// TODO
+		// reaction based on limb change & devotion/trust
+		if (returnTo) {
+			r = `<br><br>${r}<br>[[Continue|${returnTo}]]`;
+		}
+		return r;
+	}
+};
diff --git a/src/uncategorized/remoteSurgery.tw b/src/uncategorized/remoteSurgery.tw
index 870d6ea06c218c2ab4f665a0bf6e35a8e41828a8..8a87314d014c1cdac7ea965898980321ee821eaa 100644
--- a/src/uncategorized/remoteSurgery.tw
+++ b/src/uncategorized/remoteSurgery.tw
@@ -1750,6 +1750,8 @@ Work on $him structurally:
 	&nbsp;&nbsp;&nbsp;&nbsp;
 	<<link "Amputate limb(s)">>
 		<<set _atleastOne = 0>>
+		/* temporary story variable */
+		<<set $oldLimbs = App.Desc.limbChange().currentLimbs($activeSlave)>>
 		<<if _LA === 1>>
 			<<run removeLimbs($activeSlave, "left arm")>>
 			<<set _atleastOne++>>
@@ -1771,26 +1773,24 @@ Work on $him structurally:
 			<<if !hasAnyArms($activeSlave)>>
 				<<set $activeSlave.releaseRules = "restrictive">>
 			<</if>>
-			<<if !hasAnyNaturalLimbs($activeSlave) && (isProstheticAvailable($activeSlave, "interfaceP1") || isProstheticAvailable($activeSlave, "interfaceP2"))>>
-				<<set $surgeryType = "amp1">>
-			<<else>>
-				<<set $surgeryType = "amp">>
-			<</if>>
+			<<set $surgeryType = "amp">>
 			<<goto "Surgery Degradation">>
+		<<else>>
+			<<unset $oldLimbs>>
 		<</if>>
 	<</link>> //This will greatly restrict $him.//
 	<br>
 <</if>> /* extreme toggle */
 
-<<if isAmputee($activeSlave) && $activeSlave.PLimb == 0>>
-	<<if $activeSlave.readyProsthetics.findIndex(function(p) {return p.id == "interfaceP1"}) != -1>> |
-		[[Install basic prosthetic interface|Surgery Degradation][$activeSlave.PLimb = 1, cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 20, $surgeryType = "PLimb interface1"]]
+<<if !hasAllNaturalLimbs($activeSlave) && $activeSlave.PLimb == 0>>
+	<<if isProstheticAvailable($activeSlave, "interfaceP1")>>
+		[[Install basic prosthetic interface|Surgery Degradation][$oldLimbs = App.Desc.limbChange().currentLimbs($activeSlave), $activeSlave.PLimb = 1, cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 20, $surgeryType = "PLimb interface"]]
 	<</if>>
-	<<if $activeSlave.readyProsthetics.findIndex(function(p) {return p.id == "interfaceP2"}) != -1>> |
-		[[Install advanced prosthetic interface|Surgery Degradation][$activeSlave.PLimb = 2, cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 20, $surgeryType = "PLimb interface2"]]
+	<<if isProstheticAvailable($activeSlave, "interfaceP2")>> |
+		[[Install advanced prosthetic interface|Surgery Degradation][$oldLimbs = App.Desc.limbChange().currentLimbs($activeSlave), $activeSlave.PLimb = 2, cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 20, $surgeryType = "PLimb interface"]]
 	<</if>>
-<<elseif isAmputee($activeSlave) && $activeSlave.PLimb == 1 && $activeSlave.readyProsthetics.findIndex(function(p) {return p.id == "interfaceP2"}) != -1>> |
-	[[Upgrade advanced prosthetic interface|Surgery Degradation][$activeSlave.PLimb = 2, cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 5, $surgeryType = "PLimb interface3"]]
+<<elseif $activeSlave.PLimb == 1 && isProstheticAvailable($activeSlave, "interfaceP2")>>
+	[[Upgrade to advanced prosthetic interface|Surgery Degradation][$oldLimbs = App.Desc.limbChange().currentLimbs($activeSlave), $activeSlave.PLimb = 2, cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 5, $surgeryType = "PLimb interface"]]
 <</if>>
 
 <br>&nbsp;&nbsp;&nbsp;&nbsp;
diff --git a/src/uncategorized/surgeryDegradation.tw b/src/uncategorized/surgeryDegradation.tw
index 8820520c09674f3c5862b3ccdd3ca6e1189d8e01..7b746d054ba044a05412f967a2334d060116864d 100644
--- a/src/uncategorized/surgeryDegradation.tw
+++ b/src/uncategorized/surgeryDegradation.tw
@@ -1842,6 +1842,17 @@ As the remote surgery's long recovery cycle completes,
 	<</if>>
 
 <<case "amp">>
+	<<set $nextButton = " ">>
+	<<= App.Desc.limbChange().amputate($activeSlave, $oldLimbs, "Remote Surgery")>>
+	<<unset $oldLimbs>>
+
+<<case "PLimb interface">>
+	<<set $nextButton = " ">>
+	<<= App.Desc.limbChange().prosthetic($activeSlave, $oldLimbs, "Remote Surgery")>>
+	<<unset $oldLimbs>>
+
+	/*
+<<case "bla">>
 	<<if $activeSlave.fetish == "mindbroken">>
 		Of course, $he could not walk out of the surgery; you carried $him. $He squirms the entire time, trying to move the arms and legs $he now lacks. Since the surgery was invasive, @@.red;$his health has been greatly affected.@@
 	<<elseif ($activeSlave.devotion > 50)>>
@@ -1882,6 +1893,7 @@ As the remote surgery's long recovery cycle completes,
 	<<include "Prosthetics Configuration">>
 	<<set $nextLink = "Remote Surgery">>
 
+	*/
 
 <<case "PLimb interface1">>
 	When $he is carried out of surgery $he <<if canSee($activeSlave)>>cranes $his neck to better see the ports<<else>>wiggles $his stumps trying to feel the ports<</if>> installed in $his stumps. Recovery will be @@.red;significant,@@ since the surgical implantation of anchor points for the limbs themselves and the installation of nerve impulse detectors constituted major surgery.