From 1abc3ee924361b40eee142157c9024e202e711d9 Mon Sep 17 00:00:00 2001 From: lowercasedonkey <lowercasedonkey@gmail.com> Date: Wed, 23 Dec 2020 16:40:08 -0500 Subject: [PATCH] move slave specific functions into utilsSlave --- src/js/assayJS.js | 1478 ----------------------------------------- src/js/utilsSlave.js | 1480 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 1478 insertions(+), 1480 deletions(-) diff --git a/src/js/assayJS.js b/src/js/assayJS.js index b4e64a44434..0d8e416e5db 100644 --- a/src/js/assayJS.js +++ b/src/js/assayJS.js @@ -1,272 +1,3 @@ -/** - * @param {App.Entity.SlaveState} A - * @param {App.Entity.SlaveState} B - * @returns {boolean} - */ -globalThis.sameAssignmentP = function(A, B) { - return A.assignment === B.assignment; -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {boolean} - */ -globalThis.canImproveIntelligence = function(slave) { - let origIntel = V.genePool.find(function(s) { return s.ID === slave.ID; }).intelligence; - return (slave.intelligence < origIntel + 15) && (slave.intelligence < 100); -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {number} - */ -globalThis.maxHeight = function(slave) { - let max = Math.trunc(Math.clamp((Height.mean(slave) * 1.25), 0, 274)); /* max achievable height is expected height plus 25% */ - - if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2) { - max = Math.min(max, 160); - } - - return max; -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {boolean} - */ -globalThis.canImproveHeight = function(slave) { - return slave.height < maxHeight(slave); -}; - -/** - * @param {App.Entity.SlaveState} slave - * @param {FC.HumanState} target - * @returns {boolean} - */ -globalThis.haveRelationshipP = function(slave, target) { - return slave.relationshipTarget === target.ID; -}; - -/** - * @param {App.Entity.SlaveState} slave - * @param {App.Entity.SlaveState} target - * @returns {boolean} - */ -globalThis.isRivalP = function(slave, target) { - return slave.rivalryTarget === target.ID; -}; - -/** - * @param {FC.HumanState} slave - * @returns {boolean} - */ -globalThis.supremeRaceP = function(slave) { - return V.arcologies[0].FSSupremacistRace === slave.race; -}; - -/** - * @param {FC.HumanState} slave - * @returns {boolean} - */ -globalThis.inferiorRaceP = function(slave) { - return V.arcologies[0].FSSubjugationistRace === slave.race; -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {boolean} - */ -globalThis.isLeaderP = function(slave) { - const leaders = [S.HeadGirl, S.Bodyguard, S.Recruiter, S.Concubine, S.Nurse, S.Attendant, S.Matron, S.Madam, S.DJ, S.Milkmaid, S.Farmer, S.Stewardess, S.Schoolteacher, S.Wardeness]; - - return leaders.some(leader => leader && leader.ID === slave.ID); -}; - -/** - * colors skin, eyes and hair based on genetic Color. - * Takes .override_*_Color into account. - * - * @param {App.Entity.SlaveState} slave - */ -globalThis.applyGeneticColor = function(slave) { - if (slave.override_Eye_Color !== 1) { - resetEyeColor(slave, "both"); - } - if (slave.override_H_Color !== 1) { - slave.hColor = getGeneticHairColor(slave); - } - if (slave.override_Arm_H_Color !== 1) { - slave.underArmHColor = getGeneticHairColor(slave); - } - if (slave.override_Pubic_H_Color !== 1) { - slave.pubicHColor = getGeneticHairColor(slave); - } - if (slave.override_Brow_H_Color !== 1) { - slave.eyebrowHColor = getGeneticHairColor(slave); - } - if (slave.override_Skin !== 1) { - if (!(slave.skin === "sun tanned" || slave.skin === "spray tanned")) { - slave.skin = getGeneticSkinColor(slave); - } - } -}; - -/** - * @param {FC.GingeredSlave} slave - */ -globalThis.newSlave = function(slave) { - if (getSlave(slave.ID)) { - throw "Slave already exists"; - } - - // if the slave is gingered, remove the gingering proxy - if (slave.beforeGingering) { - slave = slave.beforeGingering; - } - - if (slave.override_Race !== 1) { - slave.origRace = slave.race; - } - - applyGeneticColor(slave); - - /* eslint-disable camelcase */ - slave.override_Race = 0; - slave.override_H_Color = 0; - slave.override_Arm_H_Color = 0; - slave.override_Pubic_H_Color = 0; - slave.override_Brow_H_Color = 0; - slave.override_Skin = 0; - slave.override_Eye_Color = 0; - /* eslint-enable camelcase */ - - // too tall to be a dwarf catch for event slaves - if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2 && slave.height > 165) { - slave.geneticQuirks.dwarfism = 1; - } - - if (V.surnamesForbidden === 1) { - slave.slaveSurname = 0; - } - - if (slave.preg > 0) { - slave.pregWeek = slave.preg; - } else { - slave.pregWeek = 0; - } - - if (slave.clone !== 0) { - slave.canRecruit = 0; - } - - slave.sisters = 0; - slave.daughters = 0; - if (slave.mother === -1 || slave.father === -1) { - V.PC.daughters += 1; - } - if (areSisters(V.PC, slave) > 0) { - V.PC.sisters += 1; - } - for (let k = 0; k < V.slaves.length; k++) { - if (V.slaves[k].mother === slave.ID || V.slaves[k].father === slave.ID) { - slave.daughters++; - } - if (slave.mother === V.slaves[k].ID || slave.father === V.slaves[k].ID) { - V.slaves[k].daughters++; - } - if (areSisters(V.slaves[k], slave) > 0) { - slave.sisters++; - V.slaves[k].sisters++; - } - } - - if (slave.genes === "XX") { - if (slave.pubertyXX === 1) { - if (slave.pubertyXY === 1) { - slave.hormoneBalance = 20; - } else { - slave.hormoneBalance = 60; - } - } else { - if (slave.pubertyXY === 1) { - slave.hormoneBalance = -20; - } else { - slave.hormoneBalance = 20; - } - } - } else if (slave.genes === "XY") { - if (slave.pubertyXX === 1) { - if (slave.pubertyXY === 1) { - slave.hormoneBalance = 20; - } else { - slave.hormoneBalance = 40; - } - } else { - if (slave.pubertyXY === 1) { - slave.hormoneBalance = -40; - } else { - slave.hormoneBalance = 20; - } - } - } - - if (slave.dick > 0 && - slave.balls > 0 && - slave.vagina < 0 && - slave.anus === 0 && - slave.genes === "XY" && - slave.faceShape === "masculine" && - slave.attrXY <= 35 && - slave.boobs < 400 && - slave.hormoneBalance < 0) { - V.REFeminizationCheckinIDs.push(slave.ID); - } - if (slave.actualAge > 35 && slave.face <= 10 && slave.faceImplant === 0 && slave.energy <= 60) { - V.REMILFCheckinIDs.push(slave.ID); - } - if (slave.attrXY <= 35 && slave.attrXX > 65) { - V.REOrientationCheckinIDs.push(slave.ID); - } - if (slave.face < -10) { - V.REUglyCheckinIDs.push(slave.ID); - } - if (slave.anus < 2) { - V.REButtholeCheckinIDs.push(slave.ID); - } - if (slave.boobs < 800) { - V.REReductionCheckinIDs.push(slave.ID); - } - - generatePronouns(slave); - SetBellySize(slave); - V.slaveIndices[slave.ID] = V.slaves.push(slave) - 1; - - if (slave.origin !== "$He was your slave, but you freed $him, which $he repaid by participating in a coup attempt against you. It failed, and $he is again your chattel." && slave.ID !== V.boomerangSlave.ID) { - V.genePool.push(clone(slave)); - } else { - if (!V.genePool.some(s => s.ID === slave.ID)) { - V.genePool.push(slave); - } - } - - /* special case for dulling intelligence via drugs in slave acquisition */ - if (slave.dullIntelligence) { - slave.intelligence = -100; - delete slave.dullIntelligence; - } - - if (slave.assignment) { - assignJob(slave, slave.assignment); - } else { - slave.assignment = Job.CHOICE; - } - - /** do not run the Rules Assistant before adding the new slave to the slaves list! **/ - if (V.ui !== "start" && V.universalRulesNewSlavesRA === 1 && V.rulesAssistantAuto !== 0) { - DefaultRules(slave); - } -}; - /** * @param {App.Entity.SlaveState[]} [slaves] * @returns {Object.<number, number>} @@ -297,924 +28,6 @@ globalThis.getChild = function(ID) { return V.cribs.find(s => s.ID === ID); }; -/** Get the written title for a given slave, without messing with global state. - * @param {App.Entity.SlaveState} [slave] - * @returns {string} - */ -globalThis.getWrittenTitle = function(slave) { - if (slave && slave.custom.title !== undefined && slave.custom.title !== "" && slave.rudeTitle === 0) { - return slave.custom.title; - } - if (V.PC.customTitle !== undefined) { - return V.PC.customTitle; - } else if (V.PC.title !== 0) { - return "Master"; - } else { - return "Mistress"; - } -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {number} - */ -globalThis.fetishChangeChance = function(slave) { - let chance = 0, - fetish = (slave.fetishStrength / 4), - sex = 0; - - if (slave.clitSetting !== slave.fetish) { - // fetish should be more uncertain leading towards puberty and then steadily become more set in stone afterwards - if (slave.balls) { - if (V.potencyAge >= slave.actualAge) { - sex = (50 - ((V.potencyAge - slave.actualAge) * 10)); - fetish = (slave.fetishStrength / 2); - } else { - sex = ((slave.actualAge - V.potencyAge) / 4); - } - } else if (slave.ovaries || slave.mpreg) { - if (V.fertilityAge >= slave.actualAge) { - sex = (50 - ((V.fertilityAge - slave.actualAge) * 10)); - fetish = (slave.fetishStrength / 2); - } else { - sex = ((slave.actualAge - V.fertilityAge) / 4); - } - } - chance = Math.trunc(Math.clamp((slave.devotion / 4) - (fetish) - (sex), 0, 100)); - } - - return chance; -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {string} - */ -globalThis.SlaveFullName = function(slave) { - const pair = slave.slaveSurname ? [slave.slaveName, slave.slaveSurname] : [slave.slaveName]; - if ((V.surnameOrder !== 1 && ["Cambodian", "Chinese", "Hungarian", "Japanese", "Korean", "Mongolian", "Taiwanese", "Vietnamese"].includes(slave.nationality)) || (V.surnameOrder === 2)) { - pair.reverse(); - } - return pair.join(" "); -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {string} - */ -globalThis.SlaveFullBirthName = function(slave) { - const pair = slave.birthSurname ? [slave.birthName, slave.birthSurname] : [slave.birthName]; - if ((V.surnameOrder !== 1 && ["Cambodian", "Chinese", "Hungarian", "Japanese", "Korean", "Mongolian", "Taiwanese", "Vietnamese"].includes(slave.nationality)) || (V.surnameOrder === 2)) { - pair.reverse(); - } - return pair.join(" "); -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {string} - */ -globalThis.PoliteRudeTitle = function(slave) { - const PC = V.PC; - const {s, ss, title} = getEnunciation(slave); - - let r = ""; - if (slave.nationality === "Japanese") { - if (slave.trust > 0) { - r += `${PC.slaveName}${PC.title > 0 ? "kun" : "chan"}`; - } else { - r += (PC.slaveSurname ? PC.slaveSurname : `${PC.slaveName}${s}an`); - } - } else { - if (slave.intelligence + slave.intelligenceImplant < -95) { - r += title; - } else if (slave.intelligence + slave.intelligenceImplant > 50) { - r += (PC.title > 0 ? `Ma${s}ter` : `Mi${s}tre${ss}`); - } else if (slave.trust > 0) { - r += PC.slaveName; - } else { - r += (PC.slaveSurname ? PC.slaveSurname : PC.slaveName); - } - } - return r; -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {string} - */ -globalThis.SlaveTitle = function(slave) { - let r; - if (V.newDescriptions === 1) { - if (slave.dick > 0 && slave.balls > 0 && slave.boobs > 300 && slave.vagina > -1 && slave.ovaries === 1) { - if (jsRandom(1, 100) > 50) { - r = "futanari"; - } else { - r = "herm"; - } - } else if (slave.dick > 0 && slave.balls === 0 && slave.boobs > 300 && slave.vagina > -1 && slave.ovaries === 1) { - r = "dickgirl"; - } else if (slave.dick > 0 && slave.vagina > -1 && slave.ovaries === 0) { - r = "shemale"; - } else if (slave.dick > 0 && slave.balls === 0 && slave.vagina === -1 && slave.ovaries === 0) { - r = "eunuch"; - } else if (slave.dick > 0 && slave.balls > 0 && slave.vagina === -1 && slave.ovaries === 0) { - if (slave.face > 10 && slave.hips > -1 && slave.shoulders < 1 && slave.faceShape !== "masculine") { - r = "trap"; - } else if (slave.boobs > 800) { - r = "tittyboy"; - } else if (slave.dick === 1 && slave.balls === 1) { - r = "sissy"; - } else if (slave.dick > 1 && slave.balls > 1 && slave.height < 165 && slave.muscles < 5 && slave.visualAge < 19 && slave.faceShape !== "masculine") { - r = "twink"; - } else if (slave.dick > 1 && slave.balls > 1 && slave.height < 160 && slave.muscles < 5 && slave.visualAge < 19) { - r = "boytoy"; - } else if (slave.muscles > 95 && slave.height >= 185) { - r = "titan"; - } else if (slave.muscles > 30) { - r = "muscleboy"; - } else { - r = "slaveboy"; - } - } else if (slave.dick === 0 && slave.balls === 0 && slave.vagina > -1) { - if ((slave.shoulders > slave.hips || slave.faceShape === "masculine") && slave.boobs < 400 && slave.genes === "XY") { - r = "cuntboy"; - } else if (slave.ovaries === 0 && slave.genes === "XY") { - r = "tranny"; - } else if (slave.weight > 10 && slave.boobs > 800 && slave.counter.birthsTotal > 0 && slave.physicalAge > 59) { - r = "GMILF"; - } else if (slave.weight > 10 && slave.boobs > 800 && slave.counter.birthsTotal > 0 && slave.physicalAge > 35) { - r = "MILF"; - } else if (slave.lips > 70 && slave.boobs > 2000 && slave.butt > 3) { - r = "bimbo"; - } else if (slave.hips > 1 && slave.boobs > 2000 && slave.butt > 3 && slave.waist < 50) { - r = "hourglass"; - } else if (slave.muscles > 95 && slave.height >= 185) { - r = "amazon"; - } else if (slave.muscles > 30) { - r = "musclegirl"; - } else { - r = "slavegirl"; - } - } else if (slave.dick === 0 && slave.balls === 0 && slave.vagina === -1) { - r = "neuter"; - } else if (slave.dick === 0 && slave.vagina === -1) { - r = "ballslave"; - } else { - r = "slave"; - } - - if (slave.visualAge < 13) { - if (slave.actualAge < 3) { - if (slave.actualAge < 1) { - r = "baby " + r; - } else { - r = "toddler " + r; - } - } else { - if (slave.genes === "XY" && slave.vagina === -1) { - r = "shota " + r; - } else { - r = "loli " + r; - } - } - } - - if (slave.geneticQuirks.albinism === 2) { - r = `albino ${r}`; - } - - if (slave.dick > 9 && slave.balls > 9 && slave.boobs > 12000) { - r = `hyper ${r}`; - } - - if (slave.boobs > 4000 && slave.lactation > 0) { - if (slave.physicalAge < 13) { - r = `${r} calf`; - } else { - r = `${r} cow`; - } - } else if (slave.lactation > 0) { - r = `milky ${r}`; - } - - if (slave.boobs > 20000) { - r = `supermassive titted ${r}`; - } else if (slave.boobs > 10000) { - r = `giant titted ${r}`; - } else if (slave.boobs > 4000) { - r = `huge titted ${r}`; - } else if (slave.boobs > 1000) { - r = `busty ${r}`; - } - - if (slave.dick > 5 && slave.balls > 5) { - r = `womb filling ${r}`; - } else if (slave.dick > 5) { - r = `well hung ${r}`; - } - - if (slave.butt >= 12) { - r = `colossal assed ${r}`; - } else if (slave.butt >= 10) { - r = `massive assed ${r}`; - } else if (slave.butt >= 8) { - r = `fat assed ${r}`; - } else if (slave.butt >= 6) { - r = `bottom heavy ${r}`; - } else if (slave.butt >= 4) { - r = `big bottomed ${r}`; - } - - if (slave.weight > 10 && slave.weight < 100 && slave.boobs > 5000 && slave.butt > 5 && slave.hips >= 2 && slave.bellyPreg >= 30000 && slave.counter.births >= 10) { - r = `${r} fertility goddess`; - } else if (slave.counter.births >= 6) { - r = `${r} broodmother`; - } else if (slave.counter.births >= 3) { - r = `${r} breeder`; - } - - if (slave.indenture > -1) { - r = `indentured ${r}`; - } - - if (slave.preg > slave.pregData.normalBirth / 4 && slave.pregKnown === 1) { - r = `pregnant ${r}`; - } else if (slave.bellyFluid >= 5000) { - r = `bloated ${r}`; - } else if (slave.belly >= 5000) { - r = `gravid ${r}`; - } - - if (slave.fuckdoll > 0) { - r = `${r} fuckdoll`; - } - } else { - r = "slave"; /* I don't think there is an 'else'? */ - if ((slave.dick === 0) && (slave.vagina === -1)) { - /* NULLS */ - r = "null"; - if ((slave.lactation > 0) && (slave.boobs > 2000)) { - r = `${r} cow`; - } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { - r = `${r} bimbo `; - } else if (slave.boobs > 6000) { - r = `${r} boob`; - } else if (slave.butt > 6) { - r = `${r} ass`; - } else if ((slave.muscles > 30) && (slave.height < 185)) { - r = `${r} muscle`; - } - if (slave.visualAge > 55) { - r = `${r}GILF`; - } else if (slave.visualAge > 35) { - r = `${r}MILF`; - } else if (slave.visualAge >= 25) { - r = `${r}slave`; - } else { - r = `${r}girl`; - } - } - - if ((slave.dick === 0) && (slave.vagina !== -1)) { - /* FEMALES */ - if (slave.visualAge > 55) { - r = "GILF"; - } else if (slave.visualAge > 35) { - r = "MILF"; - } else if (slave.visualAge >= 25) { - r = "slave"; - } else { - r = "slavegirl"; - } - if ((slave.muscles > 30) && (slave.height < 185)) { - r = `muscle ${r}`; - } else if ((slave.lactation > 0) && (slave.boobs > 2000)) { - r = `${r} cow`; - } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { - r = `${r} bimbo`; - } else if (slave.boobs > 6000) { - r = `boob${r}`; - } else if (slave.butt > 6) { - r = `ass${r}`; - } - } - - if ((slave.dick !== 0) && (slave.vagina !== -1)) { - if (slave.balls > 0) { - /* FUTANARI: cock & balls & vagina */ - r = "futanari "; - } else { - /* FUTANARI: cock & vagina */ - r = "futa "; - } - if ((slave.lactation > 0) && (slave.boobs > 2000)) { - r = `${r}cow`; - } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { - r = `${r}bimbo `; - } else if (slave.boobs > 6000) { - r = `${r}boob`; - } else if (slave.butt > 6) { - r = `${r}ass`; - } else if ((slave.muscles > 30) && (slave.height < 185)) { - r = `${r}muscle`; - } - if (slave.visualAge > 55) { - r = `${r}GILF`; - } else if (slave.visualAge > 35) { - r = `${r}MILF`; - } else if (slave.visualAge >= 25) { - r = `${r}slave`; - } else { - r = `${r}girl`; - } - if (slave.dick > 5 && slave.balls > 5 && slave.boobs > 5000) { - r = `hyper ${r}`; - } - } - - if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls > 0) && (slave.boobs > 300) && (slave.butt > 2)) { - /* SHEMALES: cock & balls, T&A above minimum */ - if (slave.visualAge > 55) { - r = "sheGILF"; - } else if (slave.visualAge > 35) { - r = "sheMILF"; - } else if (slave.visualAge >= 25) { - r = "shemale"; - } else { - r = "tgirl"; - } - if ((slave.muscles > 30) && (slave.height < 185)) { - r = `muscle${r}`; - } else if ((slave.lactation > 0) && (slave.boobs > 2000)) { - r = `${r} cow`; - } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { - r = `${r} bimbo`; - } else if (slave.boobs > 6000) { - r = `topheavy ${r}`; - } else if (slave.butt > 6) { - r = `bottomheavy ${r}`; - } - } - - if ((slave.boobs < 300) || (slave.butt < 2)) { - if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls > 0)) { - if ((slave.shoulders < 1) || (slave.muscles <= 30)) { - if ((slave.faceShape === "masculine") || (slave.faceShape === "androgynous")) { - /* SISSIES: feminine shoulders or muscles, masculine faces */ - if (slave.visualAge > 55) { - r = "sissyGILF"; - } else if (slave.visualAge > 35) { - r = "sissyMILF"; - } else { - r = "sissy"; - } - } else { - /* TRAPS: feminine shoulders or muscles, feminine faces */ - if (slave.visualAge > 55) { - r = "trapGILF"; - } else if (slave.visualAge > 35) { - r = "trapMILF"; - } else if (slave.visualAge >= 25) { - r = "trap"; - } else { - r = "trapgirl"; - } - } - if (slave.lactation > 0) { - r = `${r} cow`; - } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { - r = `${r} bimbo`; - } - } - } - } - - if ((slave.boobs < 300) || (slave.butt < 2)) { - if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls > 0)) { - if ((slave.shoulders > 1) || (slave.muscles >= 30)) { - /* BITCHES: masculine shoulders or muscles */ - r = "bitch"; - if ((slave.muscles > 30) && (slave.height < 185)) { - r = `muscle${r}`; - } else if (slave.lactation > 0) { - r = `${r}cow`; - } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { - r = `bimbo ${r}`; - } - if (slave.visualAge > 55) { - r = `aged ${r}`; - } else if (slave.visualAge > 35) { - r = `mature ${r}`; - } else if (slave.visualAge < 25) { - r = `young ${r}`; - } - } - } - } - - if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls === 0)) { - r = "dick"; - if (slave.visualAge > 55) { - r = `${r}GILF`; - } else if (slave.visualAge > 35) { - r = `${r}MILF`; - } else if (slave.visualAge >= 25) { - r = `${r}slave`; - } else { - r = `${r}girl`; - } - if ((slave.muscles > 30) && (slave.height < 185)) { - r = `muscle${r}`; - } else if ((slave.lactation > 0) && (slave.boobs > 2000)) { - r = `${r} cow`; - } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { - r = `${r} bimbo`; - } else if (slave.boobs > 6000) { - r = `boob ${r}`; - } else if (slave.butt > 6) { - r = `ass ${r}`; - } - } - - if ((slave.muscles > 30) && (slave.height > 185)) { - r = `amazon ${r}`; - } else if ((slave.muscles < 30) && (slave.height > 185)) { - r = `statuesque ${r}`; - } else if ((slave.boobs < 800) && (slave.height < 150)) { - r = `petite ${r}`; - } else if ((slave.boobs > 800) && (slave.height < 150)) { - r = `shortstack ${r}`; - } - - if (slave.counter.births >= 5) { - r = `${r} broodmother`; - } else if (slave.counter.births >= 2) { - r = `${r} breeder`; - } - - if (slave.geneticQuirks.albinism === 2) { - r = `albino ${r}`; - } - - if (slave.indenture > -1) { - r = `indentured ${r}`; - } - - if (slave.preg > slave.pregData.normalBirth / 4 && slave.pregKnown === 1) { - r = `pregnant ${r}`; - } else if (slave.bellyFluid >= 5000) { - r = `bloated ${r}`; - } else if (slave.belly >= 5000) { - r = `gravid ${r}`; - } - - if (slave.fuckdoll > 0) { - r = `${r} fuckdoll`; - } - } - return r; -}; - -/** - * @param {App.Entity.SlaveState} slave - */ -globalThis.DegradingName = function(slave) { - const leadershipPosition = [ - Job.ATTENDANT, - Job.MATRON, - Job.STEWARD, - Job.MILKMAID, - Job.FARMER, - Job.DJ, - Job.CONCUBINE, - Job.MADAM, - Job.TEACHER, - Job.WARDEN, - Job.NURSE, - Job.HEADGIRL, - Job.BODYGUARD, - Job.RECRUITER - ]; - const names = []; - const suffixes = []; - - if (slave.fuckdoll > 0) { - slave.slaveName = `Fuckdoll No. ${slave.ID}`; - slave.slaveSurname = 0; - } else if (slave.assignment === Job.DAIRY && V.dairyRestraintsSetting >= 2) { - slave.slaveName = `Bioreactor No. ${slave.ID}`; - slave.slaveSurname = 0; - } else { - if (V.seeRace === 1) { - switch (slave.race) { - case "white": - names.push("Pale", "White"); - break; - case "asian": - names.push("Asian", "Yellow"); - break; - case "latina": - names.push("Brown", "Latina"); - break; - case "black": - names.push("Black", "Dark"); - break; - case "pacific islander": - names.push("Islander", "Pacific", "Sea"); - break; - case "malay": - names.push("Cinnamon", "Pinoy", "Spice"); - break; - case "southern european": - names.push("Mediterranean", "Olive"); - break; - case "amerindian": - names.push("Indian", "Reservation"); - break; - case "semitic": - names.push("Semite", "Semitic"); - break; - case "middle eastern": - names.push("Arab", "Sand"); - break; - case "indo-aryan": - names.push("Brown", "Indian"); - break; - case "mixed race": - names.push("Mixed", "Mulatto", "Mutt"); - break; - } - } - names.push(slave.hColor); - if (!hasAnyEyes(slave)) { - names.push("Blind", "Eyeless", "Sightless"); - } - if (slave.hears === -2) { - names.push("Deaf", "Earless", "Unhearing"); - } - if (slave.boobs >= 2000) { - suffixes.push("Boob", "Boobs", "Titty"); - } - if (slave.boobs < 500 && slave.butt < 3) { - names.push("Girly", "Slim", "Thin"); - } - if (slave.boobs < 300) { - names.push("Flat"); - } - if (slave.anus > 2 || slave.vagina > 2) { - names.push("Gaping", "Hallway", "Slit", "Wideopen"); - } - if (slave.weight > 160) { - names.push("Blimp", "Cow", "Fat", "Fatass", "Whale"); - } else if (slave.weight > 30) { - names.push("Chubby", "Fat", "Whale"); - } else if (slave.weight <= -30) { - names.push("Bony", "Rail", "Skinny"); - } - if (slave.muscles > 30) { - names.push("Huge", "Muscles", "Ripped", "Strong"); - } - if (slave.fetishKnown === 1) { - if (slave.fetish === "buttslut") { - names.push("Anal", "Sodomy"); - } - if (slave.fetish === "cumslut") { - names.push("Cum", "Dicksuck", "Sucker"); - } - if (slave.fetish === "humiliation") { - names.push("Rape"); - } - if (slave.fetish === "masochist") { - names.push("Pain", "Rape", "Struggle"); - } - if (slave.fetish === "pregnancy") { - names.push("Fertile"); - } - } - if (slave.boobs * slave.lactation > 1000) { - names.push("Creamy", "Milky"); - suffixes.push("Cow"); - } - if (slave.skill.oral <= 30 && slave.skill.anal <= 30) { - names.push("Cheap", "Fail", "Gutter"); - } - if (slave.nipples === "fuckable") { - names.push("Nipplefuck", "Nipplecunt"); - } else if (slave.nipples !== "tiny" && slave.nipples !== "cute") { - names.push("Pointy", "Titclit"); - suffixes.push("Nipples"); - } - if (slave.visualAge > 35) { - names.push("Mature"); - suffixes.push("Cougar", "MILF"); - } else if (slave.visualAge < 25) { - names.push("Girly", "Thin", "Young"); - } - if (isAmputee(slave)) { - names.push("Stumpy"); - suffixes.push("Stumpy"); - } - if (slave.boobsImplant > 1000 || slave.buttImplant > 3) { - names.push("Fake", "Plastic", "Silicone"); - } - if (slave.dick > 5 && slave.balls > 5) { - names.push("Potent"); - suffixes.push("Cannon", "Daddy"); - } - if (slave.preg > slave.pregData.normalBirth / 1.33) { - if (slave.broodmother === 2) { - names.push("Bursting", "Seeded"); - suffixes.push("Factory", "Nursery"); - } else if (slave.broodmother === 1) { - names.push("Bloated", "Stuffed"); - suffixes.push("Breeder", "Factory"); - } - } - if (slave.bellyPreg >= 450000) { - names.push("Bulging", "Squirming"); - } - if (slave.bellyPreg >= 5000) { - names.push("Preg"); - suffixes.push("Belly", "Mommy"); - } - if (slave.belly > 150000) { - suffixes.push("Balloon"); - } - if (slave.belly > 1500) { - suffixes.push("Belly"); - } - if (slave.dick > 0) { - if (slave.dick > 4) { - names.push("Dangle", "Hung"); - suffixes.push("Cock", "Dick"); - } - if (slave.balls === 0) { - names.push("Cut", "Gelded", "Soft"); - } else { - names.push("Erect", "Hard", "Stiff"); - } - } - if (slave.dick === 1) { - names.push("Micro", "Tiny"); - suffixes.push("Bitch"); - } - if (slave.height >= 185) { - names.push("Tall", "Top"); - suffixes.push("Tower"); - } else if (slave.height < 150) { - names.push("Stumpy", "Tiny"); - suffixes.push("Shortstack", "Stumpy"); - } - if (slave.skill.whoring > 95) { - names.push("Money", "Street"); - suffixes.push("Whore"); - } - if (slave.skill.entertainment > 95) { - names.push("Easy", "Club"); - suffixes.push("Slut"); - } - if (slave.skill.oral > 95) { - names.push("Suck"); - suffixes.push("Throat"); - } - if (slave.skill.vaginal > 95) { - suffixes.push("Channel", "Kegel", "Pussy"); - } - if (slave.skill.anal > 95) { - suffixes.push("Asspussy", "Sphincter"); - } - if (slave.intelligence + slave.intelligenceImplant > 50) { - names.push("Bright", "Clever", "Smart"); - if (slave.intelligenceImplant >= 15) { - names.push("College", "Graduate", "Nerdy"); - } - } else if (slave.intelligence + slave.intelligenceImplant < -50) { - names.push("Cretin", "Dumb", "Retarded", "Stupid"); - } - if (slave.vagina === 1 && slave.skill.vaginal <= 10) { - names.push("Fresh", "New", "Tight"); - } - if (slave.devotion < -75) { - names.push("Angry", "Biter", "Caged"); - } else if (slave.devotion < -50) { - names.push("Cell", "Cuffs"); - } else if (slave.devotion < -20) { - names.push("Bag", "Box"); - } else if (slave.devotion <= 20) { - names.push("Sad", "Whiner"); - } else if (slave.devotion > 50) { - names.push("Prize"); - if (slave.visualAge > 35) { - names.push("Queen"); - } else if (slave.visualAge < 25) { - names.push("Princess"); - } - } - if (slave.trust < -50) { - names.push("Screaming"); - suffixes.push("Sobber"); - } else if (slave.trust < -20) { - names.push("Crying"); - suffixes.push("Meat", "Tears", "Thing", "Weeper"); - } else if (slave.trust < 20) { - names.push("Begging"); - } - - if (slave.dick === 0) { - if (slave.vagina === -1) { - suffixes.push("Null"); - } else { - if (slave.visualAge < 25) { - suffixes.push("Girl"); - } - } - } else { - if (slave.vagina !== -1) { - suffixes.push("Futa"); - } else { - if (slave.balls > 0) { - if (slave.boobs > 300 && slave.butt > 2) { - /* SHEMALES: cock & balls, T&A above minimum */ - suffixes.push("Shemale"); - } else { - if (slave.shoulders < 1 && slave.muscles <= 30) { - if (slave.faceShape === "masculine" || slave.faceShape === "androgynous") { - /* SISSIES: feminine shoulders or muscles, masculine faces */ - suffixes.push("Sissy"); - } else { - /* TRAPS: feminine shoulders or muscles, feminine faces */ - suffixes.push("Trap"); - } - } else { - /* BITCHES: masculine shoulders or muscles */ - suffixes.push("Bitch"); - } - } - } else { - if (slave.visualAge > 35) { - suffixes.push("DickMILF"); - } else if (slave.visualAge >= 25) { - suffixes.push("Dickslave"); - } else { - suffixes.push("Dickgirl"); - } - } - } - } - if (slave.anus > 0) { - suffixes.push("Anus", "Asshole", "Backdoor", "Butt", "Butthole"); - } - if (slave.anus === 1) { - suffixes.push("Tightass", "Tightbutt"); - } - if (slave.vagina > 0) { - suffixes.push("Cunt", "Pussy", "Vagina"); - } - if (slave.boobs < 500 && slave.butt < 3 && slave.dick > 0) { - suffixes.push("Bitch", "Bottom", "Sissy", "Trap"); - } - if (slave.energy > 95) { - suffixes.push("Fuck", "Fuckaddict", "Nympho", "Sexaddict"); - } - if (slave.fetishKnown === 1) { - if (slave.fetish === "humiliation") { - suffixes.push("Rapebait", "Showgirl"); - } - if (slave.fetish === "submissive") { - suffixes.push("Bottom", "Fuckee", "Rapebait"); - } - if (slave.fetish === "dom") { - suffixes.push("Dom", "Fucker", "Top"); - } - if (slave.fetish === "pregnancy") { - suffixes.push("Breeder", "Mommy"); - } - if (slave.fetish === "boobs") { - suffixes.push("Boob", "Boobie", "Tit", "Titty"); - } - } - if (slave.counter.births >= 2) { - suffixes.push("Breeder"); - if (slave.counter.births >= 5) { - suffixes.push("Broodmother"); - } - } - if (slave.areolae > 2) { - suffixes.push("Areolas", "Headlights"); - } - if (slave.lips > 40) { - suffixes.push("Lips", "Pillows"); - } - if (slave.labia > 1) { - suffixes.push("Curtains", "Flower", "Lips"); - } - if (slave.breedingMark === 1 && V.propOutcome === 1 && V.arcologies[0].FSRestart !== "unset") { - suffixes.push("Breeder", "Oven", "Womb"); - } - if (slave.butt > 5) { - suffixes.push("Ass", "Bottom", "Butt"); - } - if (slave.vagina === 0) { - suffixes.push("Virgin"); - } - - slave.slaveName = jsEither(names); - } - if (leadershipPosition.includes(slave.assignment)) { - switch (slave.assignment) { - case Job.ATTENDANT: - slave.slaveName = jsEither(["Bath", "Spa"]); - break; - case Job.MATRON: - slave.slaveName = jsEither(["Matron", "Nursery"]); - break; - case Job.STEWARD: - slave.slaveName = jsEither(["Maid", "Servant"]); - break; - case Job.MILKMAID: - if (V.cumSlaves > 3) { - slave.slaveName = jsEither(["Fucker", "Milker"]); - } else { - slave.slaveName = jsEither(["Dairy", "Farm"]); - } - break; - case Job.FARMER: - slave.slaveName = jsEither(["Farmer", "Farmhand"]); - break; - case Job.DJ: - slave.slaveName = jsEither(["Bass", "Booth"]); - break; - case Job.CONCUBINE: - slave.slaveName = jsEither(["Bed", "Master"]); - break; - case Job.MADAM: - slave.slaveName = jsEither(["Madam", "Pimp"]); - break; - case Job.TEACHER: - slave.slaveName = jsEither(["Classroom", "Teacher"]); - break; - case Job.WARDEN: - slave.slaveName = jsEither(["Jail", "Prison"]); - break; - case Job.NURSE: - slave.slaveName = jsEither(["Clinic", "Nurse"]); - break; - case Job.HEADGIRL: - slave.slaveName = jsEither(["Chief", "Head"]); - break; - case Job.BODYGUARD: - slave.slaveName = jsEither(["Battle", "Guard"]); - break; - case Job.RECRUITER: - slave.slaveName = jsEither(["Cam", "Recruiter"]); - break; - } - } - const surname = jsEither(suffixes); - if (typeof surname === "string" && surname.toLowerCase() === slave.slaveName.toLowerCase()) { - DegradingName(slave); - } - slave.slaveName = capFirstChar(slave.slaveName); - slave.slaveSurname = surname; -}; - -globalThis.PaternalistName = function(slave) { - if (slave.slaveName.search("Miss") === -1) { - if (slave.slaveName.search("Ms.") === -1) { - if (slave.slaveName.search("Mrs.") === -1) { - if (slave.relationship > 4) { - slave.slaveName = ("Mrs. " + slave.slaveName); - } else if (slave.actualAge > 24) { - slave.slaveName = ("Ms. " + slave.slaveName); - } else { - slave.slaveName = ("Miss " + slave.slaveName); - } - } - } - } -}; - -globalThis.parentNames = function(parent, child) { - const slaves = V.slaves; - - let currentSlaveNames = slaves.map(s => s.slaveName); - let continentNationality; - const useMaleName = (child.genes === "XY" && V.allowMaleSlaveNames === true); - - child.slaveName = generateName(parent.nationality, child.race, useMaleName, sn => !currentSlaveNames.includes(sn)); - - if (!child.slaveName) { - for (let i = 0; i < 10; i++) { - continentNationality = hashChoice(V.nationalities); - child.slaveName = generateName(continentNationality, child.race, useMaleName, sn => !currentSlaveNames.includes(sn)); // jshint ignore: line - } - } - if (!child.slaveName) { - child.slaveName = generateName(parent.nationality, child.race, useMaleName); - } -}; - globalThis.SlaveSort = function() { const effectivePreg = (slave) => { // slave.preg is only *mostly* usable for sorting @@ -1379,297 +192,6 @@ globalThis.menialPopCap = function() { return {text: r, value: popCap}; }; -/** - * @param {App.Entity.SlaveState} slave - * @param {number} amount - * @returns {string} - */ -globalThis.faceIncrease = function(slave, amount) { - const pronouns = getPronouns(slave); - const his = pronouns.possessive; - const His = capFirstChar(his); - let r = ""; - if (slave.face <= -95) { - r += `<span class="green">${His} face is no longer horrifying,</span> and is now merely ugly.`; - } else if (slave.face <= -40 && slave.face + amount > -40) { - r += `<span class="green">${His} face is no longer ugly,</span> and is now merely unattractive.`; - } else if (slave.face <= -10 && slave.face + amount > -10) { - r += `<span class="green">${His} face is no longer unattractive,</span> and is now somewhat tolerable.`; - } else if (slave.face <= 10 && slave.face + amount > 10) { - r += `<span class="green">${His} face is now decently attractive,</span> rather than merely tolerable.`; - } else if (slave.face <= 40 && slave.face + amount > 40) { - r += `<span class="green">${His} face is now quite beautiful,</span> rather than merely pretty.`; - } else if (slave.face <= 95 && slave.face + amount > 95) { - r += `<span class="green">${His} face is now perfect.</span> It's difficult to imagine how it could be any more beautiful.`; - } - slave.face = Math.clamp(slave.face + amount, -100, 100); - if (slave.face > 95) { - slave.face = 100; - } - return r; -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {number} - */ -globalThis.deadliness = function(slave) { - let deadliness = 2; - - if (slave.skill.combat > 0) { - deadliness += 2; - } - - if (App.Data.Careers.Leader.bodyguard.includes(slave.career)) { - deadliness += 1; - } else if (slave.skill.bodyguard >= V.masteredXP) { - deadliness += 1; - } - - if (V.AgePenalty !== 0) { - if (slave.physicalAge >= 100) { - deadliness -= 10; - } else if (slave.physicalAge >= 85) { - deadliness -= 3; - } else if (slave.physicalAge >= 70) { - deadliness -= 1; - } - } - - if (slave.muscles > 30 && slave.muscles <= 95) { - deadliness += 1; - } else if (slave.muscles > 95 && slave.height >= 185) { - deadliness += 2; - } else if (slave.muscles > 95) { - deadliness -= 1; - } else if (slave.muscles < -95) { - deadliness -= 20; - } else if (slave.muscles < -30) { - deadliness -= 7; - } else if (slave.muscles < -5) { - deadliness -= 3; - } - - if (slave.height >= 170) { - deadliness += 1; - } - - if (slave.health.condition > 50) { - deadliness += 1; - } else if (slave.health.condition < -50) { - deadliness -= 1; - } - - if (slave.health.illness > 3) { - deadliness -= 3; - } else if (slave.health.illness > 1) { - deadliness -= 2; - } else if (slave.health.illness > 0) { - deadliness -= 1; - } - - if (slave.boobs > 4000) { - deadliness -= 2; - } else if (slave.boobs > 2000) { - deadliness -= 1; - } - - if (slave.butt > 6) { - deadliness -= 1; - } - - if (slave.hips > 2) { - deadliness -= 1; - } - - if (slave.weight > 190) { - deadliness -= 20; - } else if (slave.weight > 160) { - deadliness -= 10; - } else if (slave.weight > 130) { - deadliness -= 3; - } else if (slave.weight > 30 || slave.weight < -10) { - deadliness -= 1; - } - - if (slave.bellyFluid >= 10000) { - deadliness -= 3; - } else if (slave.bellyFluid >= 5000) { - deadliness -= 2; - } else if (slave.bellyFluid >= 2000) { - deadliness -= 1; - } - - if (slave.pregKnown === 1 || slave.bellyPreg >= 1500 || slave.bellyImplant >= 1500) { - if (slave.belly >= 750000) { - deadliness -= 50; - } else if (slave.belly >= 600000) { - deadliness -= 25; - } else if (slave.belly >= 450000) { - deadliness -= 15; - } else if (slave.belly >= 300000) { - deadliness -= 10; - } else if (slave.belly >= 150000) { - deadliness -= 8; - } else if (slave.belly >= 100000) { - deadliness -= 7; - } else if (slave.belly >= 10000) { - deadliness -= 3; - } else if (slave.belly >= 5000) { - deadliness -= 2; - } else { - deadliness -= 1; - } - } - - if (isInLabor(slave)) { - deadliness -= 15; - } else if (slave.preg >= slave.pregData.normalBirth && slave.pregControl !== "labor suppressors") { - deadliness -= 5; - } - - if (slave.balls >= 15) { - deadliness -= 1; - } - - if (slave.dick >= 10) { - deadliness -= 1; - } - - deadliness -= getLimbCount(slave, 0) * 5; - deadliness -= getLimbCount(slave, 2) * 0.25; - deadliness -= getLimbCount(slave, 3) * 0.25; - deadliness -= getLimbCount(slave, 4) * 0.25; - deadliness += getLimbCount(slave, 5) * 1.25; - deadliness += getLimbCount(slave, 6) * 2.5; - if (hasBothLegs(slave) && !canStand(slave)) { - deadliness -= 20; - } - - if (!canSee(slave)) { - deadliness -= 8; - } else if (!canSeePerfectly(slave)) { - deadliness -= 1; - } - - if (!canHear(slave)) { - deadliness -= 4; - } else if ((slave.hears === -1 && slave.earwear !== "hearing aids") || (slave.hears === 0 && slave.earwear === "muffling ear plugs")) { - deadliness -= 1; - } - - if (slave.tail === "combat") { - deadliness += 2; - } - - if (slave.health.tired > 90) { - deadliness -= 10; - } else if (slave.health.tired > 60) { - deadliness -= 3; - } else if (slave.health.tired > 30) { - deadliness -= 1; - } - - return Math.max(deadliness, 1); -}; - -/** Is the slave ready to retire? - * @param {App.Entity.SlaveState} slave - * @returns {boolean} - */ -globalThis.retirementReady = function(slave) { - // indentured slaves don't retire, they expire - if (slave.indenture >= 0) { - return false; - } - - // retirement by age - if (V.policies.retirement.physicalAgePolicy === 0 && slave.actualAge >= V.retirementAge) { - return true; - } else if (V.policies.retirement.physicalAgePolicy === 1 && slave.physicalAge >= V.retirementAge) { - return true; - } - - // retirement by milestone - if (V.policies.retirement.sex > 0 && (slave.counter.oral + slave.counter.anal + slave.counter.vaginal + slave.counter.penetrative + slave.counter.mammary) > V.policies.retirement.sex) { - return true; - } - if (V.policies.retirement.milk > 0 && slave.counter.milk > V.policies.retirement.milk) { - return true; - } - if (V.policies.retirement.cum > 0 && slave.counter.cum > V.policies.retirement.cum) { - return true; - } - if (V.policies.retirement.births > 0 && slave.counter.births > V.policies.retirement.births) { - return true; - } - if (V.policies.retirement.kills > 0 && slave.counter.pitKills > V.policies.retirement.kills) { - return true; - } - - // no retirement for you - return false; -}; - -/** marks some weeks of time passage for a slave, counting birthdays and invoking aging if game settings require it - * @param {App.Entity.SlaveState} slave - * @param {number} [weeks=1] - */ -globalThis.ageSlaveWeeks = function(slave, weeks = 1) { - if (V.seeAge !== 0) { // birthdays enabled - for (let i = 0; i < weeks; ++i) { - slave.birthWeek++; - if (slave.birthWeek >= 52) { - slave.birthWeek = 0; - if (V.seeAge === 1) { // actual aging enabled - ageSlave(slave); - } - } - } - } -}; - -/** advances the age of a slave by one year, incurring all aging side effects - * @param {App.Entity.SlaveState} slave - * @param {boolean} [forceDevelopment=false] - */ -globalThis.ageSlave = function(slave, forceDevelopment = false) { - slave.physicalAge++; - slave.actualAge++; - if (slave.geneMods.NCS === 1 || (slave.geneticQuirks.neoteny >= 2 && slave.geneticQuirks.progeria !== 2)) { - /* Induced NCS completely takes over visual aging. Additionally, because of the neoteny aspects of NCS, ovaries don't age quite as fast. */ - /* Unsurprisingly, actual neoteny has the same effect as long as progeria isn't in play. */ - slave.ovaryAge += either(0.5, 0.6, 0.7, 0.7, 0.8, 0.9, 1.0); - } else { - slave.visualAge++; - slave.ovaryAge += either(0.8, 0.9, 0.9, 1.0, 1.0, 1.0, 1.1); - } - if (slave.broodmother === 1) { - slave.ovaryAge += 0.2; - } - if (slave.physicalAge <= 18 && (forceDevelopment || V.loliGrow > 0)) { - physicalDevelopment(slave); - } -}; - -/** Is the slave a shelter slave? - * @param {App.Entity.SlaveState} slave - * @returns {boolean} - */ -globalThis.isShelterSlave = function(slave) { - return (typeof slave.origin === "string" && slave.origin.includes("Slave Shelter")); -}; - -/** - * Returns if a slave appears male, female, or androgynous. - * - * @param {App.Entity.SlaveState} slave - * @returns {number} - */ -globalThis.perceivedGender = function(slave) { - return -1; -}; - globalThis.initRules = function() { const rule = emptyDefaultRule(); rule.name = "Obedient Slaves"; diff --git a/src/js/utilsSlave.js b/src/js/utilsSlave.js index e2abcde7e02..6cfb49ee8a6 100644 --- a/src/js/utilsSlave.js +++ b/src/js/utilsSlave.js @@ -1,5 +1,3 @@ -/* contains functions that rely on FC specific variables/conventions */ -/* eslint-disable no-unused-vars */ /* * Height.mean(nationality, race, genes, age) - returns the mean height for the given combination and age in years (>=2) * Height.mean(nationality, race, genes) - returns the mean adult height for the given combination @@ -2277,4 +2275,1482 @@ globalThis.deflate = function(slave) { globalThis.getExposure = function(slave) { const clothes = App.Data.clothes.get(slave.clothes); return (clothes.topless && clothes.exposure < 3 && (slave.boobs > 299 || (slave.genes === 'XX' && slave.vagina >= 0))) ? 3 : clothes.exposure; +}; + +/** + * @param {App.Entity.SlaveState} A + * @param {App.Entity.SlaveState} B + * @returns {boolean} + */ +globalThis.sameAssignmentP = function(A, B) { + return A.assignment === B.assignment; +}; + +/** + * @param {App.Entity.SlaveState} slave + * @returns {boolean} + */ +globalThis.canImproveIntelligence = function(slave) { + let origIntel = V.genePool.find(function(s) { return s.ID === slave.ID; }).intelligence; + return (slave.intelligence < origIntel + 15) && (slave.intelligence < 100); +}; + +/** + * @param {App.Entity.SlaveState} slave + * @returns {number} + */ +globalThis.maxHeight = function(slave) { + let max = Math.trunc(Math.clamp((Height.mean(slave) * 1.25), 0, 274)); /* max achievable height is expected height plus 25% */ + + if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2) { + max = Math.min(max, 160); + } + + return max; +}; + +/** + * @param {App.Entity.SlaveState} slave + * @returns {boolean} + */ +globalThis.canImproveHeight = function(slave) { + return slave.height < maxHeight(slave); +}; + +/** + * @param {App.Entity.SlaveState} slave + * @param {FC.HumanState} target + * @returns {boolean} + */ +globalThis.haveRelationshipP = function(slave, target) { + return slave.relationshipTarget === target.ID; +}; + +/** + * @param {App.Entity.SlaveState} slave + * @param {App.Entity.SlaveState} target + * @returns {boolean} + */ +globalThis.isRivalP = function(slave, target) { + return slave.rivalryTarget === target.ID; +}; + +/** + * @param {FC.HumanState} slave + * @returns {boolean} + */ +globalThis.supremeRaceP = function(slave) { + return V.arcologies[0].FSSupremacistRace === slave.race; +}; + +/** + * @param {FC.HumanState} slave + * @returns {boolean} + */ +globalThis.inferiorRaceP = function(slave) { + return V.arcologies[0].FSSubjugationistRace === slave.race; +}; + +/** + * @param {App.Entity.SlaveState} slave + * @returns {boolean} + */ +globalThis.isLeaderP = function(slave) { + const leaders = [S.HeadGirl, S.Bodyguard, S.Recruiter, S.Concubine, S.Nurse, S.Attendant, S.Matron, S.Madam, S.DJ, S.Milkmaid, S.Farmer, S.Stewardess, S.Schoolteacher, S.Wardeness]; + + return leaders.some(leader => leader && leader.ID === slave.ID); +}; + +/** + * colors skin, eyes and hair based on genetic Color. + * Takes .override_*_Color into account. + * + * @param {App.Entity.SlaveState} slave + */ +globalThis.applyGeneticColor = function(slave) { + if (slave.override_Eye_Color !== 1) { + resetEyeColor(slave, "both"); + } + if (slave.override_H_Color !== 1) { + slave.hColor = getGeneticHairColor(slave); + } + if (slave.override_Arm_H_Color !== 1) { + slave.underArmHColor = getGeneticHairColor(slave); + } + if (slave.override_Pubic_H_Color !== 1) { + slave.pubicHColor = getGeneticHairColor(slave); + } + if (slave.override_Brow_H_Color !== 1) { + slave.eyebrowHColor = getGeneticHairColor(slave); + } + if (slave.override_Skin !== 1) { + if (!(slave.skin === "sun tanned" || slave.skin === "spray tanned")) { + slave.skin = getGeneticSkinColor(slave); + } + } +}; + +/** + * @param {FC.GingeredSlave} slave + */ +globalThis.newSlave = function(slave) { + if (getSlave(slave.ID)) { + throw "Slave already exists"; + } + + // if the slave is gingered, remove the gingering proxy + if (slave.beforeGingering) { + slave = slave.beforeGingering; + } + + if (slave.override_Race !== 1) { + slave.origRace = slave.race; + } + + applyGeneticColor(slave); + + /* eslint-disable camelcase */ + slave.override_Race = 0; + slave.override_H_Color = 0; + slave.override_Arm_H_Color = 0; + slave.override_Pubic_H_Color = 0; + slave.override_Brow_H_Color = 0; + slave.override_Skin = 0; + slave.override_Eye_Color = 0; + /* eslint-enable camelcase */ + + // too tall to be a dwarf catch for event slaves + if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2 && slave.height > 165) { + slave.geneticQuirks.dwarfism = 1; + } + + if (V.surnamesForbidden === 1) { + slave.slaveSurname = 0; + } + + if (slave.preg > 0) { + slave.pregWeek = slave.preg; + } else { + slave.pregWeek = 0; + } + + if (slave.clone !== 0) { + slave.canRecruit = 0; + } + + slave.sisters = 0; + slave.daughters = 0; + if (slave.mother === -1 || slave.father === -1) { + V.PC.daughters += 1; + } + if (areSisters(V.PC, slave) > 0) { + V.PC.sisters += 1; + } + for (let k = 0; k < V.slaves.length; k++) { + if (V.slaves[k].mother === slave.ID || V.slaves[k].father === slave.ID) { + slave.daughters++; + } + if (slave.mother === V.slaves[k].ID || slave.father === V.slaves[k].ID) { + V.slaves[k].daughters++; + } + if (areSisters(V.slaves[k], slave) > 0) { + slave.sisters++; + V.slaves[k].sisters++; + } + } + + if (slave.genes === "XX") { + if (slave.pubertyXX === 1) { + if (slave.pubertyXY === 1) { + slave.hormoneBalance = 20; + } else { + slave.hormoneBalance = 60; + } + } else { + if (slave.pubertyXY === 1) { + slave.hormoneBalance = -20; + } else { + slave.hormoneBalance = 20; + } + } + } else if (slave.genes === "XY") { + if (slave.pubertyXX === 1) { + if (slave.pubertyXY === 1) { + slave.hormoneBalance = 20; + } else { + slave.hormoneBalance = 40; + } + } else { + if (slave.pubertyXY === 1) { + slave.hormoneBalance = -40; + } else { + slave.hormoneBalance = 20; + } + } + } + + if (slave.dick > 0 && + slave.balls > 0 && + slave.vagina < 0 && + slave.anus === 0 && + slave.genes === "XY" && + slave.faceShape === "masculine" && + slave.attrXY <= 35 && + slave.boobs < 400 && + slave.hormoneBalance < 0) { + V.REFeminizationCheckinIDs.push(slave.ID); + } + if (slave.actualAge > 35 && slave.face <= 10 && slave.faceImplant === 0 && slave.energy <= 60) { + V.REMILFCheckinIDs.push(slave.ID); + } + if (slave.attrXY <= 35 && slave.attrXX > 65) { + V.REOrientationCheckinIDs.push(slave.ID); + } + if (slave.face < -10) { + V.REUglyCheckinIDs.push(slave.ID); + } + if (slave.anus < 2) { + V.REButtholeCheckinIDs.push(slave.ID); + } + if (slave.boobs < 800) { + V.REReductionCheckinIDs.push(slave.ID); + } + + generatePronouns(slave); + SetBellySize(slave); + V.slaveIndices[slave.ID] = V.slaves.push(slave) - 1; + + if (slave.origin !== "$He was your slave, but you freed $him, which $he repaid by participating in a coup attempt against you. It failed, and $he is again your chattel." && slave.ID !== V.boomerangSlave.ID) { + V.genePool.push(clone(slave)); + } else { + if (!V.genePool.some(s => s.ID === slave.ID)) { + V.genePool.push(slave); + } + } + + /* special case for dulling intelligence via drugs in slave acquisition */ + if (slave.dullIntelligence) { + slave.intelligence = -100; + delete slave.dullIntelligence; + } + + if (slave.assignment) { + assignJob(slave, slave.assignment); + } else { + slave.assignment = Job.CHOICE; + } + + /** do not run the Rules Assistant before adding the new slave to the slaves list! **/ + if (V.ui !== "start" && V.universalRulesNewSlavesRA === 1 && V.rulesAssistantAuto !== 0) { + DefaultRules(slave); + } +}; + +/** Get the written title for a given slave, without messing with global state. + * @param {App.Entity.SlaveState} [slave] + * @returns {string} + */ +globalThis.getWrittenTitle = function(slave) { + if (slave && slave.custom.title !== undefined && slave.custom.title !== "" && slave.rudeTitle === 0) { + return slave.custom.title; + } + if (V.PC.customTitle !== undefined) { + return V.PC.customTitle; + } else if (V.PC.title !== 0) { + return "Master"; + } else { + return "Mistress"; + } +}; + +/** + * @param {App.Entity.SlaveState} slave + * @returns {number} + */ +globalThis.fetishChangeChance = function(slave) { + let chance = 0, + fetish = (slave.fetishStrength / 4), + sex = 0; + + if (slave.clitSetting !== slave.fetish) { + // fetish should be more uncertain leading towards puberty and then steadily become more set in stone afterwards + if (slave.balls) { + if (V.potencyAge >= slave.actualAge) { + sex = (50 - ((V.potencyAge - slave.actualAge) * 10)); + fetish = (slave.fetishStrength / 2); + } else { + sex = ((slave.actualAge - V.potencyAge) / 4); + } + } else if (slave.ovaries || slave.mpreg) { + if (V.fertilityAge >= slave.actualAge) { + sex = (50 - ((V.fertilityAge - slave.actualAge) * 10)); + fetish = (slave.fetishStrength / 2); + } else { + sex = ((slave.actualAge - V.fertilityAge) / 4); + } + } + chance = Math.trunc(Math.clamp((slave.devotion / 4) - (fetish) - (sex), 0, 100)); + } + + return chance; +}; + +/** + * @param {App.Entity.SlaveState} slave + * @returns {string} + */ +globalThis.SlaveFullName = function(slave) { + const pair = slave.slaveSurname ? [slave.slaveName, slave.slaveSurname] : [slave.slaveName]; + if ((V.surnameOrder !== 1 && ["Cambodian", "Chinese", "Hungarian", "Japanese", "Korean", "Mongolian", "Taiwanese", "Vietnamese"].includes(slave.nationality)) || (V.surnameOrder === 2)) { + pair.reverse(); + } + return pair.join(" "); +}; + +/** + * @param {App.Entity.SlaveState} slave + * @returns {string} + */ +globalThis.SlaveFullBirthName = function(slave) { + const pair = slave.birthSurname ? [slave.birthName, slave.birthSurname] : [slave.birthName]; + if ((V.surnameOrder !== 1 && ["Cambodian", "Chinese", "Hungarian", "Japanese", "Korean", "Mongolian", "Taiwanese", "Vietnamese"].includes(slave.nationality)) || (V.surnameOrder === 2)) { + pair.reverse(); + } + return pair.join(" "); +}; + +/** + * @param {App.Entity.SlaveState} slave + * @returns {string} + */ +globalThis.PoliteRudeTitle = function(slave) { + const PC = V.PC; + const {s, ss, title} = getEnunciation(slave); + + let r = ""; + if (slave.nationality === "Japanese") { + if (slave.trust > 0) { + r += `${PC.slaveName}${PC.title > 0 ? "kun" : "chan"}`; + } else { + r += (PC.slaveSurname ? PC.slaveSurname : `${PC.slaveName}${s}an`); + } + } else { + if (slave.intelligence + slave.intelligenceImplant < -95) { + r += title; + } else if (slave.intelligence + slave.intelligenceImplant > 50) { + r += (PC.title > 0 ? `Ma${s}ter` : `Mi${s}tre${ss}`); + } else if (slave.trust > 0) { + r += PC.slaveName; + } else { + r += (PC.slaveSurname ? PC.slaveSurname : PC.slaveName); + } + } + return r; +}; + +/** + * @param {App.Entity.SlaveState} slave + * @returns {string} + */ +globalThis.SlaveTitle = function(slave) { + let r; + if (V.newDescriptions === 1) { + if (slave.dick > 0 && slave.balls > 0 && slave.boobs > 300 && slave.vagina > -1 && slave.ovaries === 1) { + if (jsRandom(1, 100) > 50) { + r = "futanari"; + } else { + r = "herm"; + } + } else if (slave.dick > 0 && slave.balls === 0 && slave.boobs > 300 && slave.vagina > -1 && slave.ovaries === 1) { + r = "dickgirl"; + } else if (slave.dick > 0 && slave.vagina > -1 && slave.ovaries === 0) { + r = "shemale"; + } else if (slave.dick > 0 && slave.balls === 0 && slave.vagina === -1 && slave.ovaries === 0) { + r = "eunuch"; + } else if (slave.dick > 0 && slave.balls > 0 && slave.vagina === -1 && slave.ovaries === 0) { + if (slave.face > 10 && slave.hips > -1 && slave.shoulders < 1 && slave.faceShape !== "masculine") { + r = "trap"; + } else if (slave.boobs > 800) { + r = "tittyboy"; + } else if (slave.dick === 1 && slave.balls === 1) { + r = "sissy"; + } else if (slave.dick > 1 && slave.balls > 1 && slave.height < 165 && slave.muscles < 5 && slave.visualAge < 19 && slave.faceShape !== "masculine") { + r = "twink"; + } else if (slave.dick > 1 && slave.balls > 1 && slave.height < 160 && slave.muscles < 5 && slave.visualAge < 19) { + r = "boytoy"; + } else if (slave.muscles > 95 && slave.height >= 185) { + r = "titan"; + } else if (slave.muscles > 30) { + r = "muscleboy"; + } else { + r = "slaveboy"; + } + } else if (slave.dick === 0 && slave.balls === 0 && slave.vagina > -1) { + if ((slave.shoulders > slave.hips || slave.faceShape === "masculine") && slave.boobs < 400 && slave.genes === "XY") { + r = "cuntboy"; + } else if (slave.ovaries === 0 && slave.genes === "XY") { + r = "tranny"; + } else if (slave.weight > 10 && slave.boobs > 800 && slave.counter.birthsTotal > 0 && slave.physicalAge > 59) { + r = "GMILF"; + } else if (slave.weight > 10 && slave.boobs > 800 && slave.counter.birthsTotal > 0 && slave.physicalAge > 35) { + r = "MILF"; + } else if (slave.lips > 70 && slave.boobs > 2000 && slave.butt > 3) { + r = "bimbo"; + } else if (slave.hips > 1 && slave.boobs > 2000 && slave.butt > 3 && slave.waist < 50) { + r = "hourglass"; + } else if (slave.muscles > 95 && slave.height >= 185) { + r = "amazon"; + } else if (slave.muscles > 30) { + r = "musclegirl"; + } else { + r = "slavegirl"; + } + } else if (slave.dick === 0 && slave.balls === 0 && slave.vagina === -1) { + r = "neuter"; + } else if (slave.dick === 0 && slave.vagina === -1) { + r = "ballslave"; + } else { + r = "slave"; + } + + if (slave.visualAge < 13) { + if (slave.actualAge < 3) { + if (slave.actualAge < 1) { + r = "baby " + r; + } else { + r = "toddler " + r; + } + } else { + if (slave.genes === "XY" && slave.vagina === -1) { + r = "shota " + r; + } else { + r = "loli " + r; + } + } + } + + if (slave.geneticQuirks.albinism === 2) { + r = `albino ${r}`; + } + + if (slave.dick > 9 && slave.balls > 9 && slave.boobs > 12000) { + r = `hyper ${r}`; + } + + if (slave.boobs > 4000 && slave.lactation > 0) { + if (slave.physicalAge < 13) { + r = `${r} calf`; + } else { + r = `${r} cow`; + } + } else if (slave.lactation > 0) { + r = `milky ${r}`; + } + + if (slave.boobs > 20000) { + r = `supermassive titted ${r}`; + } else if (slave.boobs > 10000) { + r = `giant titted ${r}`; + } else if (slave.boobs > 4000) { + r = `huge titted ${r}`; + } else if (slave.boobs > 1000) { + r = `busty ${r}`; + } + + if (slave.dick > 5 && slave.balls > 5) { + r = `womb filling ${r}`; + } else if (slave.dick > 5) { + r = `well hung ${r}`; + } + + if (slave.butt >= 12) { + r = `colossal assed ${r}`; + } else if (slave.butt >= 10) { + r = `massive assed ${r}`; + } else if (slave.butt >= 8) { + r = `fat assed ${r}`; + } else if (slave.butt >= 6) { + r = `bottom heavy ${r}`; + } else if (slave.butt >= 4) { + r = `big bottomed ${r}`; + } + + if (slave.weight > 10 && slave.weight < 100 && slave.boobs > 5000 && slave.butt > 5 && slave.hips >= 2 && slave.bellyPreg >= 30000 && slave.counter.births >= 10) { + r = `${r} fertility goddess`; + } else if (slave.counter.births >= 6) { + r = `${r} broodmother`; + } else if (slave.counter.births >= 3) { + r = `${r} breeder`; + } + + if (slave.indenture > -1) { + r = `indentured ${r}`; + } + + if (slave.preg > slave.pregData.normalBirth / 4 && slave.pregKnown === 1) { + r = `pregnant ${r}`; + } else if (slave.bellyFluid >= 5000) { + r = `bloated ${r}`; + } else if (slave.belly >= 5000) { + r = `gravid ${r}`; + } + + if (slave.fuckdoll > 0) { + r = `${r} fuckdoll`; + } + } else { + r = "slave"; /* I don't think there is an 'else'? */ + if ((slave.dick === 0) && (slave.vagina === -1)) { + /* NULLS */ + r = "null"; + if ((slave.lactation > 0) && (slave.boobs > 2000)) { + r = `${r} cow`; + } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { + r = `${r} bimbo `; + } else if (slave.boobs > 6000) { + r = `${r} boob`; + } else if (slave.butt > 6) { + r = `${r} ass`; + } else if ((slave.muscles > 30) && (slave.height < 185)) { + r = `${r} muscle`; + } + if (slave.visualAge > 55) { + r = `${r}GILF`; + } else if (slave.visualAge > 35) { + r = `${r}MILF`; + } else if (slave.visualAge >= 25) { + r = `${r}slave`; + } else { + r = `${r}girl`; + } + } + + if ((slave.dick === 0) && (slave.vagina !== -1)) { + /* FEMALES */ + if (slave.visualAge > 55) { + r = "GILF"; + } else if (slave.visualAge > 35) { + r = "MILF"; + } else if (slave.visualAge >= 25) { + r = "slave"; + } else { + r = "slavegirl"; + } + if ((slave.muscles > 30) && (slave.height < 185)) { + r = `muscle ${r}`; + } else if ((slave.lactation > 0) && (slave.boobs > 2000)) { + r = `${r} cow`; + } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { + r = `${r} bimbo`; + } else if (slave.boobs > 6000) { + r = `boob${r}`; + } else if (slave.butt > 6) { + r = `ass${r}`; + } + } + + if ((slave.dick !== 0) && (slave.vagina !== -1)) { + if (slave.balls > 0) { + /* FUTANARI: cock & balls & vagina */ + r = "futanari "; + } else { + /* FUTANARI: cock & vagina */ + r = "futa "; + } + if ((slave.lactation > 0) && (slave.boobs > 2000)) { + r = `${r}cow`; + } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { + r = `${r}bimbo `; + } else if (slave.boobs > 6000) { + r = `${r}boob`; + } else if (slave.butt > 6) { + r = `${r}ass`; + } else if ((slave.muscles > 30) && (slave.height < 185)) { + r = `${r}muscle`; + } + if (slave.visualAge > 55) { + r = `${r}GILF`; + } else if (slave.visualAge > 35) { + r = `${r}MILF`; + } else if (slave.visualAge >= 25) { + r = `${r}slave`; + } else { + r = `${r}girl`; + } + if (slave.dick > 5 && slave.balls > 5 && slave.boobs > 5000) { + r = `hyper ${r}`; + } + } + + if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls > 0) && (slave.boobs > 300) && (slave.butt > 2)) { + /* SHEMALES: cock & balls, T&A above minimum */ + if (slave.visualAge > 55) { + r = "sheGILF"; + } else if (slave.visualAge > 35) { + r = "sheMILF"; + } else if (slave.visualAge >= 25) { + r = "shemale"; + } else { + r = "tgirl"; + } + if ((slave.muscles > 30) && (slave.height < 185)) { + r = `muscle${r}`; + } else if ((slave.lactation > 0) && (slave.boobs > 2000)) { + r = `${r} cow`; + } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { + r = `${r} bimbo`; + } else if (slave.boobs > 6000) { + r = `topheavy ${r}`; + } else if (slave.butt > 6) { + r = `bottomheavy ${r}`; + } + } + + if ((slave.boobs < 300) || (slave.butt < 2)) { + if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls > 0)) { + if ((slave.shoulders < 1) || (slave.muscles <= 30)) { + if ((slave.faceShape === "masculine") || (slave.faceShape === "androgynous")) { + /* SISSIES: feminine shoulders or muscles, masculine faces */ + if (slave.visualAge > 55) { + r = "sissyGILF"; + } else if (slave.visualAge > 35) { + r = "sissyMILF"; + } else { + r = "sissy"; + } + } else { + /* TRAPS: feminine shoulders or muscles, feminine faces */ + if (slave.visualAge > 55) { + r = "trapGILF"; + } else if (slave.visualAge > 35) { + r = "trapMILF"; + } else if (slave.visualAge >= 25) { + r = "trap"; + } else { + r = "trapgirl"; + } + } + if (slave.lactation > 0) { + r = `${r} cow`; + } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { + r = `${r} bimbo`; + } + } + } + } + + if ((slave.boobs < 300) || (slave.butt < 2)) { + if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls > 0)) { + if ((slave.shoulders > 1) || (slave.muscles >= 30)) { + /* BITCHES: masculine shoulders or muscles */ + r = "bitch"; + if ((slave.muscles > 30) && (slave.height < 185)) { + r = `muscle${r}`; + } else if (slave.lactation > 0) { + r = `${r}cow`; + } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { + r = `bimbo ${r}`; + } + if (slave.visualAge > 55) { + r = `aged ${r}`; + } else if (slave.visualAge > 35) { + r = `mature ${r}`; + } else if (slave.visualAge < 25) { + r = `young ${r}`; + } + } + } + } + + if ((slave.dick !== 0) && (slave.vagina === -1) && (slave.balls === 0)) { + r = "dick"; + if (slave.visualAge > 55) { + r = `${r}GILF`; + } else if (slave.visualAge > 35) { + r = `${r}MILF`; + } else if (slave.visualAge >= 25) { + r = `${r}slave`; + } else { + r = `${r}girl`; + } + if ((slave.muscles > 30) && (slave.height < 185)) { + r = `muscle${r}`; + } else if ((slave.lactation > 0) && (slave.boobs > 2000)) { + r = `${r} cow`; + } else if ((slave.boobsImplant > 0) && (slave.buttImplant > 0)) { + r = `${r} bimbo`; + } else if (slave.boobs > 6000) { + r = `boob ${r}`; + } else if (slave.butt > 6) { + r = `ass ${r}`; + } + } + + if ((slave.muscles > 30) && (slave.height > 185)) { + r = `amazon ${r}`; + } else if ((slave.muscles < 30) && (slave.height > 185)) { + r = `statuesque ${r}`; + } else if ((slave.boobs < 800) && (slave.height < 150)) { + r = `petite ${r}`; + } else if ((slave.boobs > 800) && (slave.height < 150)) { + r = `shortstack ${r}`; + } + + if (slave.counter.births >= 5) { + r = `${r} broodmother`; + } else if (slave.counter.births >= 2) { + r = `${r} breeder`; + } + + if (slave.geneticQuirks.albinism === 2) { + r = `albino ${r}`; + } + + if (slave.indenture > -1) { + r = `indentured ${r}`; + } + + if (slave.preg > slave.pregData.normalBirth / 4 && slave.pregKnown === 1) { + r = `pregnant ${r}`; + } else if (slave.bellyFluid >= 5000) { + r = `bloated ${r}`; + } else if (slave.belly >= 5000) { + r = `gravid ${r}`; + } + + if (slave.fuckdoll > 0) { + r = `${r} fuckdoll`; + } + } + return r; +}; + +/** + * @param {App.Entity.SlaveState} slave + */ +globalThis.DegradingName = function(slave) { + const leadershipPosition = [ + Job.ATTENDANT, + Job.MATRON, + Job.STEWARD, + Job.MILKMAID, + Job.FARMER, + Job.DJ, + Job.CONCUBINE, + Job.MADAM, + Job.TEACHER, + Job.WARDEN, + Job.NURSE, + Job.HEADGIRL, + Job.BODYGUARD, + Job.RECRUITER + ]; + const names = []; + const suffixes = []; + + if (slave.fuckdoll > 0) { + slave.slaveName = `Fuckdoll No. ${slave.ID}`; + slave.slaveSurname = 0; + } else if (slave.assignment === Job.DAIRY && V.dairyRestraintsSetting >= 2) { + slave.slaveName = `Bioreactor No. ${slave.ID}`; + slave.slaveSurname = 0; + } else { + if (V.seeRace === 1) { + switch (slave.race) { + case "white": + names.push("Pale", "White"); + break; + case "asian": + names.push("Asian", "Yellow"); + break; + case "latina": + names.push("Brown", "Latina"); + break; + case "black": + names.push("Black", "Dark"); + break; + case "pacific islander": + names.push("Islander", "Pacific", "Sea"); + break; + case "malay": + names.push("Cinnamon", "Pinoy", "Spice"); + break; + case "southern european": + names.push("Mediterranean", "Olive"); + break; + case "amerindian": + names.push("Indian", "Reservation"); + break; + case "semitic": + names.push("Semite", "Semitic"); + break; + case "middle eastern": + names.push("Arab", "Sand"); + break; + case "indo-aryan": + names.push("Brown", "Indian"); + break; + case "mixed race": + names.push("Mixed", "Mulatto", "Mutt"); + break; + } + } + names.push(slave.hColor); + if (!hasAnyEyes(slave)) { + names.push("Blind", "Eyeless", "Sightless"); + } + if (slave.hears === -2) { + names.push("Deaf", "Earless", "Unhearing"); + } + if (slave.boobs >= 2000) { + suffixes.push("Boob", "Boobs", "Titty"); + } + if (slave.boobs < 500 && slave.butt < 3) { + names.push("Girly", "Slim", "Thin"); + } + if (slave.boobs < 300) { + names.push("Flat"); + } + if (slave.anus > 2 || slave.vagina > 2) { + names.push("Gaping", "Hallway", "Slit", "Wideopen"); + } + if (slave.weight > 160) { + names.push("Blimp", "Cow", "Fat", "Fatass", "Whale"); + } else if (slave.weight > 30) { + names.push("Chubby", "Fat", "Whale"); + } else if (slave.weight <= -30) { + names.push("Bony", "Rail", "Skinny"); + } + if (slave.muscles > 30) { + names.push("Huge", "Muscles", "Ripped", "Strong"); + } + if (slave.fetishKnown === 1) { + if (slave.fetish === "buttslut") { + names.push("Anal", "Sodomy"); + } + if (slave.fetish === "cumslut") { + names.push("Cum", "Dicksuck", "Sucker"); + } + if (slave.fetish === "humiliation") { + names.push("Rape"); + } + if (slave.fetish === "masochist") { + names.push("Pain", "Rape", "Struggle"); + } + if (slave.fetish === "pregnancy") { + names.push("Fertile"); + } + } + if (slave.boobs * slave.lactation > 1000) { + names.push("Creamy", "Milky"); + suffixes.push("Cow"); + } + if (slave.skill.oral <= 30 && slave.skill.anal <= 30) { + names.push("Cheap", "Fail", "Gutter"); + } + if (slave.nipples === "fuckable") { + names.push("Nipplefuck", "Nipplecunt"); + } else if (slave.nipples !== "tiny" && slave.nipples !== "cute") { + names.push("Pointy", "Titclit"); + suffixes.push("Nipples"); + } + if (slave.visualAge > 35) { + names.push("Mature"); + suffixes.push("Cougar", "MILF"); + } else if (slave.visualAge < 25) { + names.push("Girly", "Thin", "Young"); + } + if (isAmputee(slave)) { + names.push("Stumpy"); + suffixes.push("Stumpy"); + } + if (slave.boobsImplant > 1000 || slave.buttImplant > 3) { + names.push("Fake", "Plastic", "Silicone"); + } + if (slave.dick > 5 && slave.balls > 5) { + names.push("Potent"); + suffixes.push("Cannon", "Daddy"); + } + if (slave.preg > slave.pregData.normalBirth / 1.33) { + if (slave.broodmother === 2) { + names.push("Bursting", "Seeded"); + suffixes.push("Factory", "Nursery"); + } else if (slave.broodmother === 1) { + names.push("Bloated", "Stuffed"); + suffixes.push("Breeder", "Factory"); + } + } + if (slave.bellyPreg >= 450000) { + names.push("Bulging", "Squirming"); + } + if (slave.bellyPreg >= 5000) { + names.push("Preg"); + suffixes.push("Belly", "Mommy"); + } + if (slave.belly > 150000) { + suffixes.push("Balloon"); + } + if (slave.belly > 1500) { + suffixes.push("Belly"); + } + if (slave.dick > 0) { + if (slave.dick > 4) { + names.push("Dangle", "Hung"); + suffixes.push("Cock", "Dick"); + } + if (slave.balls === 0) { + names.push("Cut", "Gelded", "Soft"); + } else { + names.push("Erect", "Hard", "Stiff"); + } + } + if (slave.dick === 1) { + names.push("Micro", "Tiny"); + suffixes.push("Bitch"); + } + if (slave.height >= 185) { + names.push("Tall", "Top"); + suffixes.push("Tower"); + } else if (slave.height < 150) { + names.push("Stumpy", "Tiny"); + suffixes.push("Shortstack", "Stumpy"); + } + if (slave.skill.whoring > 95) { + names.push("Money", "Street"); + suffixes.push("Whore"); + } + if (slave.skill.entertainment > 95) { + names.push("Easy", "Club"); + suffixes.push("Slut"); + } + if (slave.skill.oral > 95) { + names.push("Suck"); + suffixes.push("Throat"); + } + if (slave.skill.vaginal > 95) { + suffixes.push("Channel", "Kegel", "Pussy"); + } + if (slave.skill.anal > 95) { + suffixes.push("Asspussy", "Sphincter"); + } + if (slave.intelligence + slave.intelligenceImplant > 50) { + names.push("Bright", "Clever", "Smart"); + if (slave.intelligenceImplant >= 15) { + names.push("College", "Graduate", "Nerdy"); + } + } else if (slave.intelligence + slave.intelligenceImplant < -50) { + names.push("Cretin", "Dumb", "Retarded", "Stupid"); + } + if (slave.vagina === 1 && slave.skill.vaginal <= 10) { + names.push("Fresh", "New", "Tight"); + } + if (slave.devotion < -75) { + names.push("Angry", "Biter", "Caged"); + } else if (slave.devotion < -50) { + names.push("Cell", "Cuffs"); + } else if (slave.devotion < -20) { + names.push("Bag", "Box"); + } else if (slave.devotion <= 20) { + names.push("Sad", "Whiner"); + } else if (slave.devotion > 50) { + names.push("Prize"); + if (slave.visualAge > 35) { + names.push("Queen"); + } else if (slave.visualAge < 25) { + names.push("Princess"); + } + } + if (slave.trust < -50) { + names.push("Screaming"); + suffixes.push("Sobber"); + } else if (slave.trust < -20) { + names.push("Crying"); + suffixes.push("Meat", "Tears", "Thing", "Weeper"); + } else if (slave.trust < 20) { + names.push("Begging"); + } + + if (slave.dick === 0) { + if (slave.vagina === -1) { + suffixes.push("Null"); + } else { + if (slave.visualAge < 25) { + suffixes.push("Girl"); + } + } + } else { + if (slave.vagina !== -1) { + suffixes.push("Futa"); + } else { + if (slave.balls > 0) { + if (slave.boobs > 300 && slave.butt > 2) { + /* SHEMALES: cock & balls, T&A above minimum */ + suffixes.push("Shemale"); + } else { + if (slave.shoulders < 1 && slave.muscles <= 30) { + if (slave.faceShape === "masculine" || slave.faceShape === "androgynous") { + /* SISSIES: feminine shoulders or muscles, masculine faces */ + suffixes.push("Sissy"); + } else { + /* TRAPS: feminine shoulders or muscles, feminine faces */ + suffixes.push("Trap"); + } + } else { + /* BITCHES: masculine shoulders or muscles */ + suffixes.push("Bitch"); + } + } + } else { + if (slave.visualAge > 35) { + suffixes.push("DickMILF"); + } else if (slave.visualAge >= 25) { + suffixes.push("Dickslave"); + } else { + suffixes.push("Dickgirl"); + } + } + } + } + if (slave.anus > 0) { + suffixes.push("Anus", "Asshole", "Backdoor", "Butt", "Butthole"); + } + if (slave.anus === 1) { + suffixes.push("Tightass", "Tightbutt"); + } + if (slave.vagina > 0) { + suffixes.push("Cunt", "Pussy", "Vagina"); + } + if (slave.boobs < 500 && slave.butt < 3 && slave.dick > 0) { + suffixes.push("Bitch", "Bottom", "Sissy", "Trap"); + } + if (slave.energy > 95) { + suffixes.push("Fuck", "Fuckaddict", "Nympho", "Sexaddict"); + } + if (slave.fetishKnown === 1) { + if (slave.fetish === "humiliation") { + suffixes.push("Rapebait", "Showgirl"); + } + if (slave.fetish === "submissive") { + suffixes.push("Bottom", "Fuckee", "Rapebait"); + } + if (slave.fetish === "dom") { + suffixes.push("Dom", "Fucker", "Top"); + } + if (slave.fetish === "pregnancy") { + suffixes.push("Breeder", "Mommy"); + } + if (slave.fetish === "boobs") { + suffixes.push("Boob", "Boobie", "Tit", "Titty"); + } + } + if (slave.counter.births >= 2) { + suffixes.push("Breeder"); + if (slave.counter.births >= 5) { + suffixes.push("Broodmother"); + } + } + if (slave.areolae > 2) { + suffixes.push("Areolas", "Headlights"); + } + if (slave.lips > 40) { + suffixes.push("Lips", "Pillows"); + } + if (slave.labia > 1) { + suffixes.push("Curtains", "Flower", "Lips"); + } + if (slave.breedingMark === 1 && V.propOutcome === 1 && V.arcologies[0].FSRestart !== "unset") { + suffixes.push("Breeder", "Oven", "Womb"); + } + if (slave.butt > 5) { + suffixes.push("Ass", "Bottom", "Butt"); + } + if (slave.vagina === 0) { + suffixes.push("Virgin"); + } + + slave.slaveName = jsEither(names); + } + if (leadershipPosition.includes(slave.assignment)) { + switch (slave.assignment) { + case Job.ATTENDANT: + slave.slaveName = jsEither(["Bath", "Spa"]); + break; + case Job.MATRON: + slave.slaveName = jsEither(["Matron", "Nursery"]); + break; + case Job.STEWARD: + slave.slaveName = jsEither(["Maid", "Servant"]); + break; + case Job.MILKMAID: + if (V.cumSlaves > 3) { + slave.slaveName = jsEither(["Fucker", "Milker"]); + } else { + slave.slaveName = jsEither(["Dairy", "Farm"]); + } + break; + case Job.FARMER: + slave.slaveName = jsEither(["Farmer", "Farmhand"]); + break; + case Job.DJ: + slave.slaveName = jsEither(["Bass", "Booth"]); + break; + case Job.CONCUBINE: + slave.slaveName = jsEither(["Bed", "Master"]); + break; + case Job.MADAM: + slave.slaveName = jsEither(["Madam", "Pimp"]); + break; + case Job.TEACHER: + slave.slaveName = jsEither(["Classroom", "Teacher"]); + break; + case Job.WARDEN: + slave.slaveName = jsEither(["Jail", "Prison"]); + break; + case Job.NURSE: + slave.slaveName = jsEither(["Clinic", "Nurse"]); + break; + case Job.HEADGIRL: + slave.slaveName = jsEither(["Chief", "Head"]); + break; + case Job.BODYGUARD: + slave.slaveName = jsEither(["Battle", "Guard"]); + break; + case Job.RECRUITER: + slave.slaveName = jsEither(["Cam", "Recruiter"]); + break; + } + } + const surname = jsEither(suffixes); + if (typeof surname === "string" && surname.toLowerCase() === slave.slaveName.toLowerCase()) { + DegradingName(slave); + } + slave.slaveName = capFirstChar(slave.slaveName); + slave.slaveSurname = surname; +}; + +globalThis.PaternalistName = function(slave) { + if (slave.slaveName.search("Miss") === -1) { + if (slave.slaveName.search("Ms.") === -1) { + if (slave.slaveName.search("Mrs.") === -1) { + if (slave.relationship > 4) { + slave.slaveName = ("Mrs. " + slave.slaveName); + } else if (slave.actualAge > 24) { + slave.slaveName = ("Ms. " + slave.slaveName); + } else { + slave.slaveName = ("Miss " + slave.slaveName); + } + } + } + } +}; + +globalThis.parentNames = function(parent, child) { + const slaves = V.slaves; + + let currentSlaveNames = slaves.map(s => s.slaveName); + let continentNationality; + const useMaleName = (child.genes === "XY" && V.allowMaleSlaveNames === true); + + child.slaveName = generateName(parent.nationality, child.race, useMaleName, sn => !currentSlaveNames.includes(sn)); + + if (!child.slaveName) { + for (let i = 0; i < 10; i++) { + continentNationality = hashChoice(V.nationalities); + child.slaveName = generateName(continentNationality, child.race, useMaleName, sn => !currentSlaveNames.includes(sn)); // jshint ignore: line + } + } + if (!child.slaveName) { + child.slaveName = generateName(parent.nationality, child.race, useMaleName); + } +}; + +/** + * @param {App.Entity.SlaveState} slave + * @param {number} amount + * @returns {string} + */ +globalThis.faceIncrease = function(slave, amount) { + const pronouns = getPronouns(slave); + const his = pronouns.possessive; + const His = capFirstChar(his); + let r = ""; + if (slave.face <= -95) { + r += `<span class="green">${His} face is no longer horrifying,</span> and is now merely ugly.`; + } else if (slave.face <= -40 && slave.face + amount > -40) { + r += `<span class="green">${His} face is no longer ugly,</span> and is now merely unattractive.`; + } else if (slave.face <= -10 && slave.face + amount > -10) { + r += `<span class="green">${His} face is no longer unattractive,</span> and is now somewhat tolerable.`; + } else if (slave.face <= 10 && slave.face + amount > 10) { + r += `<span class="green">${His} face is now decently attractive,</span> rather than merely tolerable.`; + } else if (slave.face <= 40 && slave.face + amount > 40) { + r += `<span class="green">${His} face is now quite beautiful,</span> rather than merely pretty.`; + } else if (slave.face <= 95 && slave.face + amount > 95) { + r += `<span class="green">${His} face is now perfect.</span> It's difficult to imagine how it could be any more beautiful.`; + } + slave.face = Math.clamp(slave.face + amount, -100, 100); + if (slave.face > 95) { + slave.face = 100; + } + return r; +}; + +/** + * @param {App.Entity.SlaveState} slave + * @returns {number} + */ +globalThis.deadliness = function(slave) { + let deadliness = 2; + + if (slave.skill.combat > 0) { + deadliness += 2; + } + + if (App.Data.Careers.Leader.bodyguard.includes(slave.career)) { + deadliness += 1; + } else if (slave.skill.bodyguard >= V.masteredXP) { + deadliness += 1; + } + + if (V.AgePenalty !== 0) { + if (slave.physicalAge >= 100) { + deadliness -= 10; + } else if (slave.physicalAge >= 85) { + deadliness -= 3; + } else if (slave.physicalAge >= 70) { + deadliness -= 1; + } + } + + if (slave.muscles > 30 && slave.muscles <= 95) { + deadliness += 1; + } else if (slave.muscles > 95 && slave.height >= 185) { + deadliness += 2; + } else if (slave.muscles > 95) { + deadliness -= 1; + } else if (slave.muscles < -95) { + deadliness -= 20; + } else if (slave.muscles < -30) { + deadliness -= 7; + } else if (slave.muscles < -5) { + deadliness -= 3; + } + + if (slave.height >= 170) { + deadliness += 1; + } + + if (slave.health.condition > 50) { + deadliness += 1; + } else if (slave.health.condition < -50) { + deadliness -= 1; + } + + if (slave.health.illness > 3) { + deadliness -= 3; + } else if (slave.health.illness > 1) { + deadliness -= 2; + } else if (slave.health.illness > 0) { + deadliness -= 1; + } + + if (slave.boobs > 4000) { + deadliness -= 2; + } else if (slave.boobs > 2000) { + deadliness -= 1; + } + + if (slave.butt > 6) { + deadliness -= 1; + } + + if (slave.hips > 2) { + deadliness -= 1; + } + + if (slave.weight > 190) { + deadliness -= 20; + } else if (slave.weight > 160) { + deadliness -= 10; + } else if (slave.weight > 130) { + deadliness -= 3; + } else if (slave.weight > 30 || slave.weight < -10) { + deadliness -= 1; + } + + if (slave.bellyFluid >= 10000) { + deadliness -= 3; + } else if (slave.bellyFluid >= 5000) { + deadliness -= 2; + } else if (slave.bellyFluid >= 2000) { + deadliness -= 1; + } + + if (slave.pregKnown === 1 || slave.bellyPreg >= 1500 || slave.bellyImplant >= 1500) { + if (slave.belly >= 750000) { + deadliness -= 50; + } else if (slave.belly >= 600000) { + deadliness -= 25; + } else if (slave.belly >= 450000) { + deadliness -= 15; + } else if (slave.belly >= 300000) { + deadliness -= 10; + } else if (slave.belly >= 150000) { + deadliness -= 8; + } else if (slave.belly >= 100000) { + deadliness -= 7; + } else if (slave.belly >= 10000) { + deadliness -= 3; + } else if (slave.belly >= 5000) { + deadliness -= 2; + } else { + deadliness -= 1; + } + } + + if (isInLabor(slave)) { + deadliness -= 15; + } else if (slave.preg >= slave.pregData.normalBirth && slave.pregControl !== "labor suppressors") { + deadliness -= 5; + } + + if (slave.balls >= 15) { + deadliness -= 1; + } + + if (slave.dick >= 10) { + deadliness -= 1; + } + + deadliness -= getLimbCount(slave, 0) * 5; + deadliness -= getLimbCount(slave, 2) * 0.25; + deadliness -= getLimbCount(slave, 3) * 0.25; + deadliness -= getLimbCount(slave, 4) * 0.25; + deadliness += getLimbCount(slave, 5) * 1.25; + deadliness += getLimbCount(slave, 6) * 2.5; + if (hasBothLegs(slave) && !canStand(slave)) { + deadliness -= 20; + } + + if (!canSee(slave)) { + deadliness -= 8; + } else if (!canSeePerfectly(slave)) { + deadliness -= 1; + } + + if (!canHear(slave)) { + deadliness -= 4; + } else if ((slave.hears === -1 && slave.earwear !== "hearing aids") || (slave.hears === 0 && slave.earwear === "muffling ear plugs")) { + deadliness -= 1; + } + + if (slave.tail === "combat") { + deadliness += 2; + } + + if (slave.health.tired > 90) { + deadliness -= 10; + } else if (slave.health.tired > 60) { + deadliness -= 3; + } else if (slave.health.tired > 30) { + deadliness -= 1; + } + + return Math.max(deadliness, 1); +}; + +/** Is the slave ready to retire? + * @param {App.Entity.SlaveState} slave + * @returns {boolean} + */ +globalThis.retirementReady = function(slave) { + // indentured slaves don't retire, they expire + if (slave.indenture >= 0) { + return false; + } + + // retirement by age + if (V.policies.retirement.physicalAgePolicy === 0 && slave.actualAge >= V.retirementAge) { + return true; + } else if (V.policies.retirement.physicalAgePolicy === 1 && slave.physicalAge >= V.retirementAge) { + return true; + } + + // retirement by milestone + if (V.policies.retirement.sex > 0 && (slave.counter.oral + slave.counter.anal + slave.counter.vaginal + slave.counter.penetrative + slave.counter.mammary) > V.policies.retirement.sex) { + return true; + } + if (V.policies.retirement.milk > 0 && slave.counter.milk > V.policies.retirement.milk) { + return true; + } + if (V.policies.retirement.cum > 0 && slave.counter.cum > V.policies.retirement.cum) { + return true; + } + if (V.policies.retirement.births > 0 && slave.counter.births > V.policies.retirement.births) { + return true; + } + if (V.policies.retirement.kills > 0 && slave.counter.pitKills > V.policies.retirement.kills) { + return true; + } + + // no retirement for you + return false; +}; + +/** marks some weeks of time passage for a slave, counting birthdays and invoking aging if game settings require it + * @param {App.Entity.SlaveState} slave + * @param {number} [weeks=1] + */ +globalThis.ageSlaveWeeks = function(slave, weeks = 1) { + if (V.seeAge !== 0) { // birthdays enabled + for (let i = 0; i < weeks; ++i) { + slave.birthWeek++; + if (slave.birthWeek >= 52) { + slave.birthWeek = 0; + if (V.seeAge === 1) { // actual aging enabled + ageSlave(slave); + } + } + } + } +}; + +/** advances the age of a slave by one year, incurring all aging side effects + * @param {App.Entity.SlaveState} slave + * @param {boolean} [forceDevelopment=false] + */ +globalThis.ageSlave = function(slave, forceDevelopment = false) { + slave.physicalAge++; + slave.actualAge++; + if (slave.geneMods.NCS === 1 || (slave.geneticQuirks.neoteny >= 2 && slave.geneticQuirks.progeria !== 2)) { + /* Induced NCS completely takes over visual aging. Additionally, because of the neoteny aspects of NCS, ovaries don't age quite as fast. */ + /* Unsurprisingly, actual neoteny has the same effect as long as progeria isn't in play. */ + slave.ovaryAge += either(0.5, 0.6, 0.7, 0.7, 0.8, 0.9, 1.0); + } else { + slave.visualAge++; + slave.ovaryAge += either(0.8, 0.9, 0.9, 1.0, 1.0, 1.0, 1.1); + } + if (slave.broodmother === 1) { + slave.ovaryAge += 0.2; + } + if (slave.physicalAge <= 18 && (forceDevelopment || V.loliGrow > 0)) { + physicalDevelopment(slave); + } +}; + +/** Is the slave a shelter slave? + * @param {App.Entity.SlaveState} slave + * @returns {boolean} + */ +globalThis.isShelterSlave = function(slave) { + return (typeof slave.origin === "string" && slave.origin.includes("Slave Shelter")); +}; + +/** + * Returns if a slave appears male, female, or androgynous. + * + * @param {App.Entity.SlaveState} slave + * @returns {number} + */ +globalThis.perceivedGender = function(slave) { + return -1; }; \ No newline at end of file -- GitLab