diff --git a/src/interaction/siDescription.js b/src/interaction/siDescription.js
index 50e62da56199304467ca45e263a5966d28c7cd75..7122453cbf018beb712563bb5896c8a3b910642c 100644
--- a/src/interaction/siDescription.js
+++ b/src/interaction/siDescription.js
@@ -55,7 +55,4 @@ App.UI.SlaveInteract.description = function(slave) {
 			);
 		}
 	}
-	function refresh() {
-		jQuery("#si-description").empty().append(description());
-	}
 };
diff --git a/src/interaction/siModify.js b/src/interaction/siModify.js
index 11f52477e4c8a234ff52ad57aa030ba2f5984a52..21effcd53d69fc9ff12bf7c551332e9173387727 100644
--- a/src/interaction/siModify.js
+++ b/src/interaction/siModify.js
@@ -56,4 +56,4 @@ App.UI.SlaveInteract.modify = function(slave) {
 	}
 
 	return el;
-};
\ No newline at end of file
+};
diff --git a/src/interaction/siRules.js b/src/interaction/siRules.js
index 98283ee1f1ce638d2fb93797da1054a4c7f2700b..49300c6a81fdc6e5135cba0ebd1ee02c260dcbda 100644
--- a/src/interaction/siRules.js
+++ b/src/interaction/siRules.js
@@ -375,10 +375,10 @@ App.UI.SlaveInteract.rules = function(slave) {
 				selected.style.fontWeight = "bold";
 			}
 
-			App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Level", level, slave);
-			App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Body part", bodyPart, slave);
-			App.UI.SlaveInteract.appendLabeledChoiceRow(el, "BDSM", BDSM, slave);
-			App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Gender", gender, slave);
+			App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Level", level, slave, refresh);
+			App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Body part", bodyPart, slave, refresh);
+			App.UI.SlaveInteract.appendLabeledChoiceRow(el, "BDSM", BDSM, slave, refresh);
+			App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Gender", gender, slave, refresh);
 
 			return el;
 		}
diff --git a/src/interaction/siUtilities.js b/src/interaction/siUtilities.js
index 9741d2004527f694de64a6a1f88183e0169105d4..017d7ff0e79708e6334bacca3782bc7913f240cd 100644
--- a/src/interaction/siUtilities.js
+++ b/src/interaction/siUtilities.js
@@ -39,7 +39,7 @@ App.UI.SlaveInteract.placeInLine = function(slave) {
  * @param {string} label
  * @param {RowItem[]} array
  * @param {App.Entity.SlaveState} slave
- * @param {Function} [refresh]
+ * @param {Function} refresh
  */
 App.UI.SlaveInteract.appendLabeledChoiceRow = function(parent, label, array, slave, refresh) {
 	if (array.length > 0) {
diff --git a/src/markets/specificMarkets/customSlaveMarket.js b/src/markets/specificMarkets/customSlaveMarket.js
new file mode 100644
index 0000000000000000000000000000000000000000..62fa1ebbfe3358daae617fdbde04eca1a0157897
--- /dev/null
+++ b/src/markets/specificMarkets/customSlaveMarket.js
@@ -0,0 +1,217 @@
+App.Markets["Custom Slave"] = function() {
+	V.encyclopedia = "Kidnapped Slaves";
+	const el = document.createElement("p");
+	const slave = V.customSlave;
+	el.append(intro());
+	el.append(age());
+	el.append(health());
+	el.append(muscles());
+	el.append(lips());
+	el.append(voice());
+
+	return el;
+
+	function intro() {
+		const {heA} = getPronouns(assistant.pronouns().main).appendSuffix('A');
+		let r = [];
+		if (V.customSlaveOrdered === 0) {
+			r.push(`You work up a new slave order for posting where slave merchants can work to fulfill it.`);
+		} else {
+			r.push(`You review your posted slave order.`);
+		}
+		if (V.assistant.personality === 1) {
+			r.push(`As you work, ${V.assistant.name} makes lewd comments about what ${heA} looks forward to doing to this new slave.`);
+		}
+		r.push(`Your order requests a slave with the following characteristics:`);
+		return App.UI.DOM.makeElement("p", r.join(" "));
+	}
+
+	function age() {
+		const el = document.createElement("div");
+		const ages = [2, 4, 6, 9, 12, 14, 17, 19, 24, 29, 39, 49, 59, 69, 79, 89, 99, 109, 119, 129, 130];
+
+		createDescription(el, description, "age-text");
+
+		// Choices
+		const select = document.createElement("select");
+		for (let i = 0; i < ages.length; i++) {
+			const high = ages[i];
+			const low = ages[i-1] || (ages[i] - 1); // First element of array has nothing before it, obviously, so display low as one less than high.
+			if (low < V.minimumSlaveAge) {
+				continue;
+			} else if (high > V.retirementAge) {
+				const option = document.createElement("option");
+				option.text = `${low+1}+`;
+				option.value = low+1;
+				select.append(option);
+				break;
+			}
+
+			const option = document.createElement("option");
+			option.text = `${low+1}-${high}`;
+			option.value = high;
+			select.append(option);
+		}
+		select.onchange = () => {
+			slave.age = Number(select.options[select.selectedIndex].value);
+			jQuery("#age-text").empty().append(description());
+		};
+		el.append(select);
+		return el;
+
+		function description() {
+			// Age is displayed as a range, but recorded as the higher of the two numbers in the range
+			const highIndex = ages.indexOf(slave.age);
+
+			if (highIndex === 0) {
+				return `${(ages[highIndex]-1)}-${ages[highIndex]} years old. `;
+			} else if (highIndex === ages.length) {
+				// Highest possible number
+				return `${ages[highIndex]}+ years old. `;
+			} else {
+				// Lower age should be the previous number in the array, +1
+				return `${(ages[highIndex-1])+1}-${ages[highIndex]} years old. `;
+			}
+		}
+	}
+
+	function health() {
+		const el = document.createElement("div");
+		const slaveProperty = "health";
+		const choices = new Map([
+			[1, "Extremely healthy"],
+			[0, "Healthy"],
+		]);
+		createDescription(el, description, slaveProperty);
+		el.append(choicesMaker(slaveProperty, choices, description));
+
+		function description() {
+			for (const [value, text] of choices) {
+				if (slave.health === Number(value)) {
+					return `${text}.`;
+				}
+			}
+		}
+
+		return el;
+	}
+
+	function muscles() {
+		const el = document.createElement("div");
+		const slaveProperty = "muscles";
+		const choices = new Map([
+			["96", "Ripped"],
+			["65", "Muscular"],
+			["45", "Well built"],
+			["20", "Toned"],
+			["0", "Normal"],
+			["-21", "Weak"],
+			["-51", "Very weak"],
+			["-97", "Frail"],
+		]);
+
+		createDescription(el, description, slaveProperty);
+		el.append(choicesMaker(slaveProperty, choices, description));
+
+		function description() {
+			for (const [value, text] of choices) {
+				if (slave.muscles >= Number(value)) {
+					return `${text}.`;
+				}
+			}
+		}
+
+		return el;
+	}
+
+	function lips() {
+		const el = document.createElement("div");
+		const slaveProperty = "lips";
+		const choices = new Map([
+			["100", "Facepussy"],
+			["85", "Enormous"],
+			["65", "Big"],
+			["35", "Plush"],
+			["15", "Normal"],
+			["5", "Thin"],
+		]);
+
+		createDescription(el, description, slaveProperty);
+		el.append(choicesMaker(slaveProperty, choices, description));
+
+		function description() {
+			for (const [value, text] of choices) {
+				if (slave.lips >= Number(value)) {
+					return `${text}.`;
+				}
+			}
+		}
+
+		return el;
+	}
+
+	function voice() {
+		const el = document.createElement("div");
+		const slaveProperty = "lips";
+		const choices = new Map([
+			["3", "High, girly"],
+			["2", "Feminine"],
+			["1", "Deep"],
+			["0", "Mute"],
+			["-1", "Voice is unimportant"],
+		]);
+
+		createDescription(el, description, slaveProperty);
+		el.append(choicesMaker(slaveProperty, choices, description));
+
+		function description() {
+			for (const [value, text] of choices) {
+				if (slave.voice === Number(value)) {
+					if (slave.voice === -1) {
+						return `${text}.`;
+					} else {
+						return `${text} voice.`;
+					}
+				}
+			}
+		}
+
+		return el;
+	}
+
+
+	/**
+	 *
+	 * @param {HTMLElement} element
+	 * @param {Function} text
+	 * @param {string} id
+	 */
+	function createDescription(element, text, id) {
+		const span = document.createElement('span');
+		span.id = `${id}-text`;
+		span.append(text());
+		element.append(span);
+	}
+
+	/**
+	 *
+	 * @param {string} slaveParam
+	 * @param {Map} choices
+	 * @param {Function} description
+	 */
+	function choicesMaker(slaveParam, choices, description) {
+		const linkArray = [];
+		for (const [value, text] of choices) {
+			linkArray.push(
+				App.UI.DOM.link(
+					text,
+					() => {
+						slave[slaveParam] = (Number(value) || value);
+						jQuery(`#${slaveParam}-text`).empty().append(description());
+					}
+				)
+			);
+		}
+		return App.UI.DOM.generateLinksStrip(linkArray);
+	}
+};