diff --git a/src/002-config/fc-js-init.js b/src/002-config/fc-js-init.js
index d3bc023f91a27ba47814c46832a023b77b0140db..f2d1087953d8beef9b67e9ab917148946fcd23fe 100644
--- a/src/002-config/fc-js-init.js
+++ b/src/002-config/fc-js-init.js
@@ -4,9 +4,10 @@
 * does not work.
 */
 window.App = { };
-// the same declaration for code parsers that don't line the line above
+// the same declaration for code parsers that don't like the line above
 var App = window.App || {};
 
+App.Data = {};
 App.Debug = {};
 App.Entity = {};
 App.Entity.Utils = {};
diff --git a/src/003-assets/CSS/links.css b/src/003-assets/CSS/links.css
new file mode 100644
index 0000000000000000000000000000000000000000..518cab09b24927b774fe273e756208761ba50902
--- /dev/null
+++ b/src/003-assets/CSS/links.css
@@ -0,0 +1,48 @@
+.textWithTooltip {
+	position: relative;
+	display: inline-block;
+	text-decoration: underline;
+	text-decoration-color: lightblue;
+}
+
+.textWithTooltip .tooltip {
+	visibility: hidden;
+	display: block;
+	font-size: smaller;
+	width: 20em;
+	margin-left: -10em;
+	background-color: slategray;
+	color: black;
+  	text-align: center;
+  	border-radius: 3px;
+  	padding: 3px;
+	position: absolute;
+  	z-index: 1;
+  	bottom: 100%;
+  	left: 50%;
+}
+
+.textWithTooltip .tooltip ul {
+	margin-left: 5px;
+	margin-right: 0px;
+	padding-left: 10px;
+	padding-right: 0px;
+	text-align: left;
+}
+
+.textWithTooltip .tooltip::after {
+	content: "";
+	position: absolute;
+	top: 100%;
+	left: 50%;
+	margin-left: -5px;
+	border-width: 5px;
+	border-style: solid;
+	border-color: #555 transparent transparent transparent;
+}
+
+.textWithTooltip:hover .tooltip {
+	visibility: visible;
+	opacity: 1;
+	transition-delay: 0.3s;
+}
diff --git a/src/004-base/facility.js b/src/004-base/facility.js
new file mode 100644
index 0000000000000000000000000000000000000000..041e190e1d8bb3a757a6c015ef26426be49ea14d
--- /dev/null
+++ b/src/004-base/facility.js
@@ -0,0 +1,261 @@
+
+App.Data.PositionDesc = class {
+	constructor() {
+		this.position = "";
+		this.assignment = "";
+	}
+}
+
+App.Data.ManagerPositionDesc = class extends App.Data.PositionDesc {
+	constructor() {
+		super();
+		/**
+		 * Applicable careers
+		 * @type {string[]} */
+		this.careers = [];
+		/**
+		 * Applicable skill name
+		 * @type {string} */
+		this.skill = null;
+	}
+}
+
+App.Data.FacilityDesc = class {
+	constructor() {
+		/** Base name for state variables */
+		this.baseName = "";
+		/** Generic name for UI (Brothel, Club, etc.)
+		 * If null, baseName will be used instead
+		*/
+		this.genericName = "";
+		/** @type {App.Data.PositionDesc} */
+		this.assignee = null;
+		/** @type {App.Data.PositionDesc} */
+		this.penthouse = null;
+		/** @type {App.Data.ManagerPositionDesc} */
+		this.manager = null;
+	}
+}
+
+App.Data.Facilities = {};
+
+App.Entity.Facilities = {};
+
+App.Entity.Facilities.Facility = class {
+
+	/**
+	 * @param {App.Data.FacilityDesc} desc defines state variable for this facility
+	 */
+	constructor(desc) {
+		this.desc = desc;
+	}
+
+	/** Facility display name
+	 * @returns {string} */
+	get name() {
+		return State.variables[this.desc.baseName + "Name"];
+	}
+
+	/** Facility generic name ("Brothel", "Schoolroom", etc.)
+	 * @returns {string} */
+	get genericName() {
+		return this.desc.genericName !== null ? this.desc.genericName : capFirstChar(this.desc.baseName);
+	}
+
+	get penthouseJob() {
+		return this.desc.penthouse !== null ? this.desc.penthouse.position : undefined;
+	}
+
+	/** Facility slave capacity
+	* @returns {number} */
+	get capacity() {
+		return State.variables[this.desc.baseName];
+	}
+
+	get established() {
+		return this.capacity > 0;
+	}
+
+	get penthouseAssignmentAvailable() {
+		return this.desc.penthouse !== null;
+	}
+
+	/** Number of already hosted slaves
+	 * @returns {number} */
+	get hostedSlaves() {
+		return State.variables[this.desc.baseName + "Slaves"];
+	}
+
+	get hasFreeSpace() {
+		return this.capacity > this.hostedSlaves;
+	}
+
+	/**
+	 *
+	 * @param {string} name
+	 * @returns {number}
+	 */
+	option(name) {
+		return State.variables[this.desc.baseName + name];
+	}
+
+	/**
+	 *
+	 * @param {string} name
+	 * @returns {number}
+	 */
+	upgrade(name) {
+		return this.option("Upgrade" + name);
+	}
+
+	/**
+	 *
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]} array with rejection reasons. Slave can be hosted if this is empty.
+	 */
+	canHostSlave(slave) {
+		let r = [];
+		if (!this.hasFreeSpace) {
+			r.push(`Capacity of ${this.name} exceeded`);
+		}
+
+		if (slave.assignment === this.desc.assignee.assignment) {
+			r.push(`${slave.slaveName} is already at ${this.name}`);
+		}
+
+		return r;
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]} array with rejection reasons. Slave can be hosted if this is empty.
+	 */
+	slaveCanWorkFromPenthouse(slave) {
+		let r = [];
+		if (slave.assignment === this.desc.penthouse.assignment) {
+			r.push(`${slave.slaveName} is already assigned to ${this.desc.penthouse.assignment}`);
+		}
+		return r;
+	}
+
+	/**
+	 *
+	 * @callback linkCallback
+	 * @param {string} assignment new assignment
+	 * @returns {string} code to include into the <<link>><</link>
+	 */
+
+	/**
+	 * Returns link text for the penthhouse assignment
+	 * @param {number} i slave index
+	 * @param {string} [passage] passage to go to
+	 * @param {linkCallback} [callback]
+	 * @returns {string}
+	 */
+	penthouseAssignmentLink(i, passage, callback) {
+		const linkAction = callback !== undefined ? callback(this.desc.penthouse.assignment) : '';
+		return `<<link "${this.desc.penthouse.position}"${passage !== undefined ? ' "' + passage + '"' : ''}>><<= assignJob(${App.Utils.slaveRefString(i)}, "${this.desc.penthouse.assignment}")>>${linkAction}<</link>>`;
+	}
+
+	/**
+	 * Returns link text for the facility transfer
+	 * @param {number} i slave index
+	 * @returns {string}
+	 */
+	transferLink(i) {
+		return `[[${this.genericName}|Assign][$assignTo = "${this.genericName}", $i = ${i}]]`
+	}
+
+	/**
+	 * Returns true if slave has enough applicable skill or career
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {boolean}
+	 */
+	slaveHasExperiancedForManagerPosition(slave) {
+		return (this.desc.manager.skill !== null && slave.skill[this.desc.manager.skill] >= State.variables.masteredXP) ||
+			(typeof slave.career === 'string' && this.desc.manager.careers.includes(slave.career));
+	}
+
+	/**
+	 * Tests is slave broken enought
+	 * @protected
+	 * @param {App.Entity.SlaveState} slave
+	 * @param {number} [pureDevotion=50] Minimal devotion level to pass test with any trust
+	 * @param {number} [devotion=-50] Minimal devotion for slaves with enough fear
+	 * @param {number} [trust=-21] Maximal trust (i.e. minimal fear) for the less devotional (see above)
+	 * @param {number} [pureFear=-51] Maximal low trust to pass test with any devotion (because of the fear)
+	 * @param {number} [pureTrust=101] Minimal high trust level to pass test without devotion
+	 * @returns {boolean}
+	 */
+	static _isBrokenEnough(slave, pureDevotion, devotion, trust, pureFear, pureTrust) {
+		if ((slave.devotion < (pureDevotion || 50)) &&
+			(slave.trust < (pureTrust || 101)) && (slave.trust > (pureFear || -51)) &&
+			((slave.devotion <= (devotion || -51)) || (slave.trust >= (trust || -21)))) {
+			return false;
+		}
+		return true;
+	}
+
+	/**
+	 * @protected
+	 * Standard message that slave is not broken enough
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string}
+	 */
+	static _stdBreakageMessage(slave) {
+		return `${slave.slaveName} must be either more fearful of you or devoted to you`;
+	}
+}
+
+App.Entity.Facilities.SexWorkFacility = class extends App.Entity.Facilities.Facility {
+	/**
+	 * @param {App.Data.FacilityDesc} desc
+	 * @param {boolean} publicSexUse
+	 * @param {boolean} fuckdollsAccepted
+	 */
+	constructor(desc, publicSexUse, fuckdollsAccepted) {
+		super(desc);
+		this.publicSexUse = publicSexUse;
+		this.fuckdollsAccepted = fuckdollsAccepted;
+	}
+
+	/**
+	 *
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+
+		if (this.publicSexUse &&
+			(slave.breedingMark === 1 || State.variables.propOutcome === 1)) {
+			r.push(`${slave.slaveName} is for private use only`);
+		}
+
+		if (!this.fuckdollsAccepted && slave.fuckdoll > 0) {
+			r.push(`Fuckdolls can't work at ${this.name}`);
+		}
+		return r;
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]} array with rejection reasons. Slave can be hosted if this is empty.
+	 */
+	slaveCanWorkFromPenthouse(slave) {
+		let r = super.slaveCanWorkFromPenthouse(slave);
+
+		if (this.publicSexUse &&
+			(slave.breedingMark === 1 || State.variables.propOutcome === 1)) {
+			r.push(`${slave.slaveName} is for private use only`);
+		}
+
+		if (!this.fuckdollsAccepted && slave.fuckdoll > 0) {
+			r.push(`Fuckdolls can't ${this.desc.penthouse.assignment}`);
+		}
+		return r;
+	}
+}
+
+/** Instances of all facility objects */
+App.Entity.facilities = {};
diff --git a/src/facilities/arcade/arcade.js b/src/facilities/arcade/arcade.js
new file mode 100644
index 0000000000000000000000000000000000000000..dd44a51309f009ca185f30e564f1540e224dbdc9
--- /dev/null
+++ b/src/facilities/arcade/arcade.js
@@ -0,0 +1,49 @@
+App.Data.Facilities.arcade = {
+	baseName: "arcade",
+	genericName: null,
+	assignee: {
+		position: "whore",
+		assignment: "be confined in the arcade",
+	},
+	penthouse: {
+		position: "Gloryhole",
+		assignment: "work a glory hole",
+	},
+	manager: null
+}
+
+App.Entity.Facilities.Arcade = class extends App.Entity.Facilities.SexWorkFacility {
+	constructor() {
+		super(App.Data.Facilities.arcade, true, true);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+
+		if (slave.indentureRestrictions > 0) {
+			r.push(`${slave.slaveName}'s indenture forbids arcade service`)
+		}
+
+		return r;
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	slaveCanWorkFromPenthouse(slave) {
+		let r = super.slaveCanWorkFromPenthouse(slave);
+
+		if (slave.indentureRestrictions > 0) {
+			r.push(`${slave.slaveName}'s indenture forbids gloryhole service`)
+		}
+
+		return r;
+	}
+}
+
+App.Entity.facilities.arcade = new App.Entity.Facilities.Arcade();
diff --git a/src/facilities/brothel/brothel.js b/src/facilities/brothel/brothel.js
new file mode 100644
index 0000000000000000000000000000000000000000..296ef47f458a34eee12a4fb7b67e1892c5c442dd
--- /dev/null
+++ b/src/facilities/brothel/brothel.js
@@ -0,0 +1,42 @@
+App.Data.Facilities.brothel = {
+	baseName: "brothel",
+	genericName: null,
+	assignee: {
+		position: "whore",
+		assignment: "work in the brothel",
+	},
+	penthouse: {
+		position: "Whore",
+		assignment: "whore",
+	},
+	manager: {
+		position: "madam",
+		assignment: "be the Madam",
+		careers: ["a banker", "a business owner", "a businessman", "a camp counselor", "a club manager", "a hotel manager", "a landlady", "a madam", "a manager", "a park ranger", "a pimp", "a procuress", "a stockbroker", "an innkeeper"],
+		skill: null
+	}
+}
+
+App.Entity.Facilities.Brothel = class extends App.Entity.Facilities.SexWorkFacility {
+	constructor() {
+		super(App.Data.Facilities.brothel, true, false);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+
+		// condition is the same as for the club
+		// TODO: consider moving this to App.Entity.Facilities.SexWorkFacility
+		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, 51, -50, -20, -50, 50)) {
+			r.push(App.Entity.Facilities.Facility._stdBreakageMessage(slave));
+		}
+
+		return r;
+	}
+}
+
+App.Entity.facilities.brothel = new App.Entity.Facilities.Brothel();
diff --git a/src/facilities/cellblock/cellblock.js b/src/facilities/cellblock/cellblock.js
new file mode 100644
index 0000000000000000000000000000000000000000..e450e28c4d72c664854511d01749b5f36e4b837d
--- /dev/null
+++ b/src/facilities/cellblock/cellblock.js
@@ -0,0 +1,40 @@
+App.Data.Facilities.cellblock = {
+	baseName: "cellblock",
+	genericName: null,
+	assignee: {
+		position: "",
+		assignment: "serve in the master suite",
+	},
+	penthouse: {
+		position: "Confinement",
+		assignment: "stay confined",
+	},
+	manager: {
+		position: "wardness",
+		assignment: "be the Wardeness",
+		careers: ["a bouncer", "a bounty hunter", "a bully", "a chief of police", "a gang member", "a hall monitor", "a mercenary", "a police detective", "a police officer", "a prison guard", "a prison warden", "a private detective", "a security guard", "a street thug", "an enforcer", "an orderly"],
+		skill: "wardeness"
+	}
+}
+
+App.Entity.Facilities.Cellblock = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.cellblock);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+
+		if ((slave.devotion > -20 || slave.trust < -20) && (slave.devotion >= -50 || slave.trust < -50)) {
+			r.push(`${slave.slaveName} is sufficiently broken in so that the cellblock would have no effect`);
+		}
+
+		return r;
+	}
+}
+
+App.Entity.facilities.cellblock = new App.Entity.Facilities.Cellblock();
diff --git a/src/facilities/clinic/clinic.js b/src/facilities/clinic/clinic.js
new file mode 100644
index 0000000000000000000000000000000000000000..5b16937d91460ba6f43d98527205e28008231d9e
--- /dev/null
+++ b/src/facilities/clinic/clinic.js
@@ -0,0 +1,41 @@
+App.Data.Facilities.clinic = {
+	baseName: "clinic",
+	genericName: null,
+	assignee: {
+		position: "patient",
+		assignment: "get treatment in the clinic",
+	},
+	penthouse: null,
+	manager: {
+		position: "nurse",
+		assignment: "be the Nurse",
+		careers: ["a chemist", "a chiropractor", "a coroner", "a dentist", "a doctor", "a hospital volunteer", "a medic", "a medical student", "a midwife", "a mortician", "a nurse", "a paramedic", "a pharmacist", "a physician", "a school nurse's assistant", "a school nurse", "a surgeon"],
+		skill: "nurse"
+	}
+}
+
+App.Entity.Facilities.Clinic = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.clinic);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+		const V = State.variables;
+
+		if ((slave.health >= 20) &&
+			(V.Nurse === 0 || ((slave.chem <= 15 || this.upgrade("Filters") !== 1) &&
+				(V.bellyImplants !== 1 || slave.bellyImplant <= -1) &&
+				(slave.pregKnown !== 1 || (this.option("SpeedGestation") <= 0 && slave.pregControl !== "speed up")) && (slave.pregAdaptation * 1000 >= slave.bellyPreg && slave.preg <= slave.pregData.normalBirth / 1.33)))) {
+			r.push(`${slave.slaveName} cannot benefit from the clinic`);
+		}
+
+		return r;
+	}
+}
+
+App.Entity.facilities.clinic = new App.Entity.Facilities.Clinic();
diff --git a/src/facilities/club/club.js b/src/facilities/club/club.js
new file mode 100644
index 0000000000000000000000000000000000000000..481dcc5d79281ddb4f138d1949690c14e105736b
--- /dev/null
+++ b/src/facilities/club/club.js
@@ -0,0 +1,42 @@
+App.Data.Facilities.club = {
+	baseName: "club",
+	genericName: null,
+	assignee: {
+		position: "",
+		assignment: "serve in the club",
+	},
+	penthouse: {
+		position: "Public Servant ",
+		assignment: "serve the public",
+	},
+	manager: {
+		position: "DJ",
+		assignment: "be the DJ",
+		careers: ["a classical dancer", "a classical musician", "a dancer", "a house DJ", "a marching band leader", "a musician", "a radio show host", "an aspiring pop star", "an idol", "an orchestra conductor"],
+		skill: "DJ"
+	}
+}
+
+App.Entity.Facilities.Club = class extends App.Entity.Facilities.SexWorkFacility {
+	constructor() {
+		super(App.Data.Facilities.club, true, false);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+
+		// condition is the same as for the brothel
+		// TODO: consider moving this to App.Entity.Facilities.SexWorkFacility
+		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, 51, -50, -20, -50, 50)) {
+			r.push(App.Entity.Facilities.Facility._stdBreakageMessage(slave));
+		}
+
+		return r;
+	}
+}
+
+App.Entity.facilities.club = new App.Entity.Facilities.Club();
diff --git a/src/facilities/dairy/dairy.js b/src/facilities/dairy/dairy.js
new file mode 100644
index 0000000000000000000000000000000000000000..dfb092a78774f62c95120a18e8517f471850fd20
--- /dev/null
+++ b/src/facilities/dairy/dairy.js
@@ -0,0 +1,86 @@
+App.Data.Facilities.dairy = {
+	baseName: "dairy",
+	genericName: null,
+	assignee: {
+		position: "cow",
+		assignment: "work in the dairy",
+	},
+	penthouse: {
+		position: "Milked",
+		assignment: "get milked",
+	},
+	manager: {
+		position: "milkmaid",
+		assignment: "be the Milkmaid",
+		careers: ["a cowgirl", "a dairy worker", "a farmer's daughter", "a milkmaid", "a shepherd", "a veterinarian"],
+		skill: "milkmaid"
+	}
+}
+
+App.Entity.Facilities.Dairy = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.dairy);
+	}
+
+	get hasFreeSpace() {
+		const V = State.variables;
+		const _dairySeed = V.bioreactorsXY + V.bioreactorsXX + V.bioreactorsHerm + V.bioreactorsBarren;
+		return this.capacity > this.hostedSlaves + _dairySeed;
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+		const V = State.variables;
+
+		if ((slave.indentureRestrictions > 0) && (V.dairyRestraintsSetting > 1)) {
+			r.push(`${slave.slaveName}'s indenture forbids extractive Dairy service.`);
+		}
+		if ((slave.indentureRestrictions > 1) && (V.dairyRestraintsSetting > 0)) {
+			r.push(`${slave.slaveName}'s indenture allows only free range milking.`);
+		}
+		if (slave.breedingMark === 1 && V.propOutcome === 1 && V.dairyRestraintsSetting > 0) {
+			r.push(`${slave.slaveName} may only be a free range cow`);
+		}
+		if ((V.dairyPregSetting > 0) && ((slave.bellyImplant !== -1) || (slave.broodmother !== 0))) {
+			r.push(`${slave.slaveName}'s womb cannot accommodate current machine settings`);
+		}
+
+		if ((slave.amp !== 1) && (this.option("RestraintsUpgrade") !== 1) &&
+			!App.Entity.Facilities.Facility._isBrokenEnough(slave, 20, -50, -20, -50)) {
+			r.push(`${slave.slaveName} must be obedient in order to be milked at ${this.name}`);
+		}
+
+		if ((slave.lactation === 0) && (slave.balls === 0) && ((V.dairySlimMaintainUpgrade !== 1 && V.dairySlimMaintain <= 0) || (slave.boobs <= 300 && slave.balls !== 0 && V.dairyImplantsSetting !== 1) || V.dairyImplantsSetting === 2)) {
+			if ((V.dairySlimMaintainUpgrade === 1 && V.dairySlimMaintain === 1) || (V.dairyImplantsSetting === 2) || (slave.boobs <= 300 && slave.balls > 0 && (V.dairyImplantsSetting === 0 || V.dairyImplantsSetting === 3))) {
+				r.push(`${slave.slaveName} is not lactating ` + ((V.seeDicks > 0) ? 'or producing semen ' : '') + `and ${this.name}'s current settings forbid the automatic implantation of lactation inducing drugs or manual stimulation to induce it, so she cannot be a cow`);
+			} else {
+				r.push(`${slave.slaveName} is not lactating ` + ((V.seeDicks > 0) ? 'or producing semen ' : '') + 'and cannot be a cow');
+			}
+		} else if ((V.dairyStimulatorsSetting >= 2) && (slave.anus <= 2) && (V.dairyPrepUpgrade !== 1)) {
+			r.push(`${slave.slaveName}'s anus cannot accommodate current machine settings`);
+		} else if ((V.dairyPregSetting >= 2) && (slave.vagina <= 2) && (slave.ovaries !== 0) && (V.dairyPrepUpgrade !== 1)) {
+			r.push(`${slave.slaveName}'s vagina cannot accommodate current machine settings`);
+		}
+
+		return r;
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	slaveCanWorkFromPenthouse(slave) {
+		let r = super.slaveCanWorkFromPenthouse(slave);
+
+		if ((slave.lactation <= 0) && (slave.balls <= 0)) {
+			r.push(`${slave.slaveName} is not lactating` + ((State.variables.seeDicks > 0) ? ' or producing semen' : ''));
+		}
+		return r;
+	}
+}
+
+App.Entity.facilities.dairy = new App.Entity.Facilities.Dairy();
diff --git a/src/facilities/farmyard/farmyard.js b/src/facilities/farmyard/farmyard.js
new file mode 100644
index 0000000000000000000000000000000000000000..24f71a6edbacb504915a90172a2a15179fd565a4
--- /dev/null
+++ b/src/facilities/farmyard/farmyard.js
@@ -0,0 +1,23 @@
+App.Data.Facilities.farmyard = {
+	baseName: "farmyard",
+	genericName: null,
+	assignee: {
+		position: "",
+		assignment: "work as a farmhand",
+	},
+	penthouse: null,
+	manager: {
+		position: "farmer",
+		assignment: "be the Farmer",
+		careers: ["a beekeeper", "a bullfighter", "a farmer", "a farmhand", "a rancher", "a rodeo star", "a zookeeper"],
+		skill: "farmer"
+	}
+}
+
+App.Entity.Facilities.Farmyard = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.farmyard);
+	}
+}
+
+App.Entity.facilities.farmyard = new App.Entity.Facilities.Farmyard();
diff --git a/src/facilities/masterSuite/masterSuite.js b/src/facilities/masterSuite/masterSuite.js
new file mode 100644
index 0000000000000000000000000000000000000000..4ca615876207d3faffd5c4fbc7c9421c3c8291e7
--- /dev/null
+++ b/src/facilities/masterSuite/masterSuite.js
@@ -0,0 +1,39 @@
+App.Data.Facilities.masterSuite = {
+	baseName: "masterSuite",
+	genericName: "Master Suite",
+	assignee: {
+		position: "fucktoy",
+		assignment: "serve in the master suite",
+	},
+	penthouse: {
+		position: "Fucktoy",
+		assignment: "please you",
+	},
+	manager: {
+		position: "concubine",
+		assignment: "be your Concubine",
+		careers: [],
+		skill: null
+	}
+}
+
+App.Entity.Facilities.MasterSuite = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.masterSuite);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, 20, -51, -21, -50)) {
+			r.push(`${slave.slaveName} is not sufficiently broken for the master suite`);
+		}
+
+		return r;
+	}
+}
+
+App.Entity.facilities.masterSuite = new App.Entity.Facilities.MasterSuite();
diff --git a/src/facilities/nursery/nursery.js b/src/facilities/nursery/nursery.js
new file mode 100644
index 0000000000000000000000000000000000000000..2efb72dda025a630fb2900fe9433349a7ce0bdc2
--- /dev/null
+++ b/src/facilities/nursery/nursery.js
@@ -0,0 +1,37 @@
+App.Data.Facilities.nursery = {
+	baseName: "nursery",
+	genericName: null,
+	assignee: {
+		position: "nanny",
+		assignment: "work as a nanny"
+	},
+	penthouse: null,
+	manager: {
+		position: "matron",
+		assignment: "be the Matron",
+		careers: ["a babysitter", "a nanny", "a practitioner", "a wet nurse", "an au pair"],
+		skill: "matron"
+	}
+}
+
+App.Entity.Facilities.Nursery = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.nursery);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+
+		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, -20, -50, 20, -21)) {
+			r.push(App.Entity.Facilities.Facility._stdBreakageMessage(slave));
+		}
+
+		return r;
+	}
+}
+
+App.Entity.facilities.nursery = new App.Entity.Facilities.Nursery();
diff --git a/src/facilities/pit/pit.js b/src/facilities/pit/pit.js
new file mode 100644
index 0000000000000000000000000000000000000000..9b4369c0554b95abad9b96c4bc2715631348bfd9
--- /dev/null
+++ b/src/facilities/pit/pit.js
@@ -0,0 +1,36 @@
+App.Data.Facilities.pit = {
+	baseName: "pit",
+	genericName: null,
+	assignee: {
+		position: "fighter",
+		assignment: ""
+	},
+	penthouse: null,
+	manager: null
+}
+
+App.Entity.Facilities.Pit = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.pit);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+		if (slave.breedingMark === 1 && State.variables.propOutcome === 1) {
+			r.push(`${slave.slaveName} may not participate in combat.`);
+		}
+		if (slave.indentureRestrictions > 1) {
+			r.push(`${slave.slaveName}'s indenture forbids fighting.`);
+		}
+		if ((slave.indentureRestrictions > 0) && (this.option("Lethal") === 1)) {
+			r.push(`${slave.slaveName}'s indenture forbids lethal fights.`);
+		}
+		return r;
+	}
+}
+
+App.Entity.facilities.pit = new App.Entity.Facilities.Pit();
diff --git a/src/facilities/schoolroom/schoolroom.js b/src/facilities/schoolroom/schoolroom.js
new file mode 100644
index 0000000000000000000000000000000000000000..578612c218e1e3144ae2122798fbb4992f69871e
--- /dev/null
+++ b/src/facilities/schoolroom/schoolroom.js
@@ -0,0 +1,66 @@
+App.Data.Facilities.schoolroom = {
+	baseName: "schoolroom",
+	genericName: null,
+	assignee: {
+		position: "",
+		assignment: "learn in the schoolroom",
+	},
+	penthouse: {
+		position: "Classes",
+		assignment: "take classes",
+	},
+	manager: {
+		position: "teacher",
+		assignment: "be the Schoolteacher",
+		careers: ["a child prodigy", "a coach", "a dean", "a historian", "a librarian", "a principal", "a private instructor", "a professor", "a scholar", "a scientist", "a teacher's pet", "a teacher", "a teaching assistant", "an archaeologist", "an astronaut", "an economist"],
+		skill: "teacher"
+	}
+}
+
+App.Entity.Facilities.Schoolroom = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.schoolroom);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	slaveCanWorkFromPenthouse(slave) {
+		let r = super.slaveCanWorkFromPenthouse(slave);
+		if (slave.intelligenceImplant >= 15) {
+			r.push(`${slave.slaveName} already has a basic education`);
+		}
+		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, -20, -50, -20, -51)) {
+			r.push(`${slave.slaveName} is too resistant to learn`);
+		}
+
+		if (slave.fetish === "mindbroken") {
+			r.push(`${capFirstChar(slave.possessive)} mind is fundamentally broken and can't learn`);
+		}
+		return r;
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+
+		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, -20, -50, -20, -51)) {
+			r.push(`${slave.slaveName} is too resistant to learn`);
+		}
+
+		const maxSkill = 10 + this.upgrade("Skills") * 20; // maximal skill value the scholl can teach
+		if ((slave.intelligenceImplant >= 30) && (slave.voice === 0 || slave.accent + this.upgrade("Language") <= 2) &&
+			(slave.skill.oral > maxSkill) && (slave.skill.whoring > maxSkill) && (slave.skill.entertainment > maxSkill) &&
+			(slave.skill.anal > maxSkill) && ((slave.vagina < 0) || (slave.skill.vaginal > maxSkill))) {
+			r.push(`${slave.slaveName} already has a basic education`);
+		}
+
+		return r;
+	}
+}
+
+App.Entity.facilities.schoolrom = new App.Entity.Facilities.Schoolroom();
diff --git a/src/facilities/servantsQuaters/servantsQuaters.js b/src/facilities/servantsQuaters/servantsQuaters.js
new file mode 100644
index 0000000000000000000000000000000000000000..c2eb0fcbd2bd2b6a2606f060feeba975abf8ae00
--- /dev/null
+++ b/src/facilities/servantsQuaters/servantsQuaters.js
@@ -0,0 +1,66 @@
+App.Data.Facilities.servantsQuaters = {
+	baseName: "servantsQuarters",
+	genericName: "Servants' Quarters",
+	assignee: {
+		position: "servant",
+		assignment: "work as a servant",
+	},
+	penthouse: {
+		position: "House Servant",
+		assignment: "be a servant",
+	},
+	manager: {
+		position: "stewardess",
+		assignment: "be the Stewardess",
+		careers: ["a barista", "a bartender", "a brewer", "a bureaucrat", "a caregiver", "a charity worker", "a club treasurer", "a concierge", "a critic", "a housekeeper", "a housesitter", "a lemonade stand operator", "a personal assistant", "a professional bartender", "a secretary", "a wedding planner", "an air hostess", "an architect", "an editor", "an estate agent", "an investor", "an office worker"],
+		skill: "stewardess"
+	}
+}
+
+App.Entity.Facilities.ServantsQuarters = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.servantsQuaters);
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+
+		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, -20, -50, 20, -21)) {
+			r.push(App.Entity.Facilities.Facility._stdBreakageMessage(slave));
+		}
+		if (!window.canWalk(slave)) {
+			r.push(`${slave.slaveName} can't work as a servant because ${slave.object} can't walk`);
+		}
+		if (!canSee(slave)) {
+			r.push(`${slave.slaveName} can't work as a servant because ${slave.object} is blind`);
+		}
+		return r;
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	slaveCanWorkFromPenthouse(slave) {
+		let r = super.slaveCanWorkFromPenthouse(slave);
+
+		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, -20, -50, -19, -51)) {
+			r.push(App.Entity.Facilities.Facility._stdBreakageMessage(slave));
+		}
+
+		if (!canWalk(slave)) {
+			r.push(`${slave.slaveName} can't work as a servant because ${slave.object} can't walk`);
+		}
+		if (!canSee(slave)) {
+			r.push(`${slave.slaveName} can't work as a servant because ${slave.object} is blind`);
+		}
+
+		return r;
+	}
+}
+
+App.Entity.facilities.servantsQuarters = new App.Entity.Facilities.ServantsQuarters();
diff --git a/src/facilities/spa/spa.js b/src/facilities/spa/spa.js
new file mode 100644
index 0000000000000000000000000000000000000000..77c04f998064812c0b014a143943461d276e9ac6
--- /dev/null
+++ b/src/facilities/spa/spa.js
@@ -0,0 +1,46 @@
+App.Data.Facilities.spa = {
+	baseName: "spa",
+	genericName: null,
+	assignee: {
+		position: "",
+		assignment: "rest in the spa"
+	},
+	penthouse: {
+		position: "Rest",
+		assignment: "rest",
+	},
+	manager: {
+		position: "attendant",
+		assignment: "be the Attendant",
+		careers: ["a barber", "a cosmetologist", "a counselor", "a dispatch officer", "a fortune teller", "a groomer", "a latchkey kid", "a lifeguard", "a masseuse", "a mediator", "a personal trainer", "a police negotiator", "a psychologist", "a therapist", "a yoga instructor"],
+		skill: "attendant"
+	}
+}
+
+App.Entity.Facilities.Spa = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.spa);
+	}
+
+	penthouseAssignmentLink(i, passage, callback) {
+		const linkAction = callback !== undefined ? callback(this.desc.penthouse.assignment) : '';
+		const slRef = App.Utils.slaveRefString(i);
+		return `<<link "Rest"${passage !== undefined ? ' "' + passage + '"' : ''}>><<= removeJob(${slRef}, ${slRef}.assignment)>>${linkAction}<</link>>`;
+	}
+
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canHostSlave(slave) {
+		let r = super.canHostSlave(slave);
+
+		if (((slave.devotion < -20 && slave.fetish !== "mindbroken") || (slave.health >= 20 && slave.trust > 60 && slave.devotion > 60 && slave.fetish !== "mindbroken" && slave.sexualFlaw === "none" && slave.behavioralFlaw === "none"))) {
+			r.push(`${slave.slaveName} can not benefit from spa procedures`);
+		}
+
+		return r;
+	}
+}
+
+App.Entity.facilities.spa = new App.Entity.Facilities.Spa();
diff --git a/src/init/setupVars.tw b/src/init/setupVars.tw
index d4f1ade394f28ce268693736140eaffdc6e3a31b..303e439ee5dba5a8506619c4b361f3f6b691216e 100644
--- a/src/init/setupVars.tw
+++ b/src/init/setupVars.tw
@@ -319,27 +319,27 @@ equine: {type: "equine", normalOvaMin:1, normalOvaMax: 1, normalBirth: 48, minLi
 
 <<set setup.HGCareers = ["a captain", "a corporate executive", "a director", "a dominatrix", "a gang leader", "a judge", "a lawyer", "a leading arcology citizen", "a military officer", "a model-UN star", "a noblewoman", "a politician", "a Queen", "a slaver", "a student council president"]>>
 
-<<set setup.madamCareers = ["a banker", "a business owner", "a businessman", "a camp counselor", "a club manager", "a hotel manager", "a landlady", "a madam", "a manager", "a park ranger", "a pimp", "a procuress", "a stockbroker", "an innkeeper"]>>
+<<set setup.madamCareers = App.Data.Facilities.brothel.manager.careers>>
 
-<<set setup.DJCareers = ["a classical dancer", "a classical musician", "a dancer", "a house DJ", "a marching band leader", "a musician", "a radio show host", "an aspiring pop star", "an idol", "an orchestra conductor"]>>
+<<set setup.DJCareers = App.Data.Facilities.club.manager.careers>>
 
 <<set setup.bodyguardCareers = ["a bodyguard", "a boxer", "a bully hunter", "a child soldier", "a hitman", "a kunoichi", "a law enforcement officer", "a military brat", "a prince", "a revolutionary", "a sniper", "a soldier", "a transporter", "an assassin", "an MS pilot", "captain of the kendo club", "in a militia", "spec ops"]>>
 
-<<set setup.wardenessCareers = ["a bouncer", "a bounty hunter", "a bully", "a chief of police", "a gang member", "a hall monitor", "a mercenary", "a police detective", "a police officer", "a prison guard", "a prison warden", "a private detective", "a security guard", "a street thug", "an enforcer", "an orderly"]>>
+<<set setup.wardenessCareers = App.Data.Facilities.cellblock.manager.careers>>
 
-<<set setup.nurseCareers = ["a chemist", "a chiropractor", "a coroner", "a dentist", "a doctor", "a hospital volunteer", "a medic", "a medical student", "a midwife", "a mortician", "a nurse", "a paramedic", "a pharmacist", "a physician", "a school nurse's assistant", "a school nurse", "a surgeon"]>>
+<<set setup.nurseCareers = App.Data.Facilities.clinic.manager.careers>>
 
-<<set setup.attendantCareers = ["a barber", "a cosmetologist", "a counselor", "a dispatch officer", "a fortune teller", "a groomer", "a latchkey kid", "a lifeguard", "a masseuse", "a mediator", "a personal trainer", "a police negotiator", "a psychologist", "a therapist", "a yoga instructor"]>>
+<<set setup.attendantCareers = App.Data.Facilities.spa.manager.careers>>
 
-<<set setup.matronCareers = ["a babysitter", "a nanny", "a practitioner", "a wet nurse", "an au pair"]>>
+<<set setup.matronCareers = App.Data.Facilities.nursery.manager.careers>>
 
-<<set setup.milkmaidCareers = ["a cowgirl", "a dairy worker", "a farmer's daughter", "a milkmaid", "a shepherd", "a veterinarian"]>>
+<<set setup.milkmaidCareers = App.Data.Facilities.dairy.manager.careers>>
 
-<<set setup.farmerCareers = ["a beekeeper", "a bullfighter", "a farmer", "a farmhand", "a rancher", "a rodeo star", "a zookeeper"]>>
+<<set setup.farmerCareers = App.Data.Facilities.farmyard.manager.careers>>
 
-<<set setup.stewardessCareers = ["a barista", "a bartender", "a brewer", "a bureaucrat", "a caregiver", "a charity worker", "a club treasurer", "a concierge", "a critic", "a housekeeper", "a housesitter", "a lemonade stand operator", "a personal assistant", "a professional bartender", "a secretary", "a wedding planner", "an air hostess", "an architect", "an editor", "an estate agent", "an investor", "an office worker"]>>
+<<set setup.stewardessCareers = App.Data.Facilities.servantsQuaters.manager.careers>>
 
-<<set setup.schoolteacherCareers = ["a child prodigy", "a coach", "a dean", "a historian", "a librarian", "a principal", "a private instructor", "a professor", "a scholar", "a scientist", "a teacher's pet", "a teacher", "a teaching assistant", "an archaeologist", "an astronaut", "an economist"]>>
+<<set setup.schoolteacherCareers = App.Data.Facilities.schoolroom.manager.careers>>
 
 <<set setup.recruiterCareers = ["a club recruiter", "a college scout", "a con artist", "a cult leader", "a girl scout", "a hunter", "a lobbyist", "a military recruiter", "a missionary", "a political activist", "a princess", "a spy", "a talent scout", "retired"]>> /* pregmod */
 
diff --git a/src/js/assignJS.js b/src/js/assignJS.js
index 03285aff851b1fa43c30e93da9a2afb57152a2b6..7e20f2a38a0bde6fffe5e131481495aa47300c80 100644
--- a/src/js/assignJS.js
+++ b/src/js/assignJS.js
@@ -544,3 +544,136 @@ window.resetJobIDArray = function resetJobIDArray() { /* todo: expand to all ass
 
 	return JobIDArray;
 };
+
+/**
+ * Generates string with links for changing slave assignment
+ */
+App.UI.jobLinks = function () {
+	"use strict";
+	const facilitiesOrder = [
+		App.Entity.facilities.spa,
+		App.Entity.facilities.clinic,
+		App.Entity.facilities.masterSuite,
+		App.Entity.facilities.schoolrom,
+		App.Entity.facilities.servantsQuarters,
+		App.Entity.facilities.farmyard,
+		App.Entity.facilities.nursery,
+		App.Entity.facilities.brothel,
+		App.Entity.facilities.club,
+		App.Entity.facilities.dairy,
+		App.Entity.facilities.arcade,
+		App.Entity.facilities.cellblock
+	];
+
+	return {
+		assignments: assignmentLinks,
+		transfers: transferLinks
+	};
+
+	/**
+	 * Generates assignment links
+	 * @param {number} index index in the slaves array or -1 for the activeSlave
+	 * @param {string} [passage] optional next passage to go to
+	 * @param {linkCallback} [callback]
+	 * @returns {string}
+	 */
+	function assignmentLinks(index, passage, callback) {
+		let res = [];
+		/** @type {App.Entity.SlaveState} */
+		const slave = index >= 0 ? State.variables.slaves[index] : State.variables.activeSlave;
+
+		for (const f of facilitiesOrder) {
+			if (!f.penthouseAssignmentAvailable) continue;
+			const rejects = f.slaveCanWorkFromPenthouse(slave);
+			if (rejects.length === 0) {
+				res.push(f.penthouseAssignmentLink(index, passage, callback));
+			} else {
+				res.push(App.UI.disabledLink(f.penthouseJob, rejects));
+			}
+		}
+		if (slave.fuckdoll === 0) {
+			const assignment = "choose her own job"
+			if (slave.assignment !== assignment) {
+				const linkAction = callback !== undefined ? callback(assignment) : '';
+				res.push(`<<link "Let ${slave.object} choose" ${passage !== undefined ? '"' + passage + '"' : ''}>><<= assignJob(${App.Utils.slaveRefString(index)}, "${assignment}")>>${linkAction}<</link>>`);
+			} else {
+				res.push(App.UI.disabledLink(`Let ${slave.object} choose`, ["Fuckdolls can't choose their job"]));
+			}
+		}
+
+		return res.join("&thinsp;|&thinsp;");
+	}
+
+	function transferLinks(index) {
+		/** @type {string[]} */
+		const transfers = [];
+		/** @type {App.Entity.SlaveState} */
+		const slave = index >= 0 ? State.variables.slaves[index] : State.variables.activeSlave;
+
+		if (slave.assignment !== "rest" && slave.assignment !== "please you" && slave.assignment !== "take classes" && slave.assignment !== "be a servant" && slave.assignment !== "whore" && slave.assignment !== "work a glory hole" && slave.assignment !== "serve the public" && slave.assignment !== "get milked" && slave.assignment !== "stay confined") {
+			transfers.push(`<<link "Penthouse" "Main">><<= removeJob($slaves[${index}], $slaves[${index}].assignment)>><</link>>`);
+		} else {
+			transfers.push(App.UI.disabledLink('Penthouse', [`${slave.slaveName} is already at the Penthouse`]));
+		}
+
+		for (const f of facilitiesOrder) {
+			if (!f.established) continue;
+
+			const rejects = f.canHostSlave(slave);
+			if (rejects.length === 0) {
+				transfers.push(f.transferLink(index));
+			} else {
+				transfers.push(App.UI.disabledLink(f.genericName, rejects));
+			}
+		}
+
+		return transfers.join('&thinsp;|&thinsp;');
+	}
+}();
+
+App.UI.SlaveInteract = {
+	fucktoyPref: function () {
+		let elem = jQuery('#fucktoypref');
+		elem.empty();
+		let res = "";
+		/** @type {App.Entity.SlaveState} */
+		const slave = State.variables.activeSlave;
+		if ((slave.assignment === "please you") || (slave.assignment === "serve in the master suite") || (slave.assignment === "be your Concubine")) {
+			res += '__Fucktoy use preference__: <strong><span id = "hole">' + slave.toyHole + '</span></strong>.';
+			/** @type {string[]} */
+			let links = [];
+			links.push('<<link "Mouth">><<set $activeSlave.toyHole = "mouth">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>');
+			links.push('<<link "Tits">><<set $activeSlave.toyHole = "boobs">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>');
+			if ((slave.vagina > 0) && canDoVaginal(slave)) {
+				links.push('<<link "Pussy">><<set $activeSlave.toyHole = "pussy">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>');
+			} else if (slave.vagina === 0) {
+				links.push(App.UI.disabledLink("Pussy",
+					[`Take ${slave.possessive} virginity before giving ${slave.possessive} pussy special attention`]));
+			}
+			if ((slave.anus > 0) && canDoAnal(slave)) {
+				links.push('<<link "Ass">><<set $activeSlave.toyHole = "ass">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>');
+			} else {
+				links.push(App.UI.disabledLink("Ass",
+					[`Take ${slave.possessive} anal virginity before giving ${slave.possessive} ass special attention`]));
+			}
+			if ((slave.dick > 0) && canPenetrate(slave)) {
+				links.push('<<link "Dick">><<set $activeSlave.toyHole = "dick">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>');
+			}
+			links.push(`<<link "No Preference">><<set $activeSlave.toyHole = "all ${slave.possessive} holes">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>`);
+			res += links.join('&thinsp;|&thinsp;') + '<br>'
+		}
+		let ins = jQuery(document.createDocumentFragment());
+		ins.wiki(res);
+		elem.append(ins);
+	},
+
+	assignmentBlock: function (blockId) {
+		let res = App.UI.jobLinks.assignments(-1, undefined, () => {
+			return `<<replace "#assign">>$activeSlave.assignment<</replace>><<replace "#${blockId}">><<= App.UI.SlaveInteract.assignmentBlock("${blockId}")>><<= App.UI.SlaveInteract.fucktoyPref()>><</replace>>`;
+		});
+		if (State.variables.activeSlave.assignment !== "choose her own job") {
+			res += '&thinsp;|&thinsp; <<link "Stay on this assignment for another month">><<set $activeSlave.sentence += 4>><<replace "#assign">>$activeSlave.assignment($activeSlave.sentence weeks)<</replace>><</link>>'
+		}
+		return res;
+	}
+}
diff --git a/src/js/slaveSummaryWidgets.js b/src/js/slaveSummaryWidgets.js
index 17a0876eabeea5fb73050623ebb590a07406e939..7caebe85b2e0c19b7cffb3a976f974de4fa9414c 100644
--- a/src/js/slaveSummaryWidgets.js
+++ b/src/js/slaveSummaryWidgets.js
@@ -5060,6 +5060,61 @@ App.UI.slaveSummaryList = function (passageName) {
 		}
 	}
 
+	const passageToFacilityMap = {
+		"Arcade": App.Entity.facilities.arcade,
+		"Brothel": App.Entity.facilities.brothel,
+		"Cellblock": App.Entity.facilities.cellblock,
+		"Clinic": App.Entity.facilities.clinic,
+		"Club": App.Entity.facilities.club,
+		"Dairy": App.Entity.facilities.dairy,
+		"Farmyard": App.Entity.facilities.farmyard,
+		"Master Suite": App.Entity.facilities.masterSuite,
+		"Nursery": App.Entity.facilities.nursery,
+		"Pit": App.Entity.facilities.pit,
+		"Schoolroom": App.Entity.facilities.schoolrom,
+		"Servants' Quarters": App.Entity.facilities.servantsQuarters,
+		"Spa": App.Entity.facilities.spa
+	};
+
+	const managerSelectPassageToFacilityMap = {
+		"Attendant Select": App.Entity.facilities.spa,
+		"Matron Select": App.Entity.facilities.nursery,
+		"Madam Select": App.Entity.facilities.brothel,
+		"Milkmaid Select": App.Entity.facilities.dairy,
+		"Nurse Select": App.Entity.facilities.clinic,
+		"DJ Select": App.Entity.facilities.club,
+		"Farmer Select": App.Entity.facilities.farmyard,
+		"Stewardess Select": App.Entity.facilities.servantsQuarters,
+		"Schoolteacher Select": App.Entity.facilities.schoolrom,
+		"Wardeness Select": App.Entity.facilities.cellblock,
+	};
+
+	// TODO: merge with managerSelectPassageToFacilityMap
+	const selectionWorkarounds = {
+		"Agent Select": "Agent Workaround",
+		"BG Select": "Bodyguard Workaround",
+		"Recruiter Select": "Recruiter Workaround",
+		"HG Select": "HG Workaround",
+		"Attendant Select":"Attendant Workaround",
+		"Matron Select": "Matron Workaround",
+		"Madam Select": "Madam Workaround",
+		"DJ Select": "DJ Workaround",
+		"Nurse Select": "Nurse Workaround",
+		"Schoolteacher Select": "Schoolteacher Workaround",
+		"Milkmaid Select": "Milkmaid Workaround",
+		"Farmer Select": "Farmer Workaround",
+		"Stewardess Select": "Stewardess Workaround",
+		"Concubine Select": "Concubine Workaround",
+		"Wardeness Select": "Wardeness Workaround"
+	};
+
+	/** @type {App.Entity.Facilities.Facility} */
+	const passageFacility = passageToFacilityMap[passageName];
+	/** @type {App.Entity.Facilities.Facility} */
+	const managerSelectFacility = managerSelectPassageToFacilityMap[passageName];
+	/** @type {string} */
+	const selectionWorkaround = selectionWorkarounds[passageName];
+
 	for (const _ssi of _filteredSlaveIdxs) {
 		let _Slave = slaves[_ssi];
 
@@ -5084,6 +5139,32 @@ App.UI.slaveSummaryList = function (passageName) {
 
 		res.push(`<div id="slave_${ _Slave.ID }" style="clear:both">`);
 
+		if (passageFacility !== undefined) {
+			if (V.Flag === 0) {
+				if (!passageFacility.hasFreeSpace) {
+					res.pop();
+					continue;
+				}
+				const rejects = passageFacility.canHostSlave(_Slave);
+				if (rejects.length > 0) {
+					let rejectString = `${_slaveName}: <ul>${rejects.map(e => `<li>${e}</li>`).join('')}</ul></div>`;
+					res.push(rejectString);
+					continue;
+				} else {
+					res.push(dividerAndImage(_Slave));
+					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
+				}
+			} else if (V.Flag === 1) {
+				res.push(dividerAndImage(_Slave));
+				res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
+			} else {
+				if ((V.seeImages === 1) && (V.seeSummaryImages === 1)) res.push(slaveImage(_Slave));
+				res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
+			}
+		} else if (selectionWorkaround !== undefined) {
+			res.push(dividerAndImage(_Slave));
+			res.push(`[[${_slaveName}|${selectionWorkaround}][$i = ${_ssi}]]`);
+		}
 		switch (passageName) {
 			case "Main":
 				if ((_Slave.choosesOwnClothes === 1) && (_Slave.clothes === "choosing her own clothes")) {
@@ -5107,22 +5188,6 @@ App.UI.slaveSummaryList = function (passageName) {
 				res.push(dividerAndImage(_Slave));
 				res.push(`<<link "${_slaveName}">> <<run App.UI.selectSlaveForPersonalAttention(${_Slave.ID})>><</link>>`);
 				break;
-			case "Agent Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Agent Workaround][$i = ${_ssi}]]`);
-				break;
-			case "BG Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Bodyguard Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Recruiter Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Recruiter Workaround][$i = ${_ssi}]]`);
-				break;
-			case "HG Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|HG Workaround][$i = ${_ssi}]]`);
-				break;
 			case "Head Girl Suite":
 				if (V.Flag === 0) {
 					res.push(dividerAndImage(_Slave));
@@ -5136,392 +5201,6 @@ App.UI.slaveSummaryList = function (passageName) {
 				res.push(dividerAndImage(_Slave));
 				res.push(`[[${_slaveName}|Subordinate Targeting][$activeSlave.subTarget = $slaves[${_ssi}].ID]]`);
 				break;
-			case "Spa":
-				if (V.Flag === 0) {
-					if (V.spa <= V.spaSlaves) {
-						res.pop();
-						continue;
-					}
-					if ((_Slave.health < 20) || (_Slave.trust < 60) || (_Slave.devotion <= 60) || (_Slave.fetish === "mindbroken") || _Slave.sexualFlaw !== "none" || _Slave.behavioralFlaw !== "none") {
-						if (_Slave.devotion >= -20 || _Slave.fetish === "mindbroken") {
-							res.push(dividerAndImage(_Slave));
-							res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-						} else {
-							res.push(`<i>${_Slave.slaveName} cannot be trusted in the spa</i></div>`);
-							continue;
-						}
-					} else {
-						res.push(`<i>${_Slave.slaveName} cannot benefit from the spa</i></div>`);
-						continue;
-					}
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					if ((V.seeImages === 1) && (V.seeSummaryImages === 1)) res.push(slaveImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Attendant Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Attendant Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Nursery":
-				if (V.Flag === 0) {
-					if (V.nurseryNannies <= V.nurserySlaves) {
-						res.pop();
-						continue;
-					}
-					if ((_Slave.devotion >= -20) || ((_Slave.devotion >= -50) && (_Slave.trust <= 20)) || (_Slave.trust < -20)) {
-						res.push(dividerAndImage(_Slave));
-						res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-					} else {
-						res.push(`<i>${_Slave.slaveName} must be either more fearful of you or devoted to you</i></div>`);
-						continue;
-					}
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					if ((V.seeImages === 1) && (V.seeSummaryImages === 1)) {
-						res.push(slaveImage(_Slave));
-					}
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Matron Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Matron Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Brothel":
-				if (V.Flag === 0) {
-					if (V.brothel <= V.brothelSlaves) {
-						res.pop();
-						continue;
-					}
-					if (_Slave.breedingMark !== 1 || V.propOutcome === 0) {
-						if ((_Slave.devotion > 50) || ((_Slave.devotion >= -50) && (_Slave.trust < -20)) || (_Slave.trust < -50) || (_Slave.trust > 50)) {
-							res.push(dividerAndImage(_Slave));
-							res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-						} else {
-							res.push(`<i>${_Slave.slaveName} must be either more fearful of you or devoted to you</i></div>`);
-							continue;
-						}
-					} else {
-						res.push(`<i>${_Slave.slaveName} is for private use only</i></div>`);
-						continue;
-					}
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					if ((V.seeImages === 1) && (V.seeSummaryImages === 1)) {
-						res.push(slaveImage(_Slave));
-					}
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Madam Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Madam Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Club":
-				if (V.Flag === 0) {
-					if (V.club <= V.clubSlaves) {
-						res.pop();
-						continue;
-					}
-					if (_Slave.breedingMark !== 1 || V.propOutcome === 0) {
-						if ((_Slave.devotion > 50) || ((_Slave.devotion >= -50) && (_Slave.trust < -20)) || (_Slave.trust < -50) || (_Slave.trust > 50)) {
-							res.push(dividerAndImage(_Slave));
-							res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-						} else {
-							res.push(`//${_Slave.slaveName} must be either more fearful of you or devoted to you//</div>`);
-							continue;
-						}
-					} else {
-						res.push(`//${_Slave.slaveName} is for private use only//</div>`);
-						continue;
-					}
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName} | Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "DJ Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|DJ Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Clinic":
-				if (V.Flag === 0) {
-					if (V.clinic <= V.clinicSlaves) {
-						res.pop();
-						continue;
-					}
-					if ((_Slave.health < 20) || (V.Nurse !== 0 && ((_Slave.chem > 15 && V.clinicUpgradeFilters === 1) || (V.bellyImplants === 1 && _Slave.bellyImplant > -1) || (_Slave.pregKnown === 1 && (V.clinicSpeedGestation >= 0 || _Slave.pregControl === "speed up")) || (_Slave.pregAdaptation * 1000 < _Slave.bellyPreg || _Slave.preg > _Slave.pregData.normalBirth / 1.33)))) {
-						res.push(dividerAndImage(_Slave));
-						res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-					} else {
-						res.push(`//${_Slave.slaveName} cannot benefit from the clinic//</div>`);
-						continue;
-					}
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName} | Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Nurse Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Nurse Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Schoolroom":
-				if (V.Flag === 0) {
-					if (V.schoolroom <= V.schoolroomSlaves) {
-						res.pop();
-						continue;
-					}
-					if ((_Slave.devotion >= -20) || ((_Slave.devotion >= -50) && (_Slave.trust < -20)) || (_Slave.trust < -50)) {
-						if ((_Slave.intelligenceImplant < 30) || (_Slave.voice !== 0 && _Slave.accent + V.schoolroomUpgradeLanguage > 2) || (_Slave.skill.oral <= 10 + V.schoolroomUpgradeSkills * 20) || (_Slave.skill.whoring <= 10 + V.schoolroomUpgradeSkills * 20) || (_Slave.skill.entertainment <= 10 + V.schoolroomUpgradeSkills * 20) || (_Slave.skill.anal < 10 + V.schoolroomUpgradeSkills * 20) || ((_Slave.vagina >= 0) && (_Slave.skill.vaginal < 10 + V.schoolroomUpgradeSkills * 20))) {
-							res.push(dividerAndImage(_Slave));
-							res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-						} else {
-							res.push(`//${_Slave.slaveName} already has a basic education//</div>`);
-							continue;
-						}
-					} else {
-						res.push(`//${_Slave.slaveName} is too resistant to learn//</div>`);
-						continue;
-					}
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Schoolteacher Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Schoolteacher Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Dairy":
-				if (V.Flag === 0) {
-					const _dairySeed = V.bioreactorsXY + V.bioreactorsXX + V.bioreactorsHerm + V.bioreactorsBarren;
-					if (_Slave.assignment === "work in the dairy") {
-						res.pop();
-						continue;
-					}
-					if (V.dairy <= V.dairySlaves + _dairySeed) {
-						res.pop();
-						continue;
-					}
-					if ((_Slave.indentureRestrictions > 0) && (V.dairyRestraintsSetting > 1)) {
-						res.push(`//${_Slave.slaveName}'s indenture forbids extractive Dairy service.//</div>`);
-						continue;
-					} else if ((_Slave.indentureRestrictions > 1) && (V.dairyRestraintsSetting > 0)) {
-						res.push(`//${_Slave.slaveName}'s indenture allows only free range milking.//</div>`);
-						continue;
-					} else if (_Slave.breedingMark === 1 && V.propOutcome === 1 && V.dairyRestraintsSetting > 0) {
-						res.push(`//${_Slave.slaveName} may only be a free range cow//</div>`);
-						continue;
-					} else if ((V.dairyPregSetting > 0) && ((_Slave.bellyImplant !== -1) || (_Slave.broodmother !== 0))) {
-						res.push(`//${_Slave.slaveName}'s womb cannot accommodate current machine settings//</div>`);
-						continue;
-					} else {
-						if ((_Slave.lactation > 0) || (_Slave.balls > 0) || ((V.dairySlimMaintainUpgrade === 0 || V.dairySlimMaintain === 0) && (_Slave.boobs > 300 || _Slave.balls === 0 || V.dairyImplantsSetting === 1) && V.dairyImplantsSetting !== 2)) {
-							if ((_Slave.devotion > 20) || ((_Slave.devotion >= -50) && (_Slave.trust < -20)) || (_Slave.trust < -50) || (_Slave.amp === 1) || (V.dairyRestraintsUpgrade === 1)) {
-								if ((V.dairyStimulatorsSetting < 2) || (_Slave.anus > 2) || (V.dairyPrepUpgrade === 1)) {
-									if ((V.dairyPregSetting < 2) || (_Slave.vagina > 2) || (_Slave.ovaries === 0) || (V.dairyPrepUpgrade === 1)) {
-										res.push(dividerAndImage(_Slave));
-										res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-									} else {
-										res.push(`//${_Slave.slaveName}'s vagina cannot accommodate current machine settings//</div>`);
-										continue;
-									}
-								} else {
-									res.push(`//${_Slave.slaveName}'s anus cannot accommodate current machine settings//</div>`);
-									continue;
-								}
-							} else {
-								res.push(`//${_Slave.slaveName} must be obedient in order to be milked here//</div>`);
-								continue;
-							}
-						} else if ((V.dairySlimMaintainUpgrade === 1 && V.dairySlimMaintain === 1) || (V.dairyImplantsSetting === 2) || (_Slave.boobs <= 300 && _Slave.balls > 0 && (V.dairyImplantsSetting === 0 || V.dairyImplantsSetting === 3))) {
-							res.push(`//${_Slave.slaveName} is not lactating ${(V.seeDicks > 0) ? 'or producing semen' : ''} and ${V.dairyName}'s current settings forbid the automatic implantation of lactation inducing drugs or manual stimulation to induce it, so she cannot be a cow//</div>`);
-							continue;
-						} else {
-							res.push(`//${_Slave.slaveName} is not lactating ${(V.seeDicks > 0) ? 'or producing semen' : ''} and cannot be a cow//</div>`);
-							continue;
-						}
-					}
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Milkmaid Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Milkmaid Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Farmyard":
-				if (V.Flag === 0) {
-					if (_Slave.assignment === "work as a farmhand") {
-						res.pop();
-						continue;
-					}
-					if (V.farmyard <= V.farmyardSlaves) {
-						res.pop();
-						continue;
-					}
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Farmer Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Farmer Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Servants' Quarters":
-				if (V.Flag === 0) {
-					if (V.servantsQuarters <= V.servantsQuartersSlaves) {
-						res.pop();
-						continue;
-					}
-					if ((_Slave.devotion >= -20) || ((_Slave.devotion >= -50) && (_Slave.trust <= 20)) || (_Slave.trust < -20)) {
-						res.push(dividerAndImage(_Slave));
-						res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-					} else {
-						res.push(`//${_Slave.slaveName} must be either more fearful of you or devoted to you//</div>`);
-						continue;
-					}
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Stewardess Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Stewardess Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Master Suite":
-				if (V.Flag === 0) {
-					if (V.masterSuite <= V.masterSuiteSlaves) {
-						res.pop();
-						continue;
-					}
-					if ((_Slave.devotion > 20) || ((_Slave.devotion >= -50) && (_Slave.trust < -20)) || (_Slave.trust < -50)) {
-						res.push(dividerAndImage(_Slave));
-						res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-					} else {
-						res.push(`//${_Slave.slaveName} is not sufficiently broken for the master suite//</div>`);
-						continue;
-					}
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Concubine Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Concubine Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Cellblock":
-				if (_Slave.assignmentVisible !== 1) {
-					res.pop();
-					continue;
-				}
-				if (V.Flag === 0) {
-					if (V.cellblock <= V.cellblockSlaves) {
-						res.pop();
-						continue;
-					}
-					if ((_Slave.devotion < -20 && _Slave.trust >= -20) || (_Slave.devotion < -50 && _Slave.trust >= -50)) {
-						res.push(dividerAndImage(_Slave));
-						res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-					} else {
-						res.push(`//${_Slave.slaveName} is sufficiently broken in so that the cellblock would have no effect//</div>`);
-						continue;
-					}
-				} else if (V.Flag === 1) {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Wardeness Select":
-				res.push(dividerAndImage(_Slave));
-				res.push(`[[${_slaveName}|Wardeness Workaround][$i = ${_ssi}]]`);
-				break;
-			case "Arcade":
-				if (V.Flag === 0) {
-					if (_Slave.assignment === "be confined in the arcade") {
-						res.pop();
-						continue;
-					}
-					if (V.arcade <= V.arcadeSlaves && V.arcadeUpgradeFuckdolls !== 1) {
-						res.pop();
-						continue;
-					}
-					if ((_Slave.breedingMark !== 1 || V.propOutcome === 0)) {
-						if (_Slave.indentureRestrictions <= 0) {
-							res.push(dividerAndImage(_Slave));
-							res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-						} else {
-							res.push(`//${_Slave.slaveName}'s indenture forbids arcade service.//</div>`);
-							continue;
-						}
-					} else {
-						res.push(`//${_Slave.slaveName} is for private use only//</div>`);
-						continue;
-					}
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
-				}
-				break;
-			case "Pit":
-				if (V.Flag === 0) {
-					if ((_Slave.indentureRestrictions > 0) && (V.pitLethal === 1)) {
-						res.push(`//${_Slave.slaveName}'s indenture forbids lethal fights.//</div>`);
-						continue;
-					} else if (_Slave.indentureRestrictions > 1) {
-						res.push(`//${_Slave.slaveName}'s indenture forbids fighting.//</div>`);
-						continue;
-					} else if (_Slave.breedingMark === 1 && V.propOutcome === 1) {
-						res.push(`//${_Slave.slaveName} may not participate in combat//</div>`);
-						continue;
-					} else {
-						res.push(dividerAndImage(_Slave));
-						res.push(`[[${_slaveName}|Assign][$i = ${_ssi}]]`);
-					}
-				} else {
-					res.push(dividerAndImage(_Slave));
-					res.push(`[[${_slaveName}|Retrieve][$i = ${_ssi}]]`);
-				}
-				break;
 			case "Coursing Association":
 				if (V.Flag === 0) {
 					res.push(dividerAndImage(_Slave));
@@ -5579,86 +5258,18 @@ App.UI.slaveSummaryList = function (passageName) {
 		} else if ((_Slave.assignment === "stay confined") && ((_Slave.devotion > 20) || ((_Slave.trust < -20) && (_Slave.devotion >= -20)) || ((_Slave.trust < -50) && (_Slave.devotion >= -50)))) {
 			res.push("<strong><u><span class=lawngreen>stay confined.</span></u></strong>");
 			if (_Slave.sentence > 0) {
-				res.push(`(${_Slave.sentence} weeks)`);
+				res.push(` (${_Slave.sentence} weeks)`);
 			}
 		} else if (_Slave.choosesOwnAssignment === 1) {
 			res.push('choose her own job');
 		} else {
 			res.push(_Slave.assignment);
-			if (_Slave.sentence > 0) res.push(`${_Slave.sentence} weeks`);
+			if (_Slave.sentence > 0) res.push(` ${_Slave.sentence} weeks`);
 		}
 		res.push('. ');
 
-		/** @type {string[]} */
-		const assignments = [];
 		if ((V.displayAssignments === 1) && (passageName === "Main") && (_Slave.ID !== V.HeadGirl.ID) && (_Slave.ID !== V.Recruiter.ID) && (_Slave.ID !== V.Bodyguard.ID)) {
-			if (_Slave.assignment !== "rest") {
-				assignments.push(`<<link "Rest" "Main">><<= removeJob($slaves[${_ssi}], $slaves[${_ssi}].assignment)>><</link>>`);
-			} else {
-				assignments.push('Rest');
-			}
-			if (_Slave.assignment !== "please you") {
-				assignments.push(`<<link "Fucktoy" "Main">><<= assignJob($slaves[${_ssi}], "please you")>><</link>>`);
-			} else {
-				assignments.push('Fucktoy');
-			}
-			if (_Slave.indentureRestrictions <= 0 && (_Slave.breedingMark !== 1 || V.propOutcome === 0)) {
-				if (_Slave.assignment !== "work a glory hole") {
-					assignments.push(`<<link "Gloryhole" "Main">><<= assignJob($slaves[${_ssi}], "work a glory hole")>><</link>>`);
-				} else {
-					assignments.push('Hole');
-				}
-			}
-			if (_Slave.fuckdoll === 0) {
-				/* NON-FUCKDOLL ASSIGNMENTS */
-				if (_Slave.assignment !== "take classes") {
-					if ((_Slave.intelligenceImplant < 15) && ((_Slave.devotion >= -20) || ((_Slave.trust < -20) && (_Slave.devotion >= -50)) || (_Slave.trust < -50)) && (_Slave.fetish !== "mindbroken")) {
-						assignments.push(`<<link "Classes" "Main">><<= assignJob($slaves[${_ssi}], "take classes")>><</link>>`);
-					} else {
-						assignments.push('Classes');
-					}
-				} else {
-					assignments.push('Classes');
-				}
-				if (_Slave.assignment !== "be a servant") {
-					if (((_Slave.devotion >= -20) || ((_Slave.trust < -20) && (_Slave.devotion >= -50)) || (_Slave.trust < -50)) && canWalk(_Slave) && canSee(_Slave)) {
-						assignments.push(`<<link "House Servant" "Main">><<= assignJob($slaves[${_ssi}], "be a servant")>><</link>>`);
-					} else {
-						assignments.push('House Servant');
-					}
-				} else {
-					assignments.push('House Servant');
-				}
-				if ((_Slave.assignment !== "whore") && (_Slave.breedingMark !== 1 || V.propOutcome === 0)) {
-					assignments.push(`<<link "Whore" "Main">><<= assignJob($slaves[${_ssi}], "whore")>><</link>>`);
-				} else {
-					assignments.push('Whore');
-				}
-				if ((_Slave.assignment !== "serve the public") && (_Slave.breedingMark !== 1 || V.propOutcome === 0)) {
-					assignments.push(`<<link "Public Servant" "Main">><<= assignJob($slaves[${_ssi}], "serve the public")>><</link>>`);
-				} else {
-					assignments.push('Public Servant');
-				}
-				if ((_Slave.lactation > 0) || (_Slave.balls > 0)) {
-					if (_Slave.assignment !== "get milked") {
-						assignments.push(`<<link "Milked" "Main">><<= assignJob($slaves[${_ssi}], "get milked")>><</link>>`);
-					} else {
-						assignments.push('Milked');
-					}
-				}
-				if (_Slave.assignment !== "stay confined") {
-					assignments.push(`<<link "Confinement" "Main">><<= assignJob($slaves[${_ssi}], "stay confined")>><</link>>`);
-				} else {
-					assignments.push('Confinement');
-				}
-				if (_Slave.assignment !== "choose her own job") {
-					assignments.push(`<<link "Let ${_Slave.object} choose" "Main">><<= assignJob($slaves[${_ssi}], "choose her own job")>><</link>>`);
-				} else {
-					assignments.push(`Let ${_Slave.object} choose`);
-				}
-			} /* CLOSES FUCKDOLL CHECK */
-
-			res.push(assignments.join("&thinsp;|&thinsp;"));
+			res.push(App.UI.jobLinks.assignments(_ssi, "Main"));
 		}
 
 		const _numFacilities = V.brothel + V.club + V.dairy + V.farmyard + V.servantsQuarters + V.masterSuite + V.spa + V.clinic + V.schoolroom + V.cellblock + V.arcade + V.HGSuite;
@@ -5668,119 +5279,7 @@ App.UI.slaveSummaryList = function (passageName) {
 				V.returnTo = passageName;
 
 				res.push('<br>Transfer to: ');
-				/** @type {string[]} */
-				const transfers = [];
-				if (_Slave.assignment !== "rest" && _Slave.assignment !== "please you" && _Slave.assignment !== "take classes" && _Slave.assignment !== "be a servant" && _Slave.assignment !== "whore" && _Slave.assignment !== "serve the public" && _Slave.assignment !== "get milked" && _Slave.assignment !== "stay confined") {
-					transfers.push(`<<link "Penthouse" "Main">><<= removeJob($slaves[${_ssi}], $slaves[${_ssi}].assignment)>><</link>>`);
-				} else {
-					transfers.push('Penthouse');
-				}
-
-				if (V.arcade !== 0) {
-					if (V.arcade > V.arcadeSlaves && (_Slave.indentureRestrictions <= 0) && (_Slave.breedingMark !== 1 || V.propOutcome === 0)) {
-						transfers.push(`[[Arcade|Assign][$assignTo = "Arcade", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-					} else {
-						transfers.push('Arcade');
-					}
-				}
-
-				if (_Slave.fuckdoll === 0) {
-					/* NON-FUCKDOLL FACILITIES */
-					if (V.clinic !== 0) {
-						if (V.clinic > V.clinicSlaves && (_Slave.health < 20 || (V.Nurse !== 0 && ((_Slave.chem > 15 && V.clinicUpgradeFilters === 1) || (V.bellyImplants === 1 && _Slave.bellyImplant > -1) || (_Slave.pregKnown === 1 && (V.clinicSpeedGestation >= 0 || _Slave.pregControl === "speed up")) || (_Slave.pregAdaptation * 1000 < _Slave.bellyPreg || _Slave.preg > _Slave.pregData.normalBirth / 1.33))))) {
-							transfers.push(`[[Clinic|Assign][$assignTo = "Clinic", $i =${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Clinic');
-						}
-					}
-
-					if (V.masterSuite !== 0) {
-						if (V.masterSuite > V.masterSuiteSlaves && ((_Slave.devotion > 20) || ((_Slave.devotion >= -50) && (_Slave.trust < -20)) || (_Slave.trust < -50))) {
-							transfers.push(`[[Master Suite|Assign][$assignTo = "Master Suite", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Master Suite');
-						}
-					}
-
-					if (V.cellblock !== 0) {
-						if (V.cellblock > V.cellblockSlaves && ((_Slave.devotion < -20 && _Slave.trust >= -20) || (_Slave.devotion < -50 && _Slave.trust >= -50))) {
-							transfers.push(`[[Cellblock|Assign][$assignTo = "Cellblock", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Cellblock');
-						}
-					}
-
-					if (V.schoolroom !== 0) {
-						if (V.schoolroom > V.schoolroomSlaves && (_Slave.fetish !== "mindbroken" && (_Slave.devotion >= -20 || (_Slave.devotion >= -50 && _Slave.trust < -20) || _Slave.trust < -50) && ((_Slave.intelligenceImplant < 30) || (_Slave.voice !== 0 && _Slave.accent + V.schoolroomUpgradeLanguage > 2) || (_Slave.skill.oral <= 10 + V.schoolroomUpgradeSkills * 20) || (_Slave.skill.whoring <= 10 + V.schoolroomUpgradeSkills * 20) || (_Slave.skill.entertainment <= 10 + V.schoolroomUpgradeSkills * 20) || (_Slave.skill.anal < 10 + V.schoolroomUpgradeSkills * 20) || (_Slave.vagina >= 0 && _Slave.skill.vaginal < 10 + V.schoolroomUpgradeSkills * 20)))) {
-							transfers.push(`[[Schoolroom|Assign][$assignTo = "Schoolroom", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Schoolroom');
-						}
-					}
-
-					if (V.servantsQuarters !== 0) {
-						if (V.servantsQuarters > V.servantsQuartersSlaves && (canWalk(_Slave) && canSee(_Slave) && (_Slave.devotion >= -20 || (_Slave.devotion >= -50 && _Slave.trust <= 20) || _Slave.trust < -20))) {
-							transfers.push(`[[Servants' Quarters|Assign][$assignTo = "Servants' Quarters", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Servants\' Quarters');
-						}
-					}
-
-					if (V.brothel !== 0) {
-						if (V.brothel > V.brothelSlaves && (((_Slave.devotion > 50) || ((_Slave.devotion >= -50) && (_Slave.trust < -20)) || (_Slave.trust < -50) || (_Slave.trust > 50)) && (_Slave.breedingMark !== 1 || V.propOutcome === 0))) {
-							transfers.push(`[[Brothel|Assign][$assignTo = "Brothel", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Brothel');
-						}
-					}
-
-					if (V.club !== 0) {
-						if (V.club > V.clubSlaves && (((_Slave.devotion > 50) || ((_Slave.devotion >= -50) && (_Slave.trust < -20)) || (_Slave.trust < -50) || (_Slave.trust > 50)) && (_Slave.breedingMark !== 1 || V.propOutcome === 0))) {
-							transfers.push(`[[Club|Assign][$assignTo = "Club", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Club');
-						}
-					}
-
-					if (V.dairy !== 0) {
-						const _dairySeed = V.bioreactorsXY + V.bioreactorsXX + V.bioreactorsHerm + V.bioreactorsBarren;
-						if (V.dairy <= V.dairySlaves + _dairySeed) {
-							transfers.push('Dairy');
-						} else if (((_Slave.indentureRestrictions > 0) && (V.dairyRestraintsSetting > 1)) || ((_Slave.indentureRestrictions > 1) && (V.dairyRestraintsSetting > 0)) || (_Slave.breedingMark === 1 && V.propOutcome === 1 && V.dairyRestraintsSetting > 0) || ((V.dairyPregSetting > 0) && ((_Slave.bellyImplant !== -1) || (_Slave.broodmother > 0)))) {
-							transfers.push('Dairy');
-						} else if (((_Slave.lactation > 0) || (_Slave.balls > 0)) || ((V.dairyFeedersUpgrade === 1) && (V.dairyFeedersSetting > 0) && (V.dairySlimMaintainUpgrade === 0))) {
-							transfers.push(`[[Dairy|Assign][$assignTo = "Dairy", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Dairy');
-						}
-					}
-
-					if (V.farmyard !== 0) {
-						if (V.farmyard > V.farmyardSlaves) {
-							transfers.push(`[[Farmyard|Assign][$assignTo = "Farmyard", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Farmyard');
-						}
-					}
-
-					if (V.spa !== 0) {
-						if (V.spa > V.spaSlaves && ((_Slave.devotion >= -20 || _Slave.fetish === "mindbroken") && (_Slave.health < 20 || _Slave.trust <= 60 || _Slave.devotion <= 60 || _Slave.fetish === "mindbroken" || _Slave.sexualFlaw !== "none" || _Slave.behavioralFlaw !== "none"))) {
-							transfers.push(`[[Spa|Assign][$assignTo = "Spa", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Spa');
-						}
-					}
-
-					if (V.nursery !== 0) {
-						if (V.nurseryNannies > V.nurserySlaves && (_Slave.devotion > 20 || _Slave.trust > 20 || _Slave.fetish === "mindbroken")) {
-							transfers.push(`[[Nursery|Assign][$assignTo = "Nursery", $i = ${_ssi}]]`); /* $i = -1 tells Assign to use _Slave as-is */
-						} else {
-							transfers.push('Nursery');
-						}
-					} /* Closes transfer options check */
-
-					res.push(transfers.join('&thinsp;|&thinsp;'));
-				} /* CLOSES FUCKDOLL CHECK */
+				res.push(App.UI.jobLinks.transfers(_ssi));
 			}
 		} /* closes _numFacilities */
 
@@ -5799,6 +5298,12 @@ App.UI.slaveSummaryList = function (passageName) {
 		V.slaves[_ssi] = _Slave;
 		res.push('</div>');
 
+		if (managerSelectFacility !== undefined) {
+			if (managerSelectFacility.slaveHasExperiancedForManagerPosition(_Slave)) {
+				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
+				res.push('@@.lime;Has applicable career experience.@@');
+			}
+		}
 		switch (passageName) {
 			case "Main":
 				continue;
@@ -5838,12 +5343,6 @@ App.UI.slaveSummaryList = function (passageName) {
 					res.push('[[Change or remove Attendant|Attendant Select]]');
 				}
 				break;
-			case "Attendant Select":
-				if (setup.attendantCareers.includes(_Slave.career) || (_Slave.skill.attendant >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('@@.lime;Has applicable career experience.@@');
-				}
-				break;
 			case "Nursery":
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				if (V.Flag === 0) {
@@ -5854,12 +5353,6 @@ App.UI.slaveSummaryList = function (passageName) {
 					res.push('[[Change or remove Matron|Matron Select]]');
 				}
 				break;
-			case "Matron Select":
-				if (setup.matronCareers.includes(_Slave.career) || (_Slave.skill.matron >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('@@.lime;Has applicable career experience.@@');
-				}
-				break;
 			case "Brothel":
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				if (V.Flag === 0) {
@@ -5870,12 +5363,6 @@ App.UI.slaveSummaryList = function (passageName) {
 					res.push('[[Change or remove Madam|Madam Select]]');
 				}
 				break;
-			case "Madam Select":
-				if (setup.madamCareers.includes(_Slave.career) || (_Slave.skill.madam >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('@@.lime;Has applicable career experience.@@');
-				}
-				break;
 			case "Club":
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				if (V.Flag === 0) {
@@ -5894,12 +5381,6 @@ App.UI.slaveSummaryList = function (passageName) {
 					res.push(`<<link "Release ${_Slave.object} from $arcadeName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
 				}
 				break;
-			case "DJ Select":
-				if (setup.DJCareers.includes(_Slave.career) || (_Slave.skill.DJ >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('@@.lime;Has applicable career experience.@@');
-				}
-				break;
 			case "Clinic":
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				if (V.clinicUpgradeScanner === 1) {
@@ -5913,12 +5394,6 @@ App.UI.slaveSummaryList = function (passageName) {
 					res.push('[[Change or remove Nurse|Nurse Select]]');
 				}
 				break;
-			case "Nurse Select":
-				if (setup.nurseCareers.includes(_Slave.career) || (_Slave.skill.nurse >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('@@.lime;Has applicable career experience.@@');
-				}
-				break;
 			case "Schoolroom":
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				if (V.Flag === 0) {
@@ -5929,12 +5404,6 @@ App.UI.slaveSummaryList = function (passageName) {
 					res.push('[[Change or remove Schoolteacher|Schoolteacher Select]]');
 				}
 				break;
-			case "Schoolteacher Select":
-				if (setup.schoolteacherCareers.includes(_Slave.career) || (_Slave.skill.teacher >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('@@.lime;Has applicable career experience.@@');
-				}
-				break;
 			case "Dairy":
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				if (V.Flag === 0) {
@@ -5945,12 +5414,6 @@ App.UI.slaveSummaryList = function (passageName) {
 					res.push('[[Change or remove Milkmaid|Milkmaid Select]]');
 				}
 				break;
-			case "Milkmaid Select":
-				if (setup.milkmaidCareers.includes(_Slave.career) || (_Slave.skill.milkmaid >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('@@.lime;Has applicable career experience.@@');
-				}
-				break;
 			case "Farmyard":
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				if (V.Flag === 0) {
@@ -5961,12 +5424,6 @@ App.UI.slaveSummaryList = function (passageName) {
 					res.push('[[Change or remove Farmer|Farmer Select]]');
 				}
 				break;
-			case "Farmer Select":
-				if (setup.farmerCareers.includes(_Slave.career) || (_Slave.skill.farmer >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('@@.lime;Has applicable career experience.@@');
-				}
-				break;
 			case "Servants' Quarters":
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				if (V.Flag === 0) {
@@ -5977,12 +5434,6 @@ App.UI.slaveSummaryList = function (passageName) {
 					res.push('[[Change or remove Stewardess|Stewardess Select]]');
 				}
 				break;
-			case "Stewardess Select":
-				if (setup.stewardessCareers.includes(_Slave.career) || (_Slave.skill.stewardess >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('@@.lime;Has applicable career experience.@@');
-				}
-				break;
 			case "Master Suite":
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				if (V.Flag === 0) {
@@ -6003,12 +5454,6 @@ App.UI.slaveSummaryList = function (passageName) {
 					res.push('[[Change or remove Wardeness|Wardeness Select]]');
 				}
 				break;
-			case "Wardeness Select":
-				if (setup.wardenessCareers.includes(_Slave.career) || (_Slave.skill.wardeness >= V.masteredXP)) {
-					res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-					res.push('@@.lime;Has applicable career experience.@@');
-				}
-				break;
 			case "New Game Plus":
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				if (V.Flag === 0) {
diff --git a/src/js/utilJS.js b/src/js/utilJS.js
index 9a818220e493659114da787fe9373181146c883f..4d702148361483e3fead571b04b500eb20933180 100644
--- a/src/js/utilJS.js
+++ b/src/js/utilJS.js
@@ -1700,3 +1700,22 @@ window.changeSkinTone = function(skin, value) {
 	}
 	return prop;
 };
+
+
+/**
+ * Creates a span for an link with tooltip containing the reasons why it is disabled
+ * @param {string} link
+ * @param {string[]} reasons
+ * @returns {string}
+ */
+App.UI.disabledLink = function(link, reasons) {
+	const tooltips = reasons.length === 1 ?
+		`<span class="tooltip">${reasons}</span>`:
+		`<div class="tooltip"><ul>${reasons.map(e => `<li>${e}</li>`).join('')}</ul></div>`;
+	return '<span class="textWithTooltip">' + link + tooltips + '</span>';
+}
+
+
+App.Utils.slaveRefString = function(i) {
+	return i >= 0 ? `$slaves[${i}]` : '$activeSlave';
+}
diff --git a/src/uncategorized/slaveInteract.tw b/src/uncategorized/slaveInteract.tw
index cd313a237e65174065e24a36823e56beced54db7..e9cb0eb0668aca2956c3da466c6255a7303393c0 100644
--- a/src/uncategorized/slaveInteract.tw
+++ b/src/uncategorized/slaveInteract.tw
@@ -514,154 +514,12 @@
 	/* CAN BE REASSIGNED */
 
 	Assignment: <strong><span id="assign">$activeSlave.assignment<<if $activeSlave.sentence>> ($activeSlave.sentence weeks)<</if>></span>.</strong>
-	<<link "Rest">>				   <<= assignJob($activeSlave, "rest")>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-	<<if ["be confined in the arcade", "serve in the club", "serve in the master suite", "work as a farmhand", "work as a nanny", "work as a servant", "work in the brothel", "work in the dairy"].includes($activeSlave.assignment)>>
-	| <<link "Remove From Facility">>	<<= removeJob($activeSlave, $activeSlave.assignment)>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-	<</if>>
-	| <<link "Fucktoy">>				<<= assignJob($activeSlave, "please you")>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-
-	<<if ($activeSlave.indentureRestrictions <= 0) && ($activeSlave.breedingMark != 1 || $propOutcome == 0)>>
-	| <<link "Gloryhole">>			  <<= assignJob($activeSlave, "work a glory hole")>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-	<</if>>
-
-	<<if $activeSlave.fuckdoll == 0>> /* NON-FUCKDOLL ASSIGNMENTS */
-
-	<<if ($activeSlave.devotion >= -20) || (($activeSlave.devotion >= -50) && ($activeSlave.trust < -20)) || ($activeSlave.trust < -50)>>
-	<<if $activeSlave.intelligenceImplant < 15 && $activeSlave.fetish != "mindbroken">>
-	| <<link "Classes">>				<<= assignJob($activeSlave, "take classes")>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-	<<else>>
-	| Classes
-	<</if>>
-	<<else>>
-	/*| //Too resistant to take classes// */
-	<</if>>
-
-	<<if (($activeSlave.devotion >= -20) || (($activeSlave.trust < -20) && ($activeSlave.devotion >= -50)) || ($activeSlave.trust < -50))>>
-	| <<link "Subordinate Slave" "Subordinate Targeting">>	  <<= assignJob($activeSlave, "be a subordinate slave")>><</link>>
-	<<if canSee($activeSlave) && canWalk($activeSlave)>>
-	| <<link "House Servant">>		  <<= assignJob($activeSlave, "be a servant")>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-	<<else>>
-	/*| //Blind or immobile slaves cannot be servants// */
-	<</if>>
-	<<else>>
-	/*| //Too resistant to be a servant// */
-	<</if>>
-
-	<<if ($activeSlave.breedingMark != 1 || $propOutcome == 0)>>
-	| <<link "Whore">>				  <<= assignJob($activeSlave, "whore")>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-	| <<link "Public Servant">>		 <<= assignJob($activeSlave, "serve the public")>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-	<</if>>
-
-	<<if ($activeSlave.lactation > 0) || ($activeSlave.balls > 0 && $activeSlave.ballType == "human")>>
-	| <<link "Milked">>				 <<= assignJob($activeSlave, "get milked")>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-	<<else>>
-	/*| //Not lactating// */
-	<</if>>
-
-	| <<link "Confinement">>		 	<<= assignJob($activeSlave, "stay confined")>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-	| <<link "Let $him choose">>		<<= assignJob($activeSlave, "choose her own job")>><<replace "#assign">>$activeSlave.assignment<</replace>><<SlaveInteractFucktoy>><</link>>
-	| <<link "Stay on this assignment for another month">><<if $activeSlave.assignment != "choose her own job">><<set $activeSlave.sentence += 4>><<replace "#assign">>$activeSlave.assignment ($activeSlave.sentence weeks)<</replace>><</if>><</link>>
-
-	<</if>>/* CLOSES FUCKDOLL CHECK */
+	<span id="assignmentLinks"><<= App.UI.SlaveInteract.assignmentBlock("assignmentLinks")>></span>
 
 	<<set _numFacilities = $brothel+$club+$dairy+$farmyard+$servantsQuarters+$masterSuite+$spa+$nursery+$clinic+$schoolroom+$cellblock+$arcade+$HGSuite>>
 
 	<<if _numFacilities > 0>>
-
-	<br>Transfer to:
-
-	<<if $arcade != 0>>
-		<<if $arcade > $arcadeSlaves && ($activeSlave.indentureRestrictions <= 0) && ($activeSlave.breedingMark != 1 || $propOutcome == 0)>>
-			[[Arcade|Assign][$assignTo = "Arcade", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Arcade<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $activeSlave.fuckdoll == 0>> /* NON-FUCKDOLL FACILITIES */
-
-	<<if $clinic != 0>>
-		<<if $clinic > $clinicSlaves && ($activeSlave.health < 20 || ($Nurse != 0 && (($activeSlave.chem > 15 && $clinicUpgradeFilters == 1) || ($bellyImplants == 1 && $activeSlave.bellyImplant > -1) || ($activeSlave.pregKnown == 1 && ($clinicSpeedGestation >= 0 || $activeSlave.pregControl == "speed up")) || ($activeSlave.pregAdaptation*1000 < $activeSlave.bellyPreg || $activeSlave.preg > $activeSlave.pregData.normalBirth/1.33))))>>
-			[[Clinic|Assign][$assignTo = "Clinic", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Clinic<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $masterSuite != 0>>
-		<<if $masterSuite > $masterSuiteSlaves && (($activeSlave.devotion > 20) || (($activeSlave.devotion >= -50) && ($activeSlave.trust < -20)) || ($activeSlave.trust < -50))>>
-			[[Master Suite|Assign][$assignTo = "Master Suite", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Master Suite<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $cellblock != 0>>
-		<<if $cellblock > $cellblockSlaves && (($activeSlave.devotion < -20 && $activeSlave.trust >= -20) || ($activeSlave.devotion < -50 && $activeSlave.trust >= -50))>>
-			[[Cellblock|Assign][$assignTo = "Cellblock", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Cellblock<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $schoolroom != 0>>
-		<<if $schoolroom > $schoolroomSlaves && ($activeSlave.fetish != "mindbroken" && ($activeSlave.devotion >= -20 || ($activeSlave.devotion >= -50 && $activeSlave.trust < -20) || $activeSlave.trust < -50) && (($activeSlave.intelligenceImplant < 30) || ($activeSlave.voice != 0 && $activeSlave.accent+$schoolroomUpgradeLanguage > 2) || ($activeSlave.skill.oral <= 10+$schoolroomUpgradeSkills*20) || ($activeSlave.skill.whoring <= 10+$schoolroomUpgradeSkills*20) || ($activeSlave.skill.entertainment <= 10+$schoolroomUpgradeSkills*20) || ($activeSlave.skill.anal < 10+$schoolroomUpgradeSkills*20) || ($activeSlave.vagina >= 0 && $activeSlave.skill.vaginal < 10+$schoolroomUpgradeSkills*20)))>>
-			[[Schoolroom|Assign][$assignTo = "Schoolroom", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Schoolroom<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $servantsQuarters != 0>>
-		<<if $servantsQuarters > $servantsQuartersSlaves && (canWalk($activeSlave) && canSee($activeSlave) && ($activeSlave.devotion >= -20 || ($activeSlave.devotion >= -50 && $activeSlave.trust <= 20) || $activeSlave.trust < -20))>>
-			[[Servants' Quarters|Assign][$assignTo = "Servants' Quarters", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Servants' Quarters<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $brothel != 0>>
-		<<if $brothel > $brothelSlaves && ((($activeSlave.devotion > 50) || (($activeSlave.devotion >= -50) && ($activeSlave.trust < -20)) || ($activeSlave.trust < -50) || ($activeSlave.trust > 50)) && ($activeSlave.breedingMark != 1 || $propOutcome == 0))>>
-			[[Brothel|Assign][$assignTo = "Brothel", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Brothel<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $club != 0>>
-		<<if $club > $clubSlaves && ((($activeSlave.devotion > 50) || (($activeSlave.devotion >= -50) && ($activeSlave.trust < -20)) || ($activeSlave.trust < -50) || ($activeSlave.trust > 50)) && ($activeSlave.breedingMark != 1 || $propOutcome == 0))>>
-			[[Club|Assign][$assignTo = "Club", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Club<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $dairy != 0>>
-		<<set _dairySeed = $bioreactorsXY+$bioreactorsXX+$bioreactorsHerm+$bioreactorsBarren>>
-		<<if $dairy <= $dairySlaves+_dairySeed>>
-			Dairy
-		<<elseif((($activeSlave.indentureRestrictions > 0) && ($dairyRestraintsSetting > 1)) || (($activeSlave.indentureRestrictions > 1) && ($dairyRestraintsSetting > 0)) || ($activeSlave.breedingMark == 1 && $propOutcome == 1 && $dairyRestraintsSetting > 0) || (($dairyPregSetting > 0) && (($activeSlave.bellyImplant != -1) || ($activeSlave.broodmother > 0))))>>
-			Dairy
-		<<elseif (($activeSlave.lactation > 0) || ($activeSlave.balls > 0)) || (($dairyFeedersUpgrade == 1) && ($dairyFeedersSetting > 0) && ($dairySlimMaintainUpgrade == 0))>>
-			[[Dairy|Assign][$assignTo = "Dairy", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Dairy<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $farmyard != 0>>
-		<<if $farmyard > $farmyardSlaves>>
-			[[Farmyard|Assign][$assignTo = "Farmyard", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Farmyard<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $spa != 0>>
-		<<if $spa > $spaSlaves && (($activeSlave.devotion >= -20 || $activeSlave.fetish == "mindbroken") && ($activeSlave.health < 20 || $activeSlave.trust <= 60 || $activeSlave.devotion <= 60 || $activeSlave.fetish == "mindbroken" || $activeSlave.sexualFlaw !== "none" || $activeSlave.behavioralFlaw !== "none"))>>
-			[[Spa|Assign][$assignTo = "Spa", $i = -1]] /* $i = -1 tells Assign to use $activeSlave as-is */
-		<<else>>Spa<</if>>
-		<<if _numFacilities-- > 1>>|<</if>>
-	<</if>>
-
-	<<if $nursery != 0>>
-		<<if $nurseryNannies > $nurserySlaves && ($activeSlave.devotion > 20 || $activeSlave.trust > 20 || $activeSlave.fetish == "mindbroken")>>
-			[[Nursery|Assign][$assignTo = "Nursery", $i = -1]]
-		<<else>>Nursery<</if>>
-	<</if>>
-
-	<</if>> /* CLOSES FUCKDOLL CHECK */
-
+		<br>Transfer to: <<= App.UI.jobLinks.transfers(-1)>>
 	<</if>> /* closes _numFacilities */
 
 <</switch>> /* END CAN BE REASSIGNED */
diff --git a/src/utility/miscWidgets.tw b/src/utility/miscWidgets.tw
index f6cc307d52fc7a12636aabe21cf7acd57ff768f7..e5951ea84a16cc0c93ca7eca4765a7020dbb3c9e 100644
--- a/src/utility/miscWidgets.tw
+++ b/src/utility/miscWidgets.tw
@@ -770,37 +770,6 @@ This experience
 <</if>>
 <</widget>>
 
-/%
- Call as <<SlaveInteractFucktoy>>
-%/
-<<widget "SlaveInteractFucktoy">>
-
-<<replace #fucktoypref>>
-	<<if ($activeSlave.assignment == "please you") || ($activeSlave.assignment == "serve in the master suite") || ($activeSlave.assignment == "be your Concubine")>>
-		__Fucktoy use preference__: <strong><span id="hole">$activeSlave.toyHole</span></strong>.
-		<<link "Mouth">><<set $activeSlave.toyHole = "mouth">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>
-		| <<link "Tits">><<set $activeSlave.toyHole = "boobs">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>
-		<<if ($activeSlave.vagina > 0) && canDoVaginal($activeSlave)>>
-			| <<link "Pussy">><<set $activeSlave.toyHole = "pussy">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>
-		<<elseif ($activeSlave.vagina == 0)>>
-			| //Take $his virginity before giving $his pussy special attention//
-		<</if>>
-		<<if ($activeSlave.anus > 0) && canDoAnal($activeSlave)>>
-			| <<link "Ass">><<set $activeSlave.toyHole = "ass">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>
-		<<else>>
-			| //Take $his anal virginity before giving $his ass special attention//
-		<</if>>
-		/*check*/
-		<<if ($activeSlave.dick > 0) && canPenetrate($activeSlave)>>
-			| <<link "Dick">><<set $activeSlave.toyHole = "dick">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>
-		<</if>>
-		| <<link "No Preference">><<set $activeSlave.toyHole = "all her holes">><<replace "#hole">>$activeSlave.toyHole<</replace>><</link>>
-		<br>
-	<</if>>
-<</replace>>
-
-<</widget>>
-
 /*
  OBSOLETE: Use setPregType()instead!
  Call as <<SetPregType>>