Newer
Older
globalThis.assignJob = function(slave, job) {
const oldJob = slave.assignment;
// handle non-exclusive pseudo-assignments as special cases
if (!V.pit.fighterIDs.includes(slave.ID)) {
V.pit.fighterIDs.push(slave.ID);
}
V.JobIDMap[Job.PIT].add(slave.ID);
} else if (job === Job.LURCHER) {
V.JobIDMap[Job.LURCHER].clear();
V.JobIDMap[Job.LURCHER].add(slave.ID);
const restingAssignment = slave.assignment; // not necessary Job.REST, but the assignment chosen by removeJob() for her case
* this helper makes sure global references global IDs (V.HeadGirlID, V.AttendantID, etc) are set correctly
* @param {string} propName
*/
function uniqueJob(propName) {
if (App.Data.resetOnNGPlus.hasOwnProperty(propName)) {
// TODO remove this branch when all special slaves migrate to IDs
if (V[propName] !== 0 && V[propName].ID !== slave.ID) {
removeJob(V[propName], job, true);
}
V[propName] = slave;
} else {
const specialIDProp = `${propName}ID`;
const prevAssigneeID = V[specialIDProp];
if (prevAssigneeID !== slave.ID) {
removeJob(slaveStateById(prevAssigneeID), job, true);
}
V[specialIDProp] = slave.ID;
}
if (oldJob !== job && V.assignmentRecords[slave.ID] !== job && oldJob !== Job.REST) { // Check that there is a real change happening. Sometimes when you send someone to a classroom or something, this fires twice.
if (oldJob !== Job.CELLBLOCK) { // Due to the way assignJob fires twice on assigning to a building, we have to make sure that we are keeping the original record.
/* use .toLowerCase() to get rid of a few dupe conditions. */
switch (job.toLowerCase()) {
if (slave.clothes !== "a fuckdoll suit") {
slave.clothes = "no clothing";
}
slave.rules.living = LivingRule.SPARE;
switch (V.brothelDecoration) {
case "Degradationist":
case "standard":
slave.rules.living = LivingRule.SPARE;
slave.rules.living = LivingRule.NORMAL;
case Job.CELLBLOCK.toLowerCase():
slave.assignment = Job.CELLBLOCK;
slave.rules.living = LivingRule.NORMAL;
slave.rules.living = LivingRule.SPARE;
switch (V.clinicDecoration) {
case "Repopulation Focus":
case "Eugenics":
case "Gender Radicalist":
case "Gender Fundamentalist":
case "Paternalist":
case "Maturity Preferentialist":
case "Youth Preferentialist":
case "Slimness Enthusiast":
case "Hedonistic":
case "Intellectual Dependency":
case "Petite Admiration":
case "Statuesque Glorification":
case "Neo Imperialist":
slave.rules.living = LivingRule.LUXURIOUS;
case "Roman Revivalist":
case "Aztec Revivalist":
case "Egyptian Revivalist":
case "Arabian Revivalist":
case "Chinese Revivalist":
case "Chattel Religionist":
case "Edo Revivalist":
slave.rules.living = LivingRule.NORMAL;
slave.rules.living = LivingRule.SPARE;
slave.rules.living = LivingRule.NORMAL;
case "Neo Imperialist":
case "Aztec Revivalist":
case "Chinese Revivalist":
case "Chattel Religionist":
case "Edo Revivalist":
case "Arabian Revivalist":
case "Egyptian Revivalist":
case "Supremacist":
case "Subjugationist":
case "Degradationist":
slave.rules.living = LivingRule.SPARE;
slave.rules.living = LivingRule.NORMAL;
case Job.FARMYARD.toLowerCase():
slave.assignment = Job.FARMYARD;
case "Neo Imperialist":
case "Aztec Revivalist":
case "Chinese Revivalist":
case "Chattel Religionist":
case "Edo Revivalist":
case "Arabian Revivalist":
case "Egyptian Revivalist":
case "Supremacist":
case "Subjugationist":
case "Degradationist":
slave.rules.living = LivingRule.SPARE;
slave.rules.living = LivingRule.LUXURIOUS;
slave.rules.living = LivingRule.SPARE;
case Job.HEADGIRLSUITE.toLowerCase():
slave.assignment = Job.HEADGIRLSUITE;
slave.rules.living = LivingRule.LUXURIOUS;
case Job.MASTERSUITE.toLowerCase():
slave.assignment = Job.MASTERSUITE;
slave.rules.living = LivingRule.LUXURIOUS;
slave.rules.living = LivingRule.NORMAL;
slave.rules.living = LivingRule.NORMAL;
case "Neo Imperialist":
case "Aztec Revivalist":
case "Chinese Revivalist":
case "Chattel Religionist":
case "Edo Revivalist":
case "Supremacist":
case "Subjugationist":
case "Degradationist":
case "Arabian Revivalist":
case "Egyptian Revivalist":
slave.rules.living = LivingRule.SPARE;
case "Slave Professionalism":
if (slave.intelligence + slave.intelligenceImplant > 15) {
slave.rules.living = LivingRule.NORMAL;
slave.rules.living = LivingRule.SPARE;
}
break;
case "Petite Admiration":
case "Statuesque Glorification":
if (heightPass(slave)) {
slave.rules.living = LivingRule.NORMAL;
slave.rules.living = LivingRule.SPARE;
slave.rules.living = LivingRule.NORMAL;
switch (V.spaDecoration) {
case "Chattel Religionist":
case "Chinese Revivalist":
slave.rules.living = LivingRule.NORMAL;
slave.rules.living = LivingRule.SPARE;
slave.rules.living = LivingRule.LUXURIOUS;
slave.rules.living = LivingRule.NORMAL;
uniqueJob("Attendant");
slave.rules.living = LivingRule.LUXURIOUS;
break;
uniqueJob("Matron");
slave.rules.living = LivingRule.LUXURIOUS;
break;
slave.rules.living = LivingRule.LUXURIOUS;
break;
uniqueJob("Madam");
slave.rules.living = LivingRule.LUXURIOUS;
break;
case Job.MILKMAID.toLowerCase():
uniqueJob("Milkmaid");
slave.rules.living = LivingRule.LUXURIOUS;
break;
uniqueJob("Farmer");
slave.rules.living = LivingRule.LUXURIOUS;
break;
uniqueJob("Nurse");
slave.rules.living = LivingRule.LUXURIOUS;
break;
uniqueJob("Schoolteacher");
slave.rules.living = LivingRule.LUXURIOUS;
break;
uniqueJob("Stewardess");
slave.rules.living = LivingRule.LUXURIOUS;
break;
uniqueJob("Wardeness");
slave.rules.living = LivingRule.LUXURIOUS;
case Job.CONCUBINE.toLowerCase():
uniqueJob("Concubine");
slave.rules.living = V.masterSuiteUpgradeLuxury > 0 ? LivingRule.LUXURIOUS : LivingRule.NORMAL;
case Job.HEADGIRL.toLowerCase():
uniqueJob("HeadGirl");
slave.rules.living = LivingRule.LUXURIOUS;
V.HGTimeInGrade = 0;
case Job.BODYGUARD.toLowerCase():
uniqueJob("Bodyguard");
slave.rules.living = LivingRule.LUXURIOUS;
if (V.pit && V.pit.bodyguardFights && V.pit.fighterIDs.includes(slave.ID)) { V.pit.fighterIDs.delete(slave.ID); }
case Job.AGENT.toLowerCase():
case Job.AGENTPARTNER.toLowerCase():
slave.assignment = job;
slave.useRulesAssistant = 0; /* non-visible roles exempt from Rules Assistant */
WombCleanGenericReserve(slave, 'incubator', 9999);
WombCleanGenericReserve(slave, 'nursery', 9999);
if (App.activeArcology().direction !== 0) { // never assign an agent to the player's arcology
if (App.activeArcology().leaderID !== 0) {
const oldAgent = getSlave(App.activeArcology().leaderID);
if (oldAgent && oldAgent.assignment === Job.AGENT) {
// this is an error...you should never be able to assign an agent over the top of another
// but in order to prevent game state corruption, we are going to remove the old agent
removeJob(oldAgent, oldAgent.assignment, false);
}
}
App.activeArcology().leaderID = slave.ID;
App.activeArcology().government = "your agent";
}
slave.choosesOwnAssignment = 1;
slave.assignment = job; /* removeJob already set choosesOwnAssignment = 0 */
V.JobIDMap[slave.assignment].add(slave.ID);
if (!assignmentVisible(slave) && Array.isArray(V.personalAttention)) {
if (V.personalAttention.deleteWith(s => s.ID === slave.ID).length > 0) {
if (V.personalAttention.length === 0) {
r += `${slave.slaveName} no longer has your personal attention; you plan to focus on ${V.personalAttention}.`;
r += `${slave.slaveName} no longer has your personal attention.`;
// maybe recreate it each time? V.JobIDArray = makeJobIdMap();
globalThis.assignJobSafely = function(slave, assignmentStr) {
if (V.assignmentRecords[slave.ID] === Job.CHOICE) {
assignJob(slave, Job.REST);
} else if ([Job.AGENT, Job.AGENTPARTNER].includes(V.assignmentRecords[slave.ID])) { // it is NEVER safe to auto-reassign agents (we don't know which arcology they came from)
assignJob(slave, Job.REST);
} else if (!App.Utils.jobForAssignment(assignmentStr).canEmploy(slave).length) { // If nothing complains about job requirements not being met
assignJob(slave, assignmentStr);
} else {
// Whether they manage to go back or they default to rest, we don't need their record:
if (V.assignmentRecords[slave.ID]) {
delete V.assignmentRecords[slave.ID];
}
* @param {boolean} [saveRecord=false]
globalThis.removeJob = function(slave, assignment, saveRecord = false) {
if (!slave) {
// it is well-formed, but does nothing, to remove an assignment from nobody.
// this lets us call <<run removeJob(_S.HeadGirl, Job.HEADGIRL)>> and similar,
// without first checking to see whether a slave is really assigned to _S.HeadGirl or not.
}
if (V.assignmentRecords[slave.ID] && (saveRecord === false)) {
delete V.assignmentRecords[slave.ID];
}
if (V.pit) {
V.pit.fighterIDs.delete(slave.ID);
V.JobIDMap[Job.PIT].delete(slave.ID);
} else {
return; // TODO: should this return or just continue?
}
} else if (assignment === Job.LURCHER) {
if (V.LurcherID === slave.ID) {
V.LurcherID = 0;
}
V.JobIDMap[Job.LURCHER].delete(slave.ID);
if (V.JobIDMap.hasOwnProperty(assignment)) {
V.JobIDMap[assignment].delete(slave.ID);
} else {
V.JobIDMap[slave.assignment].delete(slave.ID);
}
if (slave.ID === V.HeadGirlID) {
V.HeadGirlID = 0;
} else if (slave.ID === V.RecruiterID) {
V.RecruiterID = 0;
} else if (slave.ID === V.BodyguardID) {
V.BodyguardID = 0;
} else if (slave.ID === V.MadamID) {
V.MadamID = 0;
} else if (slave.ID === V.djID) {
} else if (slave.ID === V.MilkmaidID) {
V.MilkmaidID = 0;
} else if (slave.ID === V.FarmerID) {
V.FarmerID = 0;
} else if (slave.ID === V.SchoolteacherID) {
} else if (V.AttendantID === slave.ID) {
V.AttendantID = 0;
} else if (slave.ID === V.MatronID) {
V.MatronID = 0;
} else if (slave.ID === V.NurseID) {
} else if (slave.ID === V.StewardessID) {
V.StewardessID = 0;
} else if (slave.ID === V.WardenessID) {
} else if (slave.ID === V.ConcubineID) {
V.ConcubineID = 0;
/* use .toLowerCase() to get rid of a few dupe conditions. */
switch (assignment.toLowerCase()) {
slave.assignment = Job.GLORYHOLE;
case Job.CELLBLOCK.toLowerCase():

svornost
committed
deflate(slave);
if (V.dairyRestraintsSetting > 1) {
slave.health.tired = 100;
}
if (V.dairyFeedersSetting > 0) {
slave.diet = "healthy";
}
if (V.dairyHormonesSetting > 0) {
slave.hormones = 0;
}
case Job.FARMYARD.toLowerCase():
case Job.MASTERSUITE.toLowerCase():
break;
case "live with your head girl":
case "head girl suite":
case "hgsuite":
const HGSlave = V.slaves.find(s => s.assignment === Job.HEADGIRLSUITE);
if (HGSlave) {
removeJob(HGSlave, Job.HEADGIRLSUITE);
if (V.HGSuiteEquality === 1 && HGSlave.devotion > 50) {
assignJob(HGSlave, Job.HEADGIRL);
V.HeadGirlID = HGSlave.ID;
HGSlave.diet = "healthy";
attentionCheck = 0;
}
}
if (V.personalAttention === "HG" && attentionCheck === 1) {
r += `You no longer have a slave assigned to be your Head Girl, so you turn your personal attention to focus on ${V.personalAttention}.`;
}
V.HGTimeInGrade = 0;
case Job.AGENT:
case Job.AGENTPARTNER:
if (slave.assignment === Job.AGENT) {
const arc = V.arcologies.find((a) => a.leaderID === slave.ID);
if (arc) {
arc.leaderID = 0;
arc.government = "your trustees";
}
if (slave.relationshipTarget > 0) {
/* following code assumes there can be at most one companion */
const lover = V.slaves.find(s => haveRelationshipP(s, slave) && s.assignment === Job.AGENTPARTNER);
if (lover) {
removeJob(lover, Job.AGENTPARTNER, saveRecord);
V.JobIDMap[slave.assignment].add(slave.ID);
if (slave.rules.living === LivingRule.LUXURIOUS && !assignmentVisible(slave)) {
slave.rules.living = LivingRule.NORMAL;
slave.choosesOwnAssignment = 0;
slave.sentence = 0;
// reset it each time? V.JobIDArray = makeJobIdMap();
/**
* Indicate whether a slave's current assignment is shown in Main
* Often used as a proxy for "penthouse slave"
* @param {App.Entity.SlaveState} slave
* @returns {boolean}
*/
globalThis.assignmentVisible = function(slave) {
switch (slave.assignment) {
/* normal out-of-penthouse jobs */
case Job.BROTHEL:
case Job.CELLBLOCK:
case Job.CLINIC:
case Job.CLUB:
case Job.DAIRY:
case Job.FARMYARD:
case Job.HEADGIRLSUITE:
case Job.MASTERSUITE:
case Job.SCHOOL:
case Job.QUARTER:
case Job.SPA:
case Job.NURSERY:
return false;
/* outside leadership jobs */
case Job.ATTENDANT:
case Job.MATRON:
case Job.DJ:
case Job.MADAM:
case Job.MILKMAID:
case Job.FARMER:
case Job.NURSE:
case Job.TEACHER:
case Job.STEWARD:
case Job.WARDEN:
case Job.CONCUBINE:
return false;
/* agents are not in the arcology at all */
case Job.AGENT:
case Job.AGENTPARTNER:
return false;
/* transition state */
return true; // show
}
/* all other jobs are shown in penthouse */
return true;
};
* @returns {Record<FC.Assignment, Set<number>>} dictionary assignment -> slave IDs
globalThis.makeJobIdMap = function() {
/** @type {Object.<FC.Assignment, Set<number>>} */
for (const jn of Object.values(Job)) {
res[jn] = new Set();
for (const slave of V.slaves) {
res[slave.assignment].add(slave.ID);
if (V.pit) {
res[Job.PIT] = new Set(V.pit.fighterIDs);
}
res[Job.LURCHER].add(V.LurcherID);
/**
* Generates string with links for changing slave assignment
*/
"use strict";
const facilitiesOrder = [
/* sorted by improvement before work, within improvement in order of progress, within work alphabetical for facilities*/
App.Entity.facilities.penthouse,
App.Entity.facilities.cellblock,
App.Entity.facilities.clinic,
App.Entity.facilities.spa,
App.Entity.facilities.arcade,
App.Entity.facilities.brothel,
App.Entity.facilities.club,
App.Entity.facilities.dairy,
App.Entity.facilities.farmyard,
App.Entity.facilities.masterSuite,
App.Entity.facilities.servantsQuarters
return {
assignmentsFragment: assignmentsFragment,
transfersFragment: transfersFragment
};
* @param {number} ID
* @param {string} passage
* @param {assignmentCallback} [callback]
* @returns {DocumentFragment}
*/
function assignmentsFragment(ID, passage, callback) {
let penthouseJobs = App.Entity.facilities.penthouse.assignmentLinkElements(ID, undefined, passage, callback);
const slave = slaveStateById(ID);
const sp = getPronouns(slave);
if (slave.fuckdoll === 0) {
penthouseJobs.push(App.UI.DOM.assignmentLink(slave, assignment, passage, callback, `Let ${sp.object} choose`));
}
} else {
penthouseJobs.push(App.UI.DOM.disabledLink(`Let ${sp.object} choose`, ["Fuckdolls can't choose their job"]));
}
let res = document.createDocumentFragment();
// there is always at least one job
res.appendChild(penthouseJobs[0]);
for (let i = 1; i < penthouseJobs.length; ++i) {
res.appendChild(document.createTextNode(" | "));
res.appendChild(penthouseJobs[i]);
}
return res;
}

svornost
committed
* Generates transfer links
* @param {number} ID
* @param {assignmentCallback} [callback]
* @returns {DocumentFragment}
*/
function transfersFragment(ID, callback) {
/** @type {HTMLElement[]} */
const transfers = [];
const slave = slaveStateById(ID);
if (!f.established || f.jobs.length === 0) { continue; }
const rejects = f.canHostSlave(slave);
if (rejects.length === 0) {
transfers.push(f.transferLinkElement(ID, undefined, passage(), callback));
} else {
transfers.push(App.UI.DOM.disabledLink(f.genericName, rejects));
}
}
let res = document.createDocumentFragment();
// there is always at least one job
res.appendChild(transfers[0]);
for (let i = 1; i < transfers.length; ++i) {
res.appendChild(document.createTextNode(" | "));
res.appendChild(transfers[i]);
}
return res;
}
App.activeArcology = function() {
return V.arcologies[V.activeArcologyIdx];

svornost
committed
return getSlave(V.arcologies[arcology].leaderID);
/**
* Remove all workers from the facility changing their assignments
* @param {App.Entity.Facilities.Facility} facility
* @param {FC.Assignment} [managerAssignment="rest"] new assignment for the facility manager
* @param {FC.Assignment} [workerAssignment="rest"] new assignment for the facility workers
App.Utils.moveFacilityWorkers = function(facility, managerAssignment = Job.REST, workerAssignment = Job.REST) {
if (facility.manager && facility.manager.currentEmployee) {
assignJob(facility.manager.currentEmployee, managerAssignment);
}
for (const w of facility.employees()) {
assignJob(w, workerAssignment);
}
};
App.Utils.jobForAssignment = function() {
const map = new Map();
function fillMap() {
/**
* @param {Map} m
* @param {App.Entity.Facilities.Facility} f
*/
function addFacility(m, f) {
if (f.manager) {
m.set(f.desc.manager.assignment, f.manager);
}
for (const j of f.jobsNames) {
m.set(f.desc.jobs[j].assignment, f.job(j));
}
}
for (const f in App.Entity.facilities) {
if (f.length > 0) {
addFacility(map, App.Entity.facilities[f]);
}
}
}
/**
function getJob(assignment) {
if (map.size === 0) {
fillMap();
}
throw Error(`Can't find job object for assignment '${assignment}'`);
}
return getJob;
}();
/** Assign a slave, play the appropriate assignment scene if necessary, and redirect to a destination passage.
* @param {App.Entity.SlaveState} slave
* @param {string} passage
*/
globalThis.assignmentTransition = function(slave, assignTo, passage) {
/** @param {string} scene */
function detourThroughScene(scene) {
V.returnTo = passage;
Engine.play(scene);
}
assignJob(slave, assignTo);
if (V.showAssignToScenes === 1 && slave.fetish !== "mindbroken") {
if (assignTo === Job.DAIRY && V.dairyRestraintsSetting >= 2 && ((V.dairyStimulatorsSetting >= 2) || (V.dairyFeedersSetting >= 2) || (V.dairyPregSetting >= 2))) {
detourThroughScene("Industrial Dairy Assignment Scene");
} else if (assignTo === Job.DAIRY && (V.dairyRestraintsSetting === 0 && slave.devotion > 0)) {
detourThroughScene("Free Range Dairy Assignment Scene");
} else if (assignTo === Job.BROTHEL) {
detourThroughScene("Brothel Assignment Scene");
} else {
Engine.play(passage);
}
}
};
/**
* Creates a link that will remove all slaves from a facility, including manager.
* @param {string} facilityName
* @param {FC.Assignment} [managerAssignment]
* @param {FC.Assignment} [workerAssignment]
*/
globalThis.removeFacilityWorkers = function(facilityName, managerAssignment, workerAssignment) {
const facility = App.Entity.facilities[facilityName];
const count = facility.totalEmployeesCount;
"Remove all slaves",
() => {
App.Utils.moveFacilityWorkers(facility, managerAssignment, workerAssignment);
penthouseCensus();
},
[],
passage(),
)
);
if ((count + V.dormitoryPopulation) > V.dormitory) {
App.UI.DOM.appendNewElement("span", frag, ` Dormitory capacity will be exceeded.`, "red");