diff --git a/src/004-base/facility.js b/src/004-base/facility.js
index 041e190e1d8bb3a757a6c015ef26426be49ea14d..1dd973e70a88057bd19d78f0f78b8ff100bf1b36 100644
--- a/src/004-base/facility.js
+++ b/src/004-base/facility.js
@@ -1,14 +1,21 @@
 
-App.Data.PositionDesc = class {
+App.Data.JobDesc = class {
 	constructor() {
 		this.position = "";
 		this.assignment = "";
+		this.publicSexUse = false;
+		this.fuckdollAccepted = false;
 	}
 }
 
-App.Data.ManagerPositionDesc = class extends App.Data.PositionDesc {
+App.Data.ManagerJobDesc = class extends App.Data.JobDesc {
 	constructor() {
 		super();
+		this.shouldWalk = true;
+		this.shouldSee = true;
+		this.shouldHear = true;
+		this.shouldTalk = true;
+		this.requiredDevotion = 50;
 		/**
 		 * Applicable careers
 		 * @type {string[]} */
@@ -25,29 +32,207 @@ App.Data.FacilityDesc = class {
 		/** Base name for state variables */
 		this.baseName = "";
 		/** Generic name for UI (Brothel, Club, etc.)
-		 * If null, baseName will be used instead
+		 * If null, baseName is used instead
 		*/
 		this.genericName = "";
-		/** @type {App.Data.PositionDesc} */
-		this.assignee = null;
-		/** @type {App.Data.PositionDesc} */
-		this.penthouse = null;
-		/** @type {App.Data.ManagerPositionDesc} */
+		/** @type {Object.<string, App.Data.JobDesc>} */
+		this.jobs = {};
+		this.defaultJob = "";
+		/** @type {App.Data.ManagerJobDesc} */
 		this.manager = null;
 	}
 }
 
 App.Data.Facilities = {};
-
 App.Entity.Facilities = {};
 
-App.Entity.Facilities.Facility = class {
+App.Entity.Facilities.Job = class {
+	constructor() {
+		/** @type {App.Data.JobDesc} */
+		this.desc = null;
+		/** @type {App.Entity.Facilities.Facility} */
+		this.facility = null;
+	}
+
+	/**
+	 * Can slave be employed at this position
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canEmploy(slave) {
+		let r = [];
+		if (this.isEmployed(slave)) {
+			r.push(`${slave.slaveName} is already assigned to ${this.desc.assignment} at ${this.facility.name}`);
+			return r;
+		}
+		if (!this._facilityHasFreeSpace) {
+			r.push(`Capacity of ${this.facility.name} exceeded`);
+		}
+		if (slave.assignment === this.desc.assignment) {
+			r.push(`${slave.slaveName} is already assigned to ${this.desc.assignment}`);
+		}
+		if (this.desc.publicSexUse &&
+			(slave.breedingMark === 1 || State.variables.propOutcome === 1)) {
+			r.push(`${slave.slaveName} is for private use only`);
+		}
+
+		if (!this.desc.fuckdollAccepted && slave.fuckdoll > 0) {
+			r.push(`Fuckdolls can't ${this.desc.assignment} at ${this.facility.name}`);
+		}
+		return r;
+	}
+
+	/**
+	 * Is slave already assigned to this job
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {boolean}
+	 */
+	isEmployed(slave) {
+		return slave.assignment === this.desc.assignment;
+	}
+
+	/**
+	 *
+	 * @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]
+	 * @param {string} [linkText]
+	 * @returns {string}
+	 */
+	assingmentLink(i, passage, callback, linkText) {
+		linkText = linkText || this.desc.position;
+		const linkAction = callback !== undefined ? callback(this.desc.assignment) : '';
+		return `<<link "${linkText}"${passage !== undefined ? ' "' + passage + '"' : ''}>><<= assignJob(${App.Utils.slaveRefString(i)}, "${this.desc.assignment}")>>${linkAction}<</link>>`;
+	}
+
+	/**
+	 * 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`;
+	}
+
+	/**
+	 * @private
+	 */
+	get _facilityHasFreeSpace() {
+		return this.facility.hasFreeSpace;
+	}
+}
+
+App.Entity.Facilities.ManagingJob = class extends App.Entity.Facilities.Job {
+	constructor() {
+		super();
+		/** @type {App.Data.ManagerJobDesc} */
+		this.desc = null;
+	}
+
+	/**
+	 * Can slave be employed at this position
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
+		if (slave.devotion < this.desc.requiredDevotion) {
+			r.push(`${slave.slaveName} must be more devoted to you.`);
+		}
+		if (this.desc.shouldWalk && !canWalk(slave)) {
+			r.push(`${slave.slaveName} must be able to walk.`);
+		}
+		if (this.desc.shouldSee && !canSee(slave)) {
+			r.push(`${slave.slaveName} must have working eyes.`);
+		}
+		if (this.desc.shouldHear && !canHear(slave)) {
+			r.push(`${slave.slaveName} must be able to hear.`);
+		}
+		if (this.desc.shouldTalk && !canTalk(slave)) {
+			r.push(`${slave.slaveName} must be able to talk.`);
+		}
+		return r;
+	}
+	/**
+	 * Returns true if slave has enough applicable skill or career
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {boolean}
+	 */
+	slaveHasExperience(slave) {
+		return (this.desc.skill !== null && slave.skill[this.desc.skill] >= State.variables.masteredXP) ||
+			(typeof slave.career === 'string' && this.desc.careers.includes(slave.career));
+	}
+
+	/**
+	 * @private
+	 */
+	get _facilityHasFreeSpace() {
+		return true;
+	}
+}
+
+App.Entity.Facilities.Facility = class {
 	/**
 	 * @param {App.Data.FacilityDesc} desc defines state variable for this facility
+	 * @param {Object.<string, App.Entity.Facilities.Job>} [jobs] job object that are not default
+	 * @param {App.Entity.Facilities.ManagingJob} [manager]
 	 */
-	constructor(desc) {
+	constructor(desc, jobs, manager) {
 		this.desc = desc;
+		jobs = jobs || {};
+		/** @private @type {Object.<string, App.Entity.Facilities.Job>} */
+		this._jobs = {};
+
+		// if this facility provides only a single job
+		const singleJobFacility = Object.keys(this.desc.jobs).length === 1;
+		for (const jn in this.desc.jobs) {
+			if (jobs[jn] !== undefined) {
+				this._jobs[jn] = jobs[jn];
+			} else {
+				this._jobs[jn] = singleJobFacility ? new App.Entity.Facilities.FacilitySingleJob() : new App.Entity.Facilities.Job();
+			}
+			this._jobs[jn].facility = this;
+			this._jobs[jn].desc = desc.jobs[jn];
+		}
+
+		if (manager === undefined) {
+			// default manager job implementation
+			manager = (this.desc.manager !== null) ? new App.Entity.Facilities.ManagingJob() : null;
+		}
+		/** @private */
+		this._manager = manager;
+		if (this._manager !== null) {
+			this._manager.facility = this;
+			this._manager.desc = this.desc.manager;
+		}
 	}
 
 	/** Facility display name
@@ -62,8 +247,24 @@ App.Entity.Facilities.Facility = class {
 		return this.desc.genericName !== null ? this.desc.genericName : capFirstChar(this.desc.baseName);
 	}
 
-	get penthouseJob() {
-		return this.desc.penthouse !== null ? this.desc.penthouse.position : undefined;
+	/** All jobs at this facility
+	 * @returns {string[]}
+	 */
+	get jobsNames() {
+		return Object.keys(this.desc.jobs);
+	}
+
+	/**
+	 * Returns job description
+	 * @param {string} name
+	 * @returns {App.Entity.Facilities.Job}
+	 */
+	job(name) {
+		return this._jobs[name];
+	}
+
+	get manager() {
+		return this._manager;
 	}
 
 	/** Facility slave capacity
@@ -76,10 +277,6 @@ App.Entity.Facilities.Facility = class {
 		return this.capacity > 0;
 	}
 
-	get penthouseAssignmentAvailable() {
-		return this.desc.penthouse !== null;
-	}
-
 	/** Number of already hosted slaves
 	 * @returns {number} */
 	get hostedSlaves() {
@@ -109,151 +306,95 @@ App.Entity.Facilities.Facility = class {
 	}
 
 	/**
-	 *
+	 * Can this facility host the given slave
 	 * @param {App.Entity.SlaveState} slave
+	 * @param {string} [job]
 	 * @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`);
+	canHostSlave(slave, job) {
+		job = job || this.desc.defaultJob;
+		const j = this.job(job);
+		if (j === undefined) {
+			console.log(`Can't find job ${job} at ${this.name}`); // eslint-disable-line no-console
 		}
-
-		if (slave.assignment === this.desc.assignee.assignment) {
-			r.push(`${slave.slaveName} is already at ${this.name}`);
+		// if there are more than one jobs at this facility, test them too
+		if (Object.keys(this.desc.jobs).length > 1 && this.isHosted(slave)) {
+			return [`${slave.slaveName} is already assigned to ${slave.assignment} at ${this.name}`];
 		}
-
+		let r = j.canEmploy(slave);
 		return r;
 	}
 
 	/**
+	 * Does the given slave work at this facility
 	 * @param {App.Entity.SlaveState} slave
-	 * @returns {string[]} array with rejection reasons. Slave can be hosted if this is empty.
+	 * @returns {boolean}
 	 */
-	slaveCanWorkFromPenthouse(slave) {
-		let r = [];
-		if (slave.assignment === this.desc.penthouse.assignment) {
-			r.push(`${slave.slaveName} is already assigned to ${this.desc.penthouse.assignment}`);
+	isHosted(slave) {
+		for (const j in this._jobs) {
+			if (this._jobs[j].isEmployed(slave)) return true;
 		}
-		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>>`;
+		return false;
 	}
 
 	/**
-	 * Returns link text for the facility transfer
+	 * Returns link text for the job assignments
 	 * @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}
+	 * @param {string} [job] generate link only for this job
+	 * @param {string} [passage]
+	 * @param {linkCallback} callback
+	 * @returns {string[]}
 	 */
-	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;
+	assignmentLinks(i, job, passage, callback) {
+		/** @type {App.Entity.SlaveState} */
+		const slave = App.Utils.slaveByIndex(i);
+		const jobs = job === undefined ? this._jobs : {job: this._jobs[job]};
+
+		let res = []
+		for (const jn in jobs) {
+			const j = jobs[jn];
+			let rejects = j.canEmploy(slave);
+			if (rejects.length === 0) {
+				res.push(j.assingmentLink(i, passage, callback));
+			} else {
+				res.push(App.UI.disabledLink(j.desc.position, rejects));
+			}
 		}
-		return true;
+		return res
 	}
 
 	/**
-	 * @protected
-	 * Standard message that slave is not broken enough
-	 * @param {App.Entity.SlaveState} slave
+	 * Returns link text for the facility transfer
+	 * @param {number} i slave index
+	 * @param {string} [job] transfer to this job (uses default job if this is undefined)
+	 * @param {string} [passage]
+	 * @param {linkCallback} [callback]
 	 * @returns {string}
 	 */
-	static _stdBreakageMessage(slave) {
-		return `${slave.slaveName} must be either more fearful of you or devoted to you`;
+	transferLink(i, job, passage, callback) {
+		job = job || this.desc.defaultJob;
+		return this._jobs[job].assingmentLink(i, passage, callback, this.genericName);
 	}
 }
 
-App.Entity.Facilities.SexWorkFacility = class extends App.Entity.Facilities.Facility {
+/**
+ * Job for a facility with a single job option
+ */
+App.Entity.Facilities.FacilitySingleJob = class extends App.Entity.Facilities.Job {
 	/**
-	 * @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.
+	 * Returns link text for the penthhouse assignment
+	 * @param {number} i slave index
+	 * @param {string} [passage] passage to go to
+	 * @param {linkCallback} [callback]
+	 * @param {string} [linkText]
+	 * @returns {string}
 	 */
-	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;
+	assingmentLink(i, passage, callback, linkText) {
+		linkText = linkText || this.facility.genericName;
+		const linkAction = callback !== undefined ? callback(this.desc.assignment) : '';
+		const psg = passage === undefined ? '' : `, $returnTo = "${passage}"`;
+		return `<<link "${linkText}" "Assign">><<set $assignTo = "${this.facility.genericName}", $i = ${i}${psg}>>${linkAction}<</link>>`;
 	}
 }
 
diff --git a/src/facilities/arcade/arcadeFramework.js b/src/facilities/arcade/arcadeFramework.js
index dd44a51309f009ca185f30e564f1540e224dbdc9..0449a7b4431fa8a02a24837ef9e1dc85f7e9049a 100644
--- a/src/facilities/arcade/arcadeFramework.js
+++ b/src/facilities/arcade/arcadeFramework.js
@@ -1,49 +1,36 @@
 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",
+	jobs: {
+		assignee: {
+			position: "whore",
+			assignment: "be confined in the arcade",
+			publicSexUse: true,
+			fuckdollAccepted: true
+		},
 	},
+	defaultJob: "assignee",
 	manager: null
 }
 
-App.Entity.Facilities.Arcade = class extends App.Entity.Facilities.SexWorkFacility {
-	constructor() {
-		super(App.Data.Facilities.arcade, true, true);
-	}
-
+App.Entity.Facilities.ArcadeJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
+	 * Can slave be employed at this position
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
-
+	canEmploy(slave) {
+		let r = super.canEmploy(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();
+App.Entity.facilities.arcade = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.arcade,
+	{
+		assignee: new App.Entity.Facilities.ArcadeJob()
+	}
+);
diff --git a/src/facilities/armory/armoryFramework.js b/src/facilities/armory/armoryFramework.js
new file mode 100644
index 0000000000000000000000000000000000000000..a425babcdbe6a0980989afa7748f48deeba4c8d4
--- /dev/null
+++ b/src/facilities/armory/armoryFramework.js
@@ -0,0 +1,23 @@
+App.Data.Facilities.armory = {
+	baseName: "dojo",
+	genericName: "armory",
+	jobs: {	},
+	defaultJob: null,
+	manager: {
+		position: "bodyguard",
+		assignment: "guard you",
+		careers: ["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"],
+		skill: "bodyguard",
+		publicSexUse: true,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: true,
+		shouldHear: true,
+		shouldTalk: false,
+		requiredDevotion: 51
+	}
+}
+
+App.Entity.facilities.armory = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.armory
+);
diff --git a/src/facilities/brothel/brothelFramework.js b/src/facilities/brothel/brothelFramework.js
index 296ef47f458a34eee12a4fb7b67e1892c5c442dd..a58133410b8440a3108d12ded1d5c7c6997e133f 100644
--- a/src/facilities/brothel/brothelFramework.js
+++ b/src/facilities/brothel/brothelFramework.js
@@ -1,42 +1,64 @@
 App.Data.Facilities.brothel = {
 	baseName: "brothel",
 	genericName: null,
-	assignee: {
-		position: "whore",
-		assignment: "work in the brothel",
-	},
-	penthouse: {
-		position: "Whore",
-		assignment: "whore",
+	jobs: {
+		assignee: {
+			position: "whore",
+			assignment: "work in the brothel",
+			publicSexUse: true,
+			fuckdollAccepted: false
+		},
 	},
+	defaultJob: "assignee",
 	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
+		skill: null,
+		publicSexUse: true,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: true,
+		shouldHear: true,
+		shouldTalk: false,
+		requiredDevotion: 50
 	}
 }
 
-App.Entity.Facilities.Brothel = class extends App.Entity.Facilities.SexWorkFacility {
-	constructor() {
-		super(App.Data.Facilities.brothel, true, false);
-	}
-
+App.Entity.Facilities.BrothelJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
+	canEmploy(slave) {
+		let r = super.canEmploy(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));
+		if (!App.Entity.Facilities.Job._isBrokenEnough(slave, 51, -50, -20, -50, 50)) {
+			r.push(App.Entity.Facilities.Job._stdBreakageMessage(slave));
 		}
+		return r;
+	}
+}
 
+App.Entity.Facilities.MadamJob = class extends App.Entity.Facilities.ManagingJob {
+	/**
+	 * @param {App.Entity.SlaveState} slave
+	 * @returns {string[]}
+	 */
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
+		if (slave.intelligence + slave.intelligenceImplant < -50) {
+			r.push(`${slave.slaveName} must be more intellegent or educated.`);
+		}
 		return r;
 	}
 }
 
-App.Entity.facilities.brothel = new App.Entity.Facilities.Brothel();
+App.Entity.facilities.brothel = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.brothel,
+	{
+		assignee: new App.Entity.Facilities.BrothelJob()
+	},
+	new App.Entity.Facilities.MadamJob()
+);
diff --git a/src/facilities/cellblock/cellblockFramework.js b/src/facilities/cellblock/cellblockFramework.js
index e450e28c4d72c664854511d01749b5f36e4b837d..12bdccfdd759a4a4c7b06e0048340e29ba14228c 100644
--- a/src/facilities/cellblock/cellblockFramework.js
+++ b/src/facilities/cellblock/cellblockFramework.js
@@ -1,33 +1,38 @@
 App.Data.Facilities.cellblock = {
 	baseName: "cellblock",
 	genericName: null,
-	assignee: {
-		position: "",
-		assignment: "serve in the master suite",
-	},
-	penthouse: {
-		position: "Confinement",
-		assignment: "stay confined",
+	jobs: {
+		assignee: {
+			position: "confinee",
+			assignment: "be confined in the cellblock",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		},
 	},
+	defaultJob: "assignee",
 	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"
-	}
-}
+		skill: "wardeness",
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: true,
+		shouldHear: true,
+		shouldTalk: false,
+		requiredDevotion: 51
 
-App.Entity.Facilities.Cellblock = class extends App.Entity.Facilities.Facility {
-	constructor() {
-		super(App.Data.Facilities.cellblock);
 	}
+}
 
+App.Entity.Facilities.CellblockJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
+	canEmploy(slave) {
+		let r = super.canEmploy(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`);
@@ -37,4 +42,9 @@ App.Entity.Facilities.Cellblock = class extends App.Entity.Facilities.Facility {
 	}
 }
 
-App.Entity.facilities.cellblock = new App.Entity.Facilities.Cellblock();
+App.Entity.facilities.cellblock = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.cellblock,
+	{
+		assignee: new App.Entity.Facilities.CellblockJob()
+	}
+);
diff --git a/src/facilities/clinic/clinicFramework.js b/src/facilities/clinic/clinicFramework.js
index 5b16937d91460ba6f43d98527205e28008231d9e..d60fe07338cc205e8be9287a204beba4da83fcad 100644
--- a/src/facilities/clinic/clinicFramework.js
+++ b/src/facilities/clinic/clinicFramework.js
@@ -1,36 +1,43 @@
 App.Data.Facilities.clinic = {
 	baseName: "clinic",
 	genericName: null,
-	assignee: {
-		position: "patient",
-		assignment: "get treatment in the clinic",
+	jobs: {
+		patient: {
+			position: "patient",
+			assignment: "get treatment in the clinic",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		}
 	},
-	penthouse: null,
+	defaultJob: "patient",
 	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"
+		skill: "nurse",
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: true,
+		shouldHear: false,
+		shouldTalk: false,
+		requiredDevotion: 51
 	}
 }
 
-App.Entity.Facilities.Clinic = class extends App.Entity.Facilities.Facility {
-	constructor() {
-		super(App.Data.Facilities.clinic);
-	}
-
+App.Entity.Facilities.ClinicPatientJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
 		const V = State.variables;
 
 		if ((slave.health >= 20) &&
-			(V.Nurse === 0 || ((slave.chem <= 15 || this.upgrade("Filters") !== 1) &&
+			(V.Nurse === 0 || ((slave.chem <= 15 || this.facility.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)))) {
+				(slave.pregKnown !== 1 || (this.facility.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`);
 		}
 
@@ -38,4 +45,9 @@ App.Entity.Facilities.Clinic = class extends App.Entity.Facilities.Facility {
 	}
 }
 
-App.Entity.facilities.clinic = new App.Entity.Facilities.Clinic();
+App.Entity.facilities.clinic = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.clinic,
+	{
+		patient: new App.Entity.Facilities.ClinicPatientJob()
+	}
+);
diff --git a/src/facilities/club/clubFramework.js b/src/facilities/club/clubFramework.js
index 481dcc5d79281ddb4f138d1949690c14e105736b..2058c7ad571a5756dd8a75c46cac225dbac970c5 100644
--- a/src/facilities/club/clubFramework.js
+++ b/src/facilities/club/clubFramework.js
@@ -1,42 +1,62 @@
 App.Data.Facilities.club = {
 	baseName: "club",
 	genericName: null,
-	assignee: {
-		position: "",
-		assignment: "serve in the club",
-	},
-	penthouse: {
-		position: "Public Servant ",
-		assignment: "serve the public",
+	jobs: {
+		slut: {
+			position: "Slut",
+			assignment: "serve in the club",
+			publicSexUse: true,
+			fuckdollAccepted: false
+		},
 	},
+	defaultJob: "slut",
 	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"
+		skill: "DJ",
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: false,
+		shouldHear: true,
+		shouldTalk: true,
+		requiredDevotion: 51
 	}
 }
 
-App.Entity.Facilities.Club = class extends App.Entity.Facilities.SexWorkFacility {
-	constructor() {
-		super(App.Data.Facilities.club, true, false);
-	}
-
+App.Entity.Facilities.ClubSlutJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
+	canEmploy(slave) {
+		let r = super.canEmploy(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));
+		// TODO: consider moving this to App.Entity.Facilities.SexJob
+		if (!App.Entity.Facilities.Job._isBrokenEnough(slave, 51, -50, -20, -50, 50)) {
+			r.push(App.Entity.Facilities.Job._stdBreakageMessage(slave));
 		}
 
 		return r;
 	}
 }
 
-App.Entity.facilities.club = new App.Entity.Facilities.Club();
+App.Entity.Facilities.ClubDJJob = class extends App.Entity.Facilities.ManagingJob {
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
+		if (slave.intelligence + slave.intelligenceImplant < -50) {
+			r.push(`${slave.slaveName} must be more intellegent or educated.`);
+		}
+		return r;
+	}
+}
+
+App.Entity.facilities.club = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.club,
+	{
+		slut: new App.Entity.Facilities.ClubSlutJob()
+	},
+	new App.Entity.Facilities.ClubDJJob()
+);
diff --git a/src/facilities/dairy/dairyFramework.js b/src/facilities/dairy/dairyFramework.js
index dfb092a78774f62c95120a18e8517f471850fd20..b072f45d32c32e774ccdc1f22d889f4d0b8e0aa5 100644
--- a/src/facilities/dairy/dairyFramework.js
+++ b/src/facilities/dairy/dairyFramework.js
@@ -1,39 +1,38 @@
 App.Data.Facilities.dairy = {
 	baseName: "dairy",
 	genericName: null,
-	assignee: {
-		position: "cow",
-		assignment: "work in the dairy",
-	},
-	penthouse: {
-		position: "Milked",
-		assignment: "get milked",
+	jobs: {
+		cow: {
+			position: "cow",
+			assignment: "work in the dairy",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		}
 	},
+	defaultJob: "cow",
 	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"
+		skill: "milkmaid",
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: true,
+		shouldHear: true,
+		shouldTalk: false,
+		requiredDevotion: 21
 	}
 }
 
-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;
-	}
-
+App.Entity.Facilities.DairyCowJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
+
 		const V = State.variables;
 
 		if ((slave.indentureRestrictions > 0) && (V.dairyRestraintsSetting > 1)) {
@@ -49,14 +48,14 @@ App.Entity.Facilities.Dairy = class extends App.Entity.Facilities.Facility {
 			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.amp !== 1) && (this.facility.option("RestraintsUpgrade") !== 1) &&
+			!App.Entity.Facilities.Job._isBrokenEnough(slave, 20, -50, -20, -50)) {
+			r.push(`${slave.slaveName} must be obedient in order to be milked at ${this.facility.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`);
+				r.push(`${slave.slaveName} is not lactating ` + ((V.seeDicks > 0) ? 'or producing semen ' : '') + `and ${this.facility.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');
 			}
@@ -68,18 +67,20 @@ App.Entity.Facilities.Dairy = class extends App.Entity.Facilities.Facility {
 
 		return r;
 	}
+}
 
-	/**
-	 * @param {App.Entity.SlaveState} slave
-	 * @returns {string[]}
-	 */
-	slaveCanWorkFromPenthouse(slave) {
-		let r = super.slaveCanWorkFromPenthouse(slave);
+App.Entity.Facilities.Dairy = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.dairy,
+			{
+			cow: new App.Entity.Facilities.DairyCowJob()
+		});
+	}
 
-		if ((slave.lactation <= 0) && (slave.balls <= 0)) {
-			r.push(`${slave.slaveName} is not lactating` + ((State.variables.seeDicks > 0) ? ' or producing semen' : ''));
-		}
-		return r;
+	get hasFreeSpace() {
+		const V = State.variables;
+		const _dairySeed = V.bioreactorsXY + V.bioreactorsXX + V.bioreactorsHerm + V.bioreactorsBarren;
+		return this.capacity > this.hostedSlaves + _dairySeed;
 	}
 }
 
diff --git a/src/facilities/farmyard/farmyardFramework.js b/src/facilities/farmyard/farmyardFramework.js
index 24f71a6edbacb504915a90172a2a15179fd565a4..83da5ddab33c58e048a472f2ebc1753772fd99d4 100644
--- a/src/facilities/farmyard/farmyardFramework.js
+++ b/src/facilities/farmyard/farmyardFramework.js
@@ -1,23 +1,30 @@
 App.Data.Facilities.farmyard = {
 	baseName: "farmyard",
 	genericName: null,
-	assignee: {
-		position: "",
-		assignment: "work as a farmhand",
+	jobs: {
+		farmhand: {
+			position: "farmhand",
+			assignment: "work as a farmhand",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		}
 	},
-	penthouse: null,
+	defaultJob: "farmhand",
 	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"
+		skill: "farmer",
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: true,
+		shouldHear: true,
+		shouldTalk: false,
+		requiredDevotion: 51
 	}
 }
 
-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();
+App.Entity.facilities.farmyard = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.farmyard
+);
diff --git a/src/facilities/headGirlSuite/headGirlSuiteFramework.js b/src/facilities/headGirlSuite/headGirlSuiteFramework.js
new file mode 100644
index 0000000000000000000000000000000000000000..bcf4c1b873bb02a9b772570c04969c0aa43a2385
--- /dev/null
+++ b/src/facilities/headGirlSuite/headGirlSuiteFramework.js
@@ -0,0 +1,18 @@
+App.Data.Facilities.headGirlSuite = {
+	baseName: "HGSuite",
+	genericName: null,
+	jobs: {
+		HGToy: {
+			position: "Head Girl's toy",
+			assignment: "live with your Head Girl",
+			publicSexUse: true,
+			fuckdollAccepted: false
+		}
+	},
+	defaultJob: "HGToy",
+	manager: null
+}
+
+App.Entity.facilities.headGirlSuite = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.headGirlSuite
+);
diff --git a/src/facilities/masterSuite/masterSuiteFramework.js b/src/facilities/masterSuite/masterSuiteFramework.js
index 4ca615876207d3faffd5c4fbc7c9421c3c8291e7..53440471958d691785efd671d3b3c6ad6cc62ab6 100644
--- a/src/facilities/masterSuite/masterSuiteFramework.js
+++ b/src/facilities/masterSuite/masterSuiteFramework.js
@@ -1,34 +1,38 @@
 App.Data.Facilities.masterSuite = {
 	baseName: "masterSuite",
 	genericName: "Master Suite",
-	assignee: {
-		position: "fucktoy",
-		assignment: "serve in the master suite",
-	},
-	penthouse: {
-		position: "Fucktoy",
-		assignment: "please you",
+	jobs: {
+		fucktoy: {
+			position: "fucktoy",
+			assignment: "serve in the master suite",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		}
 	},
+	defaultJob: "fucktoy",
 	manager: {
 		position: "concubine",
 		assignment: "be your Concubine",
 		careers: [],
-		skill: null
+		skill: null,
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: false,
+		shouldSee: false,
+		shouldHear: false,
+		shouldTalk: false,
+		requiredDevotion: 51
 	}
 }
 
-App.Entity.Facilities.MasterSuite = class extends App.Entity.Facilities.Facility {
-	constructor() {
-		super(App.Data.Facilities.masterSuite);
-	}
-
+App.Entity.Facilities.MasterSuiteGuckToyJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @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)) {
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
+		if (!App.Entity.Facilities.Job._isBrokenEnough(slave, 20, -51, -21, -50)) {
 			r.push(`${slave.slaveName} is not sufficiently broken for the master suite`);
 		}
 
@@ -36,4 +40,20 @@ App.Entity.Facilities.MasterSuite = class extends App.Entity.Facilities.Facility
 	}
 }
 
-App.Entity.facilities.masterSuite = new App.Entity.Facilities.MasterSuite();
+App.Entity.Facilities.ConcubineJob = class extends App.Entity.Facilities.ManagingJob {
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
+		if (slave.amp === 1) {
+			r.push(`${slave.slaveName} can't be your concubine because ${slave.object} is an amputee.`)
+		}
+		return r;
+	}
+}
+
+App.Entity.facilities.masterSuite = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.masterSuite,
+	{
+		fucktoy: new App.Entity.Facilities.MasterSuiteGuckToyJob()
+	},
+	new App.Entity.Facilities.ConcubineJob()
+);
diff --git a/src/facilities/nursery/nurseryFramework.js b/src/facilities/nursery/nurseryFramework.js
index 2efb72dda025a630fb2900fe9433349a7ce0bdc2..e13ffb6c2aa80e61afda00b09505a532fce00879 100644
--- a/src/facilities/nursery/nurseryFramework.js
+++ b/src/facilities/nursery/nurseryFramework.js
@@ -1,37 +1,49 @@
 App.Data.Facilities.nursery = {
 	baseName: "nursery",
 	genericName: null,
-	assignee: {
-		position: "nanny",
-		assignment: "work as a nanny"
+	jobs: {
+		nanny: {
+			position: "nanny",
+			assignment: "work as a nanny",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		}
 	},
-	penthouse: null,
+	defaultJob: "nanny",
 	manager: {
 		position: "matron",
 		assignment: "be the Matron",
 		careers: ["a babysitter", "a nanny", "a practitioner", "a wet nurse", "an au pair"],
-		skill: "matron"
+		skill: "matron",
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: false,
+		shouldHear: true,
+		shouldTalk: false,
+		requiredDevotion: 51
 	}
 }
 
-App.Entity.Facilities.Nursery = class extends App.Entity.Facilities.Facility {
-	constructor() {
-		super(App.Data.Facilities.nursery);
-	}
-
+App.Entity.Facilities.NurseryNannyJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
 
-		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, -20, -50, 20, -21)) {
-			r.push(App.Entity.Facilities.Facility._stdBreakageMessage(slave));
+		if (!App.Entity.Facilities.Job._isBrokenEnough(slave, -20, -50, 20, -21)) {
+			r.push(App.Entity.Facilities.Job._stdBreakageMessage(slave));
 		}
 
 		return r;
 	}
 }
 
-App.Entity.facilities.nursery = new App.Entity.Facilities.Nursery();
+App.Entity.facilities.nursery = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.nursery,
+	{
+		nanny: new App.Entity.Facilities.NurseryNannyJob()
+	}
+);
diff --git a/src/facilities/penthouse/penthouseFramework.js b/src/facilities/penthouse/penthouseFramework.js
new file mode 100644
index 0000000000000000000000000000000000000000..f0df090cebeabc1b850b79f1752d496916bd1524
--- /dev/null
+++ b/src/facilities/penthouse/penthouseFramework.js
@@ -0,0 +1,169 @@
+
+App.Data.Facilities.penthouse = {
+	baseName: "",
+	genericName: "Penthouse",
+	jobs: {
+		rest: {
+			position: "Rest",
+			assignment: "rest",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		},
+		fucktoy: {
+			position: "Fucktoy",
+			assignment: "please you",
+			publicSexUse: false,
+			fuckdollAccepted: true
+		},
+		classes: {
+			position: "Classes",
+			assignment: "take classes",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		},
+		houseServant: {
+			position: "House Servant",
+			assignment: "be a servant",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		},
+		whore: {
+			position: "Whore",
+			assignment: "whore",
+			publicSexUse: true,
+			fuckdollAccepted: false
+		},
+		publicServant: {
+			position: "Public Servant",
+			assignment: "serve the public",
+			publicSexUse: true,
+			fuckdollAccepted: false
+		},
+		subordinateSlave: {
+			position: "Subordinate slave",
+			assignment: "be a subordinate slave",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		},
+		cow: {
+			position: "Milked",
+			assignment: "get milked",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		},
+		gloryhole: {
+			position: "Gloryhole",
+			assignment: "work a glory hole",
+			publicSexUse: false,
+			fuckdollAccepted: true
+		},
+		confinement: {
+			position: "Confinement",
+			assignment: "stay confined",
+			publicSexUse: false,
+			fuckdollAccepted: true
+		}
+	},
+	defaultJob: "rest",
+	manager: {
+		position: "Head Girl",
+		assignment: "be your Head Girl",
+		careers: ["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"],
+		skill: "headGirl",
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: true,
+		shouldHear: true,
+		shouldTalk: true,
+		requiredDevotion: 51
+	}
+}
+
+App.Entity.Facilities.PenthouseJob = class extends App.Entity.Facilities.Job {
+
+}
+
+App.Entity.Facilities.PenthouseJobs = {
+	Classes: class extends App.Entity.Facilities.PenthouseJob {
+		canEmploy(slave) {
+			let r = super.canEmploy(slave);
+			if (slave.intelligenceImplant >= 15) {
+				r.push(`${slave.slaveName} already has a basic education`);
+			}
+			if (!App.Entity.Facilities.Job._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;
+		}
+	},
+	HouseServant: class extends App.Entity.Facilities.PenthouseJob {
+		canEmploy(slave) {
+			let r = super.canEmploy(slave);
+
+			if (!App.Entity.Facilities.Job._isBrokenEnough(slave, -20, -50, -19, -51)) {
+				r.push(App.Entity.Facilities.Job._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;
+		}
+
+	},
+
+	SubordinateSlave: class extends App.Entity.Facilities.PenthouseJob {
+		canEmploy(slave) {
+			let r = super.canEmploy(slave);
+			if (!App.Entity.Facilities.Job._isBrokenEnough(slave, -20, -50, -19, -51)) {
+				r.push(App.Entity.Facilities.Job._stdBreakageMessage(slave));
+			}
+			return r;
+		}
+	},
+	Cow: class extends App.Entity.Facilities.PenthouseJob {
+		canEmploy(slave) {
+			let r = super.canEmploy(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.Penthouse = class extends App.Entity.Facilities.Facility {
+	constructor() {
+
+		super(App.Data.Facilities.penthouse, {
+			classes: new App.Entity.Facilities.PenthouseJobs.Classes(),
+			houseServant: new App.Entity.Facilities.PenthouseJobs.HouseServant(),
+			subordinateSlave: new App.Entity.Facilities.PenthouseJobs.SubordinateSlave(),
+			cow: new App.Entity.Facilities.PenthouseJobs.Cow()
+		});
+	}
+
+	/** Facility slave capacity
+	* @returns {number} */
+	get capacity() {
+		return State.variables.dormitory;
+	}
+
+	/** Number of already hosted slaves
+	 * @returns {number} */
+	get hostedSlaves() {
+		return State.variables.dormitoryPopulation;
+	}
+}
+
+App.Entity.facilities.penthouse = new App.Entity.Facilities.Penthouse();
diff --git a/src/facilities/pit/pitFramework.js b/src/facilities/pit/pitFramework.js
index 9b4369c0554b95abad9b96c4bc2715631348bfd9..b77697e3862d278da448f3ba490a64d01903db33 100644
--- a/src/facilities/pit/pitFramework.js
+++ b/src/facilities/pit/pitFramework.js
@@ -1,36 +1,53 @@
 App.Data.Facilities.pit = {
 	baseName: "pit",
 	genericName: null,
-	assignee: {
-		position: "fighter",
-		assignment: ""
+	jobs: {
+		fighter: {
+			position: "fighter",
+			assignment: "",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		}
 	},
-	penthouse: null,
+	defaultJob: "fighter",
 	manager: null
 }
 
-App.Entity.Facilities.Pit = class extends App.Entity.Facilities.Facility {
-	constructor() {
-		super(App.Data.Facilities.pit);
-	}
-
+App.Entity.Facilities.PitFighterJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
+	canEmploy(slave) {
+		let r = super.canEmploy(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)) {
+		if ((slave.indentureRestrictions > 0) && (this.facility.option("Lethal") === 1)) {
 			r.push(`${slave.slaveName}'s indenture forbids lethal fights.`);
 		}
 		return r;
 	}
+
+	isEmployed(slave) {
+		return State.variables.fighterIDs.includes(slave.ID);
+	}
+}
+
+App.Entity.Facilities.Pit = class extends App.Entity.Facilities.Facility {
+	constructor() {
+		super(App.Data.Facilities.pit,
+			{
+				fighter: new App.Entity.Facilities.PitFighterJob()
+			});
+	}
+
+	get hostedSlaves() {
+		return 0; // does not host anyone
+	}
 }
 
 App.Entity.facilities.pit = new App.Entity.Facilities.Pit();
diff --git a/src/facilities/schoolroom/schoolroomFramework.js b/src/facilities/schoolroom/schoolroomFramework.js
index 578612c218e1e3144ae2122798fbb4992f69871e..4aaf9dccb011825f21d31eacdfb04032014d4139 100644
--- a/src/facilities/schoolroom/schoolroomFramework.js
+++ b/src/facilities/schoolroom/schoolroomFramework.js
@@ -1,59 +1,44 @@
 App.Data.Facilities.schoolroom = {
 	baseName: "schoolroom",
 	genericName: null,
-	assignee: {
-		position: "",
-		assignment: "learn in the schoolroom",
-	},
-	penthouse: {
-		position: "Classes",
-		assignment: "take classes",
+	jobs: {
+		student: {
+			position: "",
+			assignment: "learn in the schoolroom",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		}
 	},
+	defaultJob: "student",
 	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"
+		skill: "teacher",
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: false,
+		shouldSee: true,
+		shouldHear: true,
+		shouldTalk: true,
+		requiredDevotion: 51
 	}
 }
 
-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;
-	}
-
+App.Entity.Facilities.SchoolroomStudentJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
 
-		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, -20, -50, -20, -51)) {
+		if (!App.Entity.Facilities.Job._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) &&
+		const maxSkill = 10 + this.facility.upgrade("Skills") * 20; // maximal skill value the scholl can teach
+		if ((slave.intelligenceImplant >= 30) && (slave.voice === 0 || slave.accent + this.facility.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`);
@@ -63,4 +48,9 @@ App.Entity.Facilities.Schoolroom = class extends App.Entity.Facilities.Facility
 	}
 }
 
-App.Entity.facilities.schoolrom = new App.Entity.Facilities.Schoolroom();
+App.Entity.facilities.schoolrom = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.schoolroom,
+	{
+		student: new App.Entity.Facilities.SchoolroomStudentJob()
+	}
+);
diff --git a/src/facilities/servantsQuarters/servantsQuartersFramework.js b/src/facilities/servantsQuarters/servantsQuartersFramework.js
index 03a556170703c7a845d5734a5c070106125d633b..a0a4354d5a9ff552c1ccb2d28719843be23eb19c 100644
--- a/src/facilities/servantsQuarters/servantsQuartersFramework.js
+++ b/src/facilities/servantsQuarters/servantsQuartersFramework.js
@@ -1,36 +1,40 @@
 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",
+	jobs: {
+		servant: {
+			position: "servant",
+			assignment: "work as a servant",
+			publicSexUse: false,
+			fuckdollAccepted: false
+		}
 	},
+	defaultJob: "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"
+		skill: "stewardess",
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: true,
+		shouldHear: true,
+		shouldTalk: false,
+		requiredDevotion: 51
 	}
 }
 
-App.Entity.Facilities.ServantsQuarters = class extends App.Entity.Facilities.Facility {
-	constructor() {
-		super(App.Data.Facilities.servantsQuaters);
-	}
-
+App.Entity.Facilities.ServantsQuartersServantJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
 
-		if (!App.Entity.Facilities.Facility._isBrokenEnough(slave, -20, -50, 20, -21)) {
-			r.push(App.Entity.Facilities.Facility._stdBreakageMessage(slave));
+		if (!App.Entity.Facilities.Job._isBrokenEnough(slave, -20, -50, 20, -21)) {
+			r.push(App.Entity.Facilities.Job._stdBreakageMessage(slave));
 		}
 		if (!window.canWalk(slave)) {
 			r.push(`${slave.slaveName} can't work as a servant because ${slave.pronoun} can't walk`);
@@ -40,27 +44,26 @@ App.Entity.Facilities.ServantsQuarters = class extends App.Entity.Facilities.Fac
 		}
 		return r;
 	}
+}
 
+App.Entity.Facilities.ServantsQuartersStewardessJob = class extends App.Entity.Facilities.ManagingJob {
 	/**
 	 * @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.pronoun} can't walk`);
+	canEmploy(slave) {
+		let r = super.canEmploy(slave);
+		if (slave.intelligence + slave.intelligenceImplant < -50) {
+			r.push(`${slave.slaveName} must be more intellegent or educated.`);
 		}
-		if (!canSee(slave)) {
-			r.push(`${slave.slaveName} can't work as a servant because ${slave.pronoun} is blind`);
-		}
-
 		return r;
 	}
 }
 
-App.Entity.facilities.servantsQuarters = new App.Entity.Facilities.ServantsQuarters();
+App.Entity.facilities.servantsQuarters = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.servantsQuaters,
+	{
+		servant: new App.Entity.Facilities.ServantsQuartersServantJob()
+	},
+	new App.Entity.Facilities.ServantsQuartersStewardessJob()
+);
diff --git a/src/facilities/spa/spaFramework.js b/src/facilities/spa/spaFramework.js
index 77c04f998064812c0b014a143943461d276e9ac6..7af26bf5466dae1c371b7450f9ae17b305cfd8c7 100644
--- a/src/facilities/spa/spaFramework.js
+++ b/src/facilities/spa/spaFramework.js
@@ -1,39 +1,37 @@
 App.Data.Facilities.spa = {
 	baseName: "spa",
 	genericName: null,
-	assignee: {
-		position: "",
-		assignment: "rest in the spa"
-	},
-	penthouse: {
-		position: "Rest",
-		assignment: "rest",
+	jobs: {
+		assignee: {
+			position: "",
+			assignment: "rest in the spa",
+			publicSexUse: false,
+			fuckdollAccepted: false,
+		}
 	},
+	defaultJob: "assignee",
 	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"
+		skill: "attendant",
+		publicSexUse: false,
+		fuckdollAccepted: false,
+		shouldWalk: true,
+		shouldSee: false,
+		shouldHear: true,
+		shouldTalk: false,
+		requiredDevotion: 51
 	}
 }
 
-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>>`;
-	}
-
+App.Entity.Facilities.SpaAssigneeJob = class extends App.Entity.Facilities.FacilitySingleJob {
 	/**
 	 * @param {App.Entity.SlaveState} slave
 	 * @returns {string[]}
 	 */
-	canHostSlave(slave) {
-		let r = super.canHostSlave(slave);
+	canEmploy(slave) {
+		let r = super.canEmploy(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`);
@@ -43,4 +41,9 @@ App.Entity.Facilities.Spa = class extends App.Entity.Facilities.Facility {
 	}
 }
 
-App.Entity.facilities.spa = new App.Entity.Facilities.Spa();
+App.Entity.facilities.spa = new App.Entity.Facilities.Facility(
+	App.Data.Facilities.spa,
+	{
+		assignee: new App.Entity.Facilities.SpaAssigneeJob()
+	}
+);
diff --git a/src/init/setupVars.tw b/src/init/setupVars.tw
index 303e439ee5dba5a8506619c4b361f3f6b691216e..7d204c0a1b55426d448a8d7bf478a481db4298d0 100644
--- a/src/init/setupVars.tw
+++ b/src/init/setupVars.tw
@@ -317,13 +317,13 @@ equine: {type: "equine", normalOvaMin:1, normalOvaMax: 1, normalBirth: 48, minLi
 
 <<set setup.whoreCareers = ["a child prostitute", "a criminal", "a cum dump", "a Futanari Sister", "a juvenile delinquent", "a mail-order bride", "a meat toilet", "a mistress", "a model", "a pageant star", "a pirate", "a porn star", "a prostitute", "a reality show star", "a saleswoman", "a serial divorcee", "a stripper", "a trophy wife", "an escort", "an exotic dancer"]>>
 
-<<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.HGCareers = App.Data.Facilities.penthouse.manager.careers>>
 
 <<set setup.madamCareers = App.Data.Facilities.brothel.manager.careers>>
 
 <<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.bodyguardCareers = App.Data.Facilities.armory.manager.careers>>
 
 <<set setup.wardenessCareers = App.Data.Facilities.cellblock.manager.careers>>
 
diff --git a/src/js/assignJS.js b/src/js/assignJS.js
index 17d69c8b0e51c86529454a62f4fe46fba723a38e..459f9e6b22feb352b23cd74d136f4dedbc48c075 100644
--- a/src/js/assignJS.js
+++ b/src/js/assignJS.js
@@ -551,6 +551,7 @@ window.resetJobIDArray = function resetJobIDArray() { /* todo: expand to all ass
 App.UI.jobLinks = function () {
 	"use strict";
 	const facilitiesOrder = [
+		App.Entity.facilities.penthouse,
 		App.Entity.facilities.spa,
 		App.Entity.facilities.clinic,
 		App.Entity.facilities.masterSuite,
@@ -578,50 +579,32 @@ App.UI.jobLinks = function () {
 	 * @returns {string}
 	 */
 	function assignmentLinks(index, passage, callback) {
-		let res = [];
-		/** @type {App.Entity.SlaveState} */
-		const slave = index >= 0 ? State.variables.slaves[index] : State.variables.activeSlave;
+		let penthouseJobs = App.Entity.facilities.penthouse.assignmentLinks(index, undefined, passage, callback);
+		const slave = App.Utils.slaveByIndex(index);
 
-		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>>`);
+				penthouseJobs.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"]));
+			penthouseJobs.push(App.UI.disabledLink(`Let ${slave.object} choose`, ["Fuckdolls can't choose their job"]));
 		}
 
-		return res.join("&thinsp;|&thinsp;");
+		return penthouseJobs.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`]));
-		}
+		const slave = App.Utils.slaveByIndex(index);
 
 		for (const f of facilitiesOrder) {
 			if (!f.established) continue;
-
 			const rejects = f.canHostSlave(slave);
 			if (rejects.length === 0) {
-				transfers.push(f.transferLink(index));
+				transfers.push(f.transferLink(index, undefined, passage()));
 			} else {
 				transfers.push(App.UI.disabledLink(f.genericName, rejects));
 			}
diff --git a/src/js/slaveSummaryWidgets.js b/src/js/slaveSummaryWidgets.js
index 7ddcc60993eda3a6e27a939cf3d63952919b4629..f3d9bce85ba95997a1c56e95d4526b988415b9da 100644
--- a/src/js/slaveSummaryWidgets.js
+++ b/src/js/slaveSummaryWidgets.js
@@ -5068,6 +5068,7 @@ App.UI.slaveSummaryList = function (passageName) {
 		"Club": App.Entity.facilities.club,
 		"Dairy": App.Entity.facilities.dairy,
 		"Farmyard": App.Entity.facilities.farmyard,
+		"Head Girl Suite": App.Entity.facilities.headGirlSuite,
 		"Master Suite": App.Entity.facilities.masterSuite,
 		"Nursery": App.Entity.facilities.nursery,
 		"Pit": App.Entity.facilities.pit,
@@ -5076,53 +5077,44 @@ App.UI.slaveSummaryList = function (passageName) {
 		"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,
-	};
+	function makeSelectionPassageInfo(f, wp) {
+		return {
+			facility: f,
+			passage: wp
+		};
+	}
 
-	// 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"
+	const selectionPassageToFacilityMap = {
+		"HG Select": makeSelectionPassageInfo(App.Entity.facilities.penthouse, "HG Workaround"),
+		"BG Select": makeSelectionPassageInfo(App.Entity.facilities.armory, "Bodyguard Workaround"),
+		"Attendant Select": makeSelectionPassageInfo(App.Entity.facilities.spa, "Attendant Workaround"),
+		"Concubine Select":  makeSelectionPassageInfo(App.Entity.facilities.masterSuite, "Concubine Workaround"),
+		"Matron Select": makeSelectionPassageInfo(App.Entity.facilities.nursery, "Matron Workaround"),
+		"Madam Select": makeSelectionPassageInfo(App.Entity.facilities.brothel, "Madam Workaround"),
+		"Milkmaid Select": makeSelectionPassageInfo(App.Entity.facilities.dairy,  "Milkmaid Workaround"),
+		"Nurse Select": makeSelectionPassageInfo(App.Entity.facilities.clinic, "Nurse Workaround"),
+		"DJ Select": makeSelectionPassageInfo(App.Entity.facilities.club, "DJ Workaround"),
+		"Farmer Select": makeSelectionPassageInfo(App.Entity.facilities.farmyard, "Farmer Workaround"),
+		"Stewardess Select": makeSelectionPassageInfo(App.Entity.facilities.servantsQuarters, "Stewardess Workaround"),
+		"Schoolteacher Select": makeSelectionPassageInfo(App.Entity.facilities.schoolrom, "Schoolteacher Workaround"),
+		"Wardeness Select": makeSelectionPassageInfo(App.Entity.facilities.cellblock, "Wardeness Workaround"),
+		"Agent Select": makeSelectionPassageInfo(null, "Agent Workaround"),
+		"Recruiter Select": makeSelectionPassageInfo(null, "Recruiter 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];
+	/** @type {{facility: App.Entity.Facilities.Facility, passage: string}} */
+	const slaveSelect = passageFacility === undefined ? selectionPassageToFacilityMap[passageName] : undefined;
 
 	for (const _ssi of _filteredSlaveIdxs) {
 		let _Slave = slaves[_ssi];
 
 		if (passageName === "Main" && V.useSlaveSummaryTabs === 1) {
 			if (tabName === "overview") {
-				if (V.showOneSlave === "Head Girl" && _Slave.assignment !== "be your Head Girl") continue;
+				if (V.showOneSlave === "Head Girl" && _Slave.assignment !== App.Data.Facilities.penthouse.manager.assignment) continue;
 				if (V.showOneSlave === "recruit girls" && _Slave.assignment !== "recruit girls") continue;
-				if (V.showOneSlave === "guard you" && _Slave.assignment !== "guard you") continue;
+				if (V.showOneSlave === "guard you" && _Slave.assignment !== App.Data.Facilities.armory.manager.assignment) continue;
 			} else {
 				if (tabName === "resting") {
 					if (_Slave.assignment !== "rest") continue;
@@ -5161,9 +5153,9 @@ App.UI.slaveSummaryList = function (passageName) {
 				if ((V.seeImages === 1) && (V.seeSummaryImages === 1)) res.push(slaveImage(_Slave));
 				res.push(`[[${_slaveName}|Slave Interact][$activeSlave = $slaves[${_ssi}]]]`);
 			}
-		} else if (selectionWorkaround !== undefined) {
+		} else if (slaveSelect !== undefined && slaveSelect.passage !== "") {
 			res.push(dividerAndImage(_Slave));
-			res.push(`[[${_slaveName}|${selectionWorkaround}][$i = ${_ssi}]]`);
+			res.push(`[[${_slaveName}|${slaveSelect.passage}][$i = ${_ssi}]]`);
 		}
 		switch (passageName) {
 			case "Main":
@@ -5174,9 +5166,9 @@ App.UI.slaveSummaryList = function (passageName) {
 					_Slave = slaves[_ssi]; /* restore devotion value so repeatedly changing clothes isn't an exploit */
 				}
 				res.push(dividerAndImage(_Slave));
-				if ("be your Head Girl" === _Slave.assignment) res.push('<strong>@@.lightcoral;HG@@</strong> ');
+				if (App.Data.Facilities.penthouse.manager.assignment === _Slave.assignment) res.push('<strong>@@.lightcoral;HG@@</strong> ');
 				else if ("recruit girls" === _Slave.assignment) res.push('<strong>@@.lightcoral;RC@@</strong> ');
-				else if ("guard you" === _Slave.assignment) res.push('<strong>@@.lightcoral;BG@@</strong> ');
+				else if (App.Data.Facilities.armory.manager.assignment === _Slave.assignment) res.push('<strong>@@.lightcoral;BG@@</strong> ');
 
 				if (Array.isArray(V.personalAttention) && V.personalAttention.findIndex(s => s.ID === _Slave.ID) !== -1) {
 					res.push('<strong>@@.lightcoral; PA@@</strong> ');
@@ -5188,15 +5180,6 @@ App.UI.slaveSummaryList = function (passageName) {
 				res.push(dividerAndImage(_Slave));
 				res.push(`<<link "${_slaveName}">> <<run App.UI.selectSlaveForPersonalAttention(${_Slave.ID})>><</link>>`);
 				break;
-			case "Head Girl Suite":
-				if (V.Flag === 0) {
-					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 "Subordinate Targeting":
 				res.push(dividerAndImage(_Slave));
 				res.push(`[[${_slaveName}|Subordinate Targeting][$activeSlave.subTarget = $slaves[${_ssi}].ID]]`);
@@ -5298,8 +5281,18 @@ App.UI.slaveSummaryList = function (passageName) {
 		V.slaves[_ssi] = _Slave;
 		res.push('</div>');
 
-		if (managerSelectFacility !== undefined) {
-			if (managerSelectFacility.slaveHasExperiancedForManagerPosition(_Slave)) {
+		if (passageFacility !== undefined) {
+			res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
+			if (V.Flag === 0) {
+				res.push(`<<link "Send ${_Slave.object} to ${passageFacility.name}" "Assign">><<set $i = ${_ssi}>><</link>>`);
+			} else if (V.Flag === 1) {
+				res.push(`<<link "Remove ${_Slave.object} from ${passageFacility.name}" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
+			} else if (passageFacility.desc.manager !== null){
+				const managerCapName = capFirstChar(passageFacility.desc.manager.position);
+				res.push(`[[Change or remove ${managerCapName}|${managerCapName} Select]]`);
+			}
+		} else if (slaveSelect !== undefined) {
+			if (slaveSelect.facility.manager.slaveHasExperience(_Slave)) {
 				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
 				res.push('@@.lime;Has applicable career experience.@@');
 			}
@@ -5307,153 +5300,12 @@ App.UI.slaveSummaryList = function (passageName) {
 		switch (passageName) {
 			case "Main":
 				continue;
-			case "HG Select":
-				if (setup.HGCareers.includes(_Slave.career) || (_Slave.skill.headGirl >= 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 "Head Girl Suite":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`[[Send her to live with your Head Girl|Assign][$i = ${_ssi}]]`);
-				} else {
-					res.push(`[[Bring her out of the Head Girl's suite|Retrieve][$i = ${_ssi}]]`);
-				}
-				break;
 			case "Recruiter Select":
 				if (setup.recruiterCareers.includes(_Slave.career) || (_Slave.skill.recruiter >= 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 "BG Select":
-				if (setup.bodyguardCareers.includes(_Slave.career) || (_Slave.skill.bodyguard >= 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 "Spa":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Send ${_Slave.object} to $spaName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Remove ${_Slave.object} from ${V.spaName}" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove Attendant|Attendant Select]]');
-				}
-				break;
-			case "Nursery":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Send ${_Slave.object} to $nurseryName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Remove ${_Slave.object} from $nurseryName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove Matron|Matron Select]]');
-				}
-				break;
-			case "Brothel":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Send ${_Slave.object} to $brothelName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Release ${_Slave.object} from $brothelName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove Madam|Madam Select]]');
-				}
-				break;
-			case "Club":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Send ${_Slave.object} to $clubName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Remove ${_Slave.object} from $clubName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove DJ|DJ Select]]');
-				}
-				break;
-			case "Arcade":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Confine ${_Slave.object} in $arcadeName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push(`<<link "Release ${_Slave.object} from $arcadeName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				}
-				break;
-			case "Clinic":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.clinicUpgradeScanner === 1) {
-					res.push(`@@.cyan;Estimated DNA error value: ${Math.ceil(_Slave.chem / 10)}@@`);
-				}
-				if (V.Flag === 0) {
-					res.push(`<<link "Send ${_Slave.object} to $clinicName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Take ${_Slave.object} out of $clinicName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove Nurse|Nurse Select]]');
-				}
-				break;
-			case "Schoolroom":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Assign ${_Slave.object} to $schoolroomName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Release ${_Slave.object} from $schoolroomName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove Schoolteacher|Schoolteacher Select]]');
-				}
-				break;
-			case "Dairy":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Send ${_Slave.object} to $dairyName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Release ${_Slave.object} from $dairyName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove Milkmaid|Milkmaid Select]]');
-				}
-				break;
-			case "Farmyard":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Send ${_Slave.object} to $farmyardName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Release ${_Slave.object} from $farmyardName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove Farmer|Farmer Select]]');
-				}
-				break;
-			case "Servants' Quarters":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Assign ${_Slave.object} to $servantsQuartersName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Release ${_Slave.object} from $servantsQuartersName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove Stewardess|Stewardess Select]]');
-				}
-				break;
-			case "Master Suite":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Add ${_Slave.object} to $masterSuiteName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Send ${_Slave.object} out of $masterSuiteName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove Concubine|Concubine Select]]');
-				}
-				break;
-			case "Cellblock":
-				res.push(`<br>${ V.seeImages !== 1 || V.seeSummaryImages !== 1 || V.imageChoice === 1}` ? '&nbsp;&nbsp;&nbsp;&nbsp;' : '');
-				if (V.Flag === 0) {
-					res.push(`<<link "Confine ${_Slave.object} in $cellblockName" "Assign">><<set $i = ${_ssi}>><</link>>`);
-				} else if (V.Flag === 1) {
-					res.push(`<<link "Release ${_Slave.object} from $cellblockName" "Retrieve">><<set $i = ${_ssi}>><</link>>`);
-				} else {
-					res.push('[[Change or remove Wardeness|Wardeness Select]]');
-				}
-				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 4d702148361483e3fead571b04b500eb20933180..31adf6b85424cfa1eedf2952f2521802718262f4 100644
--- a/src/js/utilJS.js
+++ b/src/js/utilJS.js
@@ -1715,7 +1715,20 @@ App.UI.disabledLink = function(link, reasons) {
 	return '<span class="textWithTooltip">' + link + tooltips + '</span>';
 }
 
-
+/**
+ * Expresion for SugarCube for referencing a slave by index
+ * @param {number} i slave array index or -1 for activeSlave
+ * @returns {string}
+ */
 App.Utils.slaveRefString = function(i) {
 	return i >= 0 ? `$slaves[${i}]` : '$activeSlave';
 }
+
+/**
+ * Returns slave by index in the slave array, Accepts -1 for the activeSlave
+ * @param {number} i slave array index or -1 for activeSlave
+ * @returns {App.Entity.SlaveState}
+ */
+App.Utils.slaveByIndex = function(i) {
+	return i === -1 ? State.variables.activeSlave : State.variables.slaves[i];
+}