diff --git a/player variables documentation - Pregmod.txt b/player variables documentation - Pregmod.txt index 1eddbc1385ad5c208599a727f86fa3316b49d45d..d8fd24f46feb390f6093293bbf6c92c4cb7be7fb 100644 --- a/player variables documentation - Pregmod.txt +++ b/player variables documentation - Pregmod.txt @@ -541,6 +541,21 @@ face: 100 +lips: + +lip size (0-100) +0 - 10 - thin +11 - 20 - normal +21 - 40 - pretty +41 - 70 - plush +71 - 95 - huge (lisps) +96 - 100- facepussy (mute) + +lipsImplant: + +how large her lip implants are +See .lips + reservedChildren: how many of your children will be added to the incubator diff --git a/src/002-config/fc-version.js b/src/002-config/fc-version.js index b51ecbc0720c5ee7275a26f60f3eb99044fc3f69..2f2d540f2fbb6c4994a03913d1ca9485f34f296b 100644 --- a/src/002-config/fc-version.js +++ b/src/002-config/fc-version.js @@ -1,6 +1,6 @@ App.Version = { base: "0.10.7.1", // The vanilla version the mod is based off of, this should never be changed. - pmod: "3.9.6", + pmod: "4.0.0-alpha.0", commitHash: null, - release: 1129 // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js. + release: 1130 // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js. }; diff --git a/src/Mods/SecExp/js/secExp.js b/src/Mods/SecExp/js/secExp.js index be6f467b4c9e93574b4b590acb2393ee124793ed..00183102f1b2670ff4e3c92306462d83daadbdcc 100644 --- a/src/Mods/SecExp/js/secExp.js +++ b/src/Mods/SecExp/js/secExp.js @@ -351,9 +351,9 @@ App.SecExp.initTrade = function() { } else if (V.terrain === "ravine") { init -= jsRandom(5, 5); } - if (["BlackHat", "capitalist", "celebrity", "wealth"].includes(V.PC.career)) { + if (isPCCareerInCategory("wealth") || isPCCareerInCategory("capitalist") || isPCCareerInCategory("celebrity") || isPCCareerInCategory("BlackHat")) { init += jsRandom(5, 5); - } else if (["escort", "gang", "servant"].includes(V.PC.career)) { + } else if (isPCCareerInCategory("escort") || isPCCareerInCategory("gang") || isPCCareerInCategory("servant")) { init -= jsRandom(5, 5); } V.SecExp.core.trade = init; diff --git a/src/data/backwardsCompatibility/datatypeCleanup.js b/src/data/backwardsCompatibility/datatypeCleanup.js index 8e934c7070f1ab93a54e1eb9dc44c38f18705254..8765da86270430c715d7d3b4d7f634123310b613 100644 --- a/src/data/backwardsCompatibility/datatypeCleanup.js +++ b/src/data/backwardsCompatibility/datatypeCleanup.js @@ -579,7 +579,7 @@ globalThis.SlaveDatatypeCleanup = (function SlaveDatatypeCleanup() { slave.hLength = Math.clamp(+slave.hLength, 0, 300) || 60; } if (typeof slave.hStyle !== "string") { - slave.hStyle = "long"; + slave.hStyle = "neat"; } slave.haircuts = Math.clamp(+slave.haircuts, 0, 1) || 0; slave.bald = Math.clamp(+slave.bald, 0, 1) || 0; @@ -1200,194 +1200,485 @@ globalThis.SlaveDatatypeCleanup = (function SlaveDatatypeCleanup() { } })(); -/* Make sure any new PC variables put into use are added to this! */ -globalThis.PCDatatypeCleanup = function() { - const PC = V.PC; +/* See slave datatype cleanup for details */ +globalThis.PCDatatypeCleanup = (function PCDatatypeCleanup() { + "use strict"; - if (PC.title !== 0) { - PC.title = Math.clamp(+PC.title, 0, 1) || 1; - } - if (PC.dick !== 0) { - PC.dick = Math.clamp(+PC.dick, 0, 5) || 4; - } - if (PC.vagina !== -1) { - PC.vagina = Math.clamp(+PC.vagina, 0, 5) || 0; - } - if (typeof PC.genes !== "string") { - PC.genes = "XY"; - } - if (typeof PC.nationality !== "string") { - PC.nationality = "Stateless"; - } - if (typeof PC.race !== "string") { - PC.race = "white"; - } - if (typeof PC.skin !== "string") { - PC.skin = "light"; - } - if (typeof PC.markings !== "string") { - PC.markings = "none"; - } - if (typeof PC.hColor !== "string") { - PC.hColor = "blonde"; - } - if (typeof PC.eye.origColor !== "string") { - PC.eye.origColor = "blue"; - } - PC.belly = Math.max(+PC.belly, 0) || 0; - PC.fertPeak = Math.clamp(+PC.fertPeak, 0, 4) || 0; - PC.pregMood = Math.clamp(+PC.pregMood, 0, 2) || 0; - PC.boobs = Math.clamp(+PC.boobs, 100, 1500) || 100; - PC.boobsImplant = Math.clamp(+PC.boobsImplant, 0, 1000) || 0; - PC.butt = Math.clamp(+PC.butt, 0, 5) || 2; - PC.buttImplant = Math.clamp(+PC.buttImplant, 0, 5) || 0; - PC.balls = Math.clamp(+PC.balls, 0, 100) || 0; - PC.ballsImplant = Math.clamp(+PC.ballsImplant, 0, 100) || 0; - PC.prostate = Math.clamp(+PC.prostate, 0, 1) || 0; - PC.degeneracy = Math.max(+PC.degeneracy, 0) || 0; - PC.birthWeek = Math.clamp(+PC.birthWeek, 0, 51) || 0; - if (PC.sexualEnergy !== 0) { - PC.sexualEnergy = +PC.sexualEnergy || 4; - } - if (typeof PC.refreshment !== "string") { - PC.refreshment = "cigar"; + return PCDatatypeCleanup; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCDatatypeCleanup(PC) { + PCAgeDatatypeCleanup(PC); + PCPhysicalDatatypeCleanup(PC); + PCFaceDatatypeCleanup(PC); + PCHairDatatypeCleanup(PC); + PCBoobsDatatypeCleanup(PC); + PCButtDatatypeCleanup(PC); + PCPregnancyDatatypeCleanup(PC); + PCBellyDatatypeCleanup(PC); + PCGenitaliaDatatypeCleanup(PC); + PCImplantsDatatypeCleanup(PC); + PCCosmeticsDatatypeCleanup(PC); + PCDietDatatypeCleanup(PC); + PCRelationDatatypeCleanup(PC); + PCSkillsDatatypeCleanup(PC); + PCStatCountDatatypeCleanup(PC); + PCPreferencesDatatypeCleanup(PC); + PCRulesDatatypeCleanup(PC); + PCCustomStatsDatatypeCleanup(PC); + PCMiscellaneousDatatypeCleanup(PC); + App.Entity.Utils.migratePronouns(PC); + generatePlayerPronouns(PC); } - if (!(V.ver.startsWith("0.10"))) { - if (V.PC.refreshment === "cigar") { - V.PC.refreshmentType = 0; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCAgeDatatypeCleanup(PC) { + if (PC.birthWeek > 51) { + PC.birthWeek = PC.birthWeek % 52; + } + PC.birthWeek = Math.clamp(+PC.birthWeek, 0, 51) || 0; + if (PC.age > 0) { + PC.actualAge = Math.clamp(+PC.actualAge, 10, 80) || PC.age; /* if undefined, this sets to PC.age */ + delete PC.age; } else { - V.PC.refreshmentType = 1; - } - } - PC.refreshmentType = Math.clamp(+PC.refreshmentType, 0, 6) || 0; - PC.skill.trading = Math.clamp(+PC.skill.trading, -100, 100) || 0; - PC.skill.warfare = Math.clamp(+PC.skill.warfare, -100, 100) || 0; - PC.skill.slaving = Math.clamp(+PC.skill.slaving, -100, 100) || 0; - PC.skill.engineering = Math.clamp(+PC.skill.engineering, -100, 100) || 0; - PC.skill.medicine = Math.clamp(+PC.skill.medicine, -100, 100) || 0; - PC.skill.hacking = Math.clamp(+PC.skill.hacking, -100, 100) || 0; - PC.skill.cumTap = Math.max(+PC.skill.cumTap, 0) || 0; - PC.mother = +PC.mother || 0; - PC.father = +PC.father || 0; - PC.labor = Math.clamp(+PC.labor, 0, 1) || 0; - PC.counter.birthsTotal = Math.max(+PC.counter.birthsTotal, 0) || 0; - PC.counter.birthElite = Math.max(+PC.counter.birthElite, 0) || 0; - PC.counter.birthMaster = Math.max(+PC.counter.birthMaster, 0) || 0; - PC.counter.birthDegenerate = Math.max(+PC.counter.birthDegenerate, 0) || 0; - PC.counter.birthClient = Math.max(+PC.counter.birthClient, 0) || 0; - PC.counter.birthOther = Math.max(+PC.counter.birthOther, 0) || 0; - PC.counter.birthArcOwner = Math.max(+PC.counter.birthArcOwner, 0) || 0; - PC.counter.birthCitizen = Math.max(+PC.counter.birthCitizen, 0) || 0; - PC.counter.birthSelf = Math.max(+PC.counter.birthSelf, 0) || 0; - PC.counter.birthLab = Math.max(+PC.counter.birthLab, 0) || 0; - PC.counter.birthFutaSis = Math.max(+PC.counter.birthFutaSis, 0) || 0; - PC.counter.slavesFathered = Math.max(+PC.counter.slavesFathered, 0) || 0; - PC.counter.slavesKnockedUp = Math.max(+PC.counter.slavesKnockedUp, 0) || 0; - PC.counter.storedCum = Math.max(+PC.counter.storedCum, 0) || 0; - PC.intelligence = 100; - PC.face = 100; - PC.actualAge = Math.clamp(+PC.actualAge, 14, 80) || 35; - PC.physicalAge = Math.clamp(+PC.physicalAge, 14, 80) || PC.actualAge; - PC.visualAge = Math.clamp(+PC.visualAge, 14, 80) || PC.actualAge; - PC.ovaryAge = Math.clamp(+PC.ovaryAge, 14, 80) || PC.physicalAge; - if (V.playerAging !== 0) { - V.playerAging = Math.clamp(+V.playerAging, 0, 2) || 2; - } - PC.newVag = Math.clamp(+PC.newVag, 0, 1) || 0; - PC.fertDrugs = Math.clamp(+PC.fertDrugs, 0, 1) || 0; - PC.forcedFertDrugs = Math.max(+PC.forcedFertDrugs, 0) || 0; - PC.staminaPills = Math.clamp(+PC.staminaPills, 0, 1) || 0; - PC.mpreg = 0; /* So knockMeUp() may be used with the PC */ - PC.lactation = Math.max(+PC.lactation, 0) || 0; - PC.lactationDuration = Math.max(+PC.lactationDuration, 0) || 0; - PC.muscles = Math.clamp(+PC.muscles, -100, 100) || 50; - PC.hLength = Math.clamp(+PC.hLength, 0, 150) || 2; - PC.voice = Math.clamp(+PC.voice, 1, 3) || 1; - if (typeof PC.health === "number") { - const condition = PC.health; - PC.health = {}; - PC.health.condition = condition; - } - PC.health.condition = Math.clamp(PC.health.condition, -100, 100) || 0; - if (PC.majorInjury !== undefined) { - if (PC.majorInjury > 0) { - PC.health.shortDamage = Math.max(PC.majorInjury * 20, 30); + PC.actualAge = Math.clamp(+PC.actualAge, 10, Infinity) || 35; + } + PC.physicalAge = Math.clamp(+PC.physicalAge, 14, 80) || PC.actualAge; + PC.visualAge = Math.clamp(+PC.visualAge, 14, 80) || PC.actualAge; + PC.ovaryAge = Math.clamp(+PC.ovaryAge, 14, 80) || PC.physicalAge; + if (V.playerAging !== 0) { + V.playerAging = Math.clamp(+V.playerAging, 0, 2) || 2; + } + PC.pubertyAgeXX = Math.max(+PC.pubertyAgeXX, 0) || 13; + PC.pubertyAgeXY = Math.max(+PC.pubertyAgeXY, 0) || 13; + if (typeof PC.health === "number") { + const condition = PC.health; + PC.health = {}; + PC.health.condition = condition; + } + PC.health.condition = Math.clamp(PC.health.condition, -100, 100) || 0; + if (PC.majorInjury !== undefined) { + if (PC.majorInjury > 0) { + PC.health.shortDamage = Math.max(PC.majorInjury * 20, 30); + } else { + PC.health.shortDamage = 0; + } + delete PC.majorInjury; } else { - PC.health.shortDamage = 0; + PC.health.shortDamage = Math.max(+PC.health.shortDamage, 0) || 0; } - delete PC.majorInjury; - } else { + PC.health.longDamage = Math.max(+PC.health.longDamage, 0) || 0; + PC.health.illness = Math.max(+PC.health.illness, 0) || 0; + PC.health.tired = Math.clamp(+PC.health.tired, 0, 100) || 0; + PC.health.health = Math.clamp(PC.health.condition - PC.health.shortDamage - PC.health.longDamage, -100, 100) || 0; + } + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCPhysicalDatatypeCleanup(PC) { + if (PC.title !== 0) { + PC.title = Math.clamp(+PC.title, 0, 1) || 1; + } + if (typeof PC.genes !== "string") { + PC.genes = "XY"; + } + if (typeof PC.nationality !== "string") { + PC.nationality = "Stateless"; + } + if (typeof PC.race !== "string") { + PC.race = "white"; + } + if (typeof PC.origRace !== "string") { + PC.origRace = PC.race; + } + if (typeof PC.skin !== "string") { + PC.skin = "light"; + } + if (typeof PC.origSkin !== "string") { + PC.origSkin = PC.skin; + } + + // why is this duplicated? + PC.health.condition = Math.clamp(PC.health.condition, -100, 200) || 0; PC.health.shortDamage = Math.max(+PC.health.shortDamage, 0) || 0; + PC.health.longDamage = Math.max(+PC.health.longDamage, 0) || 0; + PC.health.illness = Math.max(+PC.health.illness, 0) || 0; + PC.health.tired = Math.clamp(+PC.health.tired, 0, 100) || 0; + PC.health.health = Math.clamp(PC.health.condition - PC.health.shortDamage - PC.health.longDamage, -100, 100) || 0; + + PC.muscles = Math.clamp(+PC.muscles, -100, 100) || 0; + PC.weight = Math.clamp(+PC.weight, -100, 200) || 0; + PC.waist = Math.clamp(+PC.waist, -100, 100) || 0; + PC.height = Math.round(Math.max(+PC.height, 0)) || Math.round(Height.mean(PC)); + PC.shoulders = Math.clamp(+PC.shoulders, -2, 2) || 0; + PC.hips = Math.clamp(+PC.hips, -2, 3) || 0; } - PC.health.longDamage = Math.max(+PC.health.longDamage, 0) || 0; - PC.health.illness = Math.max(+PC.health.illness, 0) || 0; - PC.health.tired = Math.clamp(+PC.health.tired, 0, 100) || 0; - PC.health.health = Math.clamp(PC.health.condition - PC.health.shortDamage - PC.health.longDamage, -100, 100) || 0; - if (typeof PC.rules.living !== "string") { - PC.rules.living = "normal"; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCFaceDatatypeCleanup(PC) { + if (typeof PC.eye.origColor !== "string") { + PC.eye.origColor = "blue"; + } + PC.face = 100; + if (PC.lips !== 0) { + PC.lips = Math.clamp(+PC.lips, 0, 100) || 15; + } } - if (typeof PC.rules.lactation !== "string") { - PC.rules.lactation = "none"; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCHairDatatypeCleanup(PC) { + if (typeof PC.hColor !== "string") { + PC.hColor = "blonde"; + } + if (typeof PC.origHColor !== "string") { + PC.origHColor = PC.hColor; + } + if (PC.hLength !== 0) { + PC.hLength = Math.clamp(+PC.hLength, 0, 300) || 2; + } + if (typeof PC.hStyle !== "string") { + PC.hStyle = "neat"; + } + if (typeof PC.pubicHColor !== "string") { + PC.pubicHColor = PC.hColor; + } + if (typeof PC.pubicHStyle !== "string") { + PC.pubicHStyle = "hairless"; + } + if (typeof PC.underArmHColor !== "string") { + PC.underArmHColor = PC.hColor; + } + if (typeof PC.underArmHStyle !== "string") { + PC.underArmHStyle = "hairless"; + } + if (typeof PC.eyebrowHColor !== "string") { + PC.eyebrowHColor = PC.hColor; + } + if (typeof PC.eyebrowHStyle !== "string") { + PC.eyebrowHStyle = "natural"; + } + if (typeof PC.eyebrowFullness !== "string") { + PC.eyebrowFullness = "natural"; + } } - if (typeof PC.rules.rest !== "string") { - PC.rules.rest = "permissive"; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCBoobsDatatypeCleanup(PC) { + PC.boobs = Math.max(+PC.boobs, 100) || 200; + if (typeof PC.boobShape !== "string") { + PC.boobShape = "normal"; + } + if (PC.boobShape === "spherical" && PC.boobsImplant === 0) { + PC.boobShape = "normal"; + } + if (typeof PC.nipples !== "string") { + PC.nipples = "tiny"; + } + PC.areolae = Math.clamp(+slave.areolae, 0, 4) || 0; + PC.lactation = Math.max(+PC.lactation, 0) || 0; + PC.lactationDuration = Math.max(+PC.lactationDuration, 0) || 0; + if (PC.boobsMilk > 0 && PC.boobs - PC.boobsMilk - PC.boobsImplant < 0) { + // should never get here, but if it does, just immediately abort! + PC.boobsMilk = 0; + } + PC.lactationAdaptation = Math.clamp(+PC.lactationAdaptation, 0, 100) || 0; } - App.Entity.Utils.migratePronouns(PC); - generatePlayerPronouns(PC); - if (PC.age !== undefined) { - delete PC.age; + /** + * @param {App.Entity.PlayerState} PC + */ + function PCButtDatatypeCleanup(PC) { + if (PC.butt !== 0) { + PC.butt = Math.clamp(+PC.butt, 0, 20) || 2; + } + PC.anus = Math.clamp(+PC.anus, 0, 4) || 0; + PC.analArea = Math.max(+PC.analArea, 0) || 0; } - if (PC.indenture !== undefined) { - delete PC.indenture; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCPregnancyDatatypeCleanup(PC) { + PC.induce = Math.clamp(+PC.induce, 0, 1) || 0; + PC.labor = Math.clamp(+PC.labor, 0, 1) || 0; + PC.prematureBirth = Math.clamp(+PC.prematureBirth, 0, 1) || 0; + PC.ovaries = Math.clamp(+PC.ovaries, 0, 1) || 0; + PC.vasectomy = Math.clamp(+PC.vasectomy, 0, 1) || 0; + PC.mpreg = Math.clamp(+PC.mpreg, 0, 1) || 0; + if (PC.pregAdaptation !== 0) { + PC.pregAdaptation = Math.max(+PC.pregAdaptation, 0) || 50; + } + if (PC.pubertyXX === 0 && (PC.ovaries > 0 || PC.mpreg > 0) && PC.preg === -1) { + PC.preg = 0; // no contraceptives for prepubescent slaves + } + PC.fertPeak = Math.clamp(+PC.fertPeak, 0, 4) || 0; + PC.pregSource = +PC.pregSource || 0; + PC.pregMood = Math.clamp(+PC.pregMood, 0, 2) || 0; + PC.fertDrugs = Math.clamp(+PC.fertDrugs, 0, 1) || 0; + PC.forcedFertDrugs = Math.max(+PC.forcedFertDrugs, 0) || 0; + WombNormalizePreg(PC); } - if (PC.indentureRestrictions !== undefined) { - delete PC.indentureRestrictions; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCBellyDatatypeCleanup(PC) { + PC.inflation = Math.clamp(+PC.inflation, 0, 3) || 0; + if (typeof PC.inflationType !== "string") { + PC.inflationType = "none"; + } + PC.inflationMethod = Math.clamp(+PC.inflationMethod, 0, 3) || 0; + PC.milkSource = Math.max(+PC.milkSource, 0) || 0; + PC.cumSource = Math.max(+PC.cumSource, 0) || 0; + if (PC.bellyImplant !== 0) { + PC.bellyImplant = Math.max(+PC.bellyImplant, -1) || -1; + } + PC.cervixImplant = Math.clamp(+PC.cervixImplant, 0, 3) || 0; + PC.bellySag = Math.max(+PC.bellySag, 0) || 0; + PC.bellySagPreg = Math.max(+PC.bellySagPreg, 0) || PC.bellySag; + PC.bellyPain = Math.clamp(+PC.bellyPain, 0, 2) || 0; + SetBellySize(PC); } - if (PC.boobsImplant > 0) { - // update with 4.0.0 - PC.boobsImplantType = "normal"; - } else { - PC.boobsImplantType = "none"; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCGenitaliaDatatypeCleanup(PC) { + PC.newVag = Math.clamp(+PC.newVag, 0, 1) || 0; + if (PC.vagina !== -1) { + PC.vagina = Math.clamp(+PC.vagina, 0, 10) || 1; + } + PC.vaginaLube = Math.clamp(+PC.vaginaLube, 0, 2) || 0; + PC.labia = Math.clamp(+PC.labia, 0, 3) || 0; + PC.clit = Math.clamp(+PC.clit, 0, 5) || 0; + PC.foreskin = Math.max(+PC.foreskin, 0) || 0; + if (PC.dick !== 0) { + PC.dick = Math.max(+PC.dick, 1) || 4; + PC.prostate = Math.clamp(+PC.prostate, 0, 1) || 1; + PC.balls = Math.max(+PC.balls, 0) || 3; + } else { + PC.prostate = Math.clamp(+PC.prostate, 0, 1) || 0; + PC.balls = Math.max(+PC.balls, 0) || 0; + } + if (PC.scrotum !== 0) { + PC.scrotum = Math.max(+PC.scrotum, 0) || PC.balls; + } } - if (PC.buttImplant > 0) { - PC.buttImplantType = "normal"; - } else { - PC.buttImplantType = "none"; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCImplantsDatatypeCleanup(PC) { + PC.ageImplant = Math.clamp(+PC.ageImplant, 0, 1) || 0; + PC.faceImplant = Math.clamp(+PC.faceImplant, 0, 100) || 0; + PC.lipsImplant = Math.clamp(+PC.lipsImplant, 0, 100) || 0; + PC.voiceImplant = Math.clamp(+PC.voiceImplant, -1, 1) || 0; + PC.boobsImplant = Math.clamp(+PC.boobsImplant, 0, PC.boobs) || 0; + if (PC.boobsImplant === 0) { + PC.boobsImplantType = "none"; + } else if (PC.boobsImplant > 0 && PC.boobsImplantType === "none") { + if (PC.boobsImplant > 10000) { + PC.boobsImplantType = "hyper fillable"; + } else if (PC.boobsImplant > 2200) { + PC.boobsImplantType = "advanced fillable"; + } else if (PC.boobsImplant > 1000) { + PC.boobsImplantType = "fillable"; + } else { + PC.boobsImplantType = "normal"; + } + } + PC.breastMesh = Math.clamp(+PC.breastMesh, 0, 1) || 0; + PC.buttImplant = Math.clamp(+PC.buttImplant, 0, Math.min(PC.butt, 20)) || 0; + if (typeof PC.buttImplantType !== "string") { + if (PC.buttImplant === 0) { + PC.buttImplantType = "none"; + } else if (PC.buttImplant > 0) { + PC.buttImplantType = "normal"; + } + } + PC.heightImplant = Math.clamp(+PC.heightImplant, -10, 10) || 0; + PC.earImplant = Math.clamp(+PC.earImplant, 0, 1) || 0; + PC.shouldersImplant = Math.clamp(+PC.shouldersImplant, -10, 10) || 0; + PC.hipsImplant = Math.clamp(+PC.hipsImplant, -10, 10) || 0; + PC.ballsImplant = Math.clamp(+PC.ballsImplant, 0, 100) || 0; } - if (V.PC.customTitle === "") { - V.PC.customTitle = undefined; - V.PC.customTitleLisp = undefined; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCCosmeticsDatatypeCleanup(PC) { + if (typeof PC.clothes !== "string") { + PC.clothes = "nice business attire"; + } + if (typeof PC.eyewear !== "string") { + PC.eyewear = "none"; + } + if (typeof PC.markings !== "string") { + PC.markings = "none"; + } } - if (typeof V.PC.counter.oral === "undefined") { - V.PC.counter.oral = 0; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCDietDatatypeCleanup(PC) { + if (typeof PC.refreshment !== "string") { + PC.refreshment = "cigar"; + } + if (!(V.ver.startsWith("0.10"))) { + if (V.PC.refreshment === "cigar") { + V.PC.refreshmentType = 0; + } else { + V.PC.refreshmentType = 1; + } + } + PC.refreshmentType = Math.clamp(+PC.refreshmentType, 0, 6) || 0; + if (typeof PC.diet !== "string") { + PC.diet = "healthy"; + } + PC.hormones = Math.clamp(+PC.hormones, -2, 2) || 0; + PC.hormoneBalance = Math.clamp(+PC.hormoneBalance, -500, 500) || 0; + if (typeof PC.drugs !== "string") { + PC.drugs = "no drugs"; + } + PC.aphrodisiacs = Math.clamp(+PC.aphrodisiacs, -1, 2) || 0; + PC.staminaPills = Math.clamp(+PC.staminaPills, 0, 1) || 0; } - if (typeof V.PC.counter.vaginal === "undefined") { - V.PC.counter.vaginal = 0; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCRelationDatatypeCleanup(PC) { + PC.mother = +PC.mother || 0; + PC.father = +PC.father || 0; } - if (typeof V.PC.counter.anal === "undefined") { - V.PC.counter.anal = 0; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCSkillsDatatypeCleanup(PC) { + PC.skill.trading = Math.clamp(+PC.skill.trading, -100, 100) || 0; + PC.skill.warfare = Math.clamp(+PC.skill.warfare, -100, 100) || 0; + PC.skill.slaving = Math.clamp(+PC.skill.slaving, -100, 100) || 0; + PC.skill.engineering = Math.clamp(+PC.skill.engineering, -100, 100) || 0; + PC.skill.medicine = Math.clamp(+PC.skill.medicine, -100, 100) || 0; + PC.skill.hacking = Math.clamp(+PC.skill.hacking, -100, 100) || 0; + PC.skill.cumTap = Math.max(+PC.skill.cumTap, 0) || 0; } - if (typeof V.PC.counter.mammary === "undefined") { - V.PC.counter.mammary = 0; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCStatCountDatatypeCleanup(PC) { + PC.counter.oral = Math.max(+PC.counter.oral, 0) || 0; + PC.counter.vaginal = Math.max(+PC.counter.vaginal, 0) || 0; + PC.counter.anal = Math.max(+PC.counter.anal, 0) || 0; + PC.counter.mammary = Math.max(+PC.counter.mammary, 0) || 0; + PC.counter.penetrative = Math.max(+PC.counter.penetrative, 0) || 0; + PC.counter.milk = Math.max(+PC.counter.milk, 0) || 0; + PC.counter.cum = Math.max(+PC.counter.cum, 0) || 0; + PC.counter.birthsTotal = Math.max(+PC.counter.birthsTotal, 0) || 0; + PC.counter.birthElite = Math.max(+PC.counter.birthElite, 0) || 0; + PC.counter.birthMaster = Math.max(+PC.counter.birthMaster, 0) || 0; + PC.counter.birthDegenerate = Math.max(+PC.counter.birthDegenerate, 0) || 0; + PC.counter.birthClient = Math.max(+PC.counter.birthClient, 0) || 0; + PC.counter.birthOther = Math.max(+PC.counter.birthOther, 0) || 0; + PC.counter.birthArcOwner = Math.max(+PC.counter.birthArcOwner, 0) || 0; + PC.counter.birthCitizen = Math.max(+PC.counter.birthCitizen, 0) || 0; + PC.counter.birthSelf = Math.max(+PC.counter.birthSelf, 0) || 0; + PC.counter.birthLab = Math.max(+PC.counter.birthLab, 0) || 0; + PC.counter.birthFutaSis = Math.max(+PC.counter.birthFutaSis, 0) || 0; + PC.counter.abortions = Math.max(+PC.counter.abortions, 0) || 0; + PC.counter.miscarriages = Math.max(+PC.counter.miscarriages, 0) || 0; + PC.counter.slavesFathered = Math.max(+PC.counter.slavesFathered, 0) || 0; + PC.counter.slavesKnockedUp = Math.max(+PC.counter.slavesKnockedUp, 0) || 0; + PC.counter.storedCum = Math.max(+PC.counter.storedCum, 0) || 0; + PC.bodySwap = Math.max(+PC.bodySwap, 0) || 0; } - if (typeof V.PC.counter.penetrative === "undefined") { - V.PC.counter.penetrative = 0; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCPreferencesDatatypeCleanup(PC) { + if (PC.sexualEnergy !== 0) { + PC.sexualEnergy = +PC.sexualEnergy || 4; + } + PC.energy = Math.clamp(+PC.energy, 0, 100) || 80; + PC.need = Math.max(+PC.need, 0) || 0; + PC.degeneracy = Math.max(+PC.degeneracy, 0) || 0; } - WombInit(V.PC); - if (typeof V.PC.ID === "undefined") { - V.PC.ID = -1; + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCRulesDatatypeCleanup(PC) { + if (typeof PC.rules.living !== "string") { + PC.rules.living = "normal"; + } + if (typeof PC.rules.lactation !== "string") { + PC.rules.lactation = "none"; + } + if (typeof PC.rules.rest !== "string") { + PC.rules.rest = "permissive"; + } } - if (typeof V.PC.partners !== "object") { - V.PC.partners = new Set(); + + /** + * @param {App.Entity.PlayerState} PC + */ + function PCCustomStatsDatatypeCleanup(PC) { + if (V.PC.customTitle === "") { + V.PC.customTitle = undefined; + V.PC.customTitleLisp = undefined; + } } - /* None of these are in use */ - PC.bellyPreg = PC.belly; - PC.ageImplant = 0; - PC.voiceImplant = 0; - PC.accent = 0; -}; + /** + * @param {App.Entity.PlayerState} PC + */ + function PCMiscellaneousDatatypeCleanup(PC) { + if (typeof V.PC.ID === "undefined") { + V.PC.ID = -1; + } + PC.chem = Math.max(+PC.chem, 0) || 0; + PC.addict = Math.max(+PC.addict, 0) || 0; + PC.intelligence = 100; + PC.intelligenceImplant = Math.clamp(+PC.intelligenceImplant, -15, 30) || 30; + PC.hears = Math.clamp(+PC.hears, -2, 0) || 0; + PC.smells = Math.clamp(+PC.smells, -1, 0) || 0; + PC.tastes = Math.clamp(+PC.tastes, -1, 0) || 0; + PC.PLimb = Math.clamp(+PC.PLimb, 0, 2) || 0; + if (PC.voice !== 0) { + PC.voice = Math.clamp(+PC.voice, 0, 3) || 1; + } + PC.electrolarynx = Math.clamp(+PC.electrolarynx, 0, 1) || 0; + if (typeof PC.origBodyOwner !== "string") { + PC.origBodyOwner = ""; + } + PC.origBodyOwnerID = Math.max(+PC.origBodyOwnerID, 0) || 0; + if (PC.indenture !== undefined) { + delete PC.indenture; + } + if (PC.indentureRestrictions !== undefined) { + delete PC.indentureRestrictions; + } + if (typeof V.PC.partners !== "object") { + V.PC.partners = new Set(); + } + PC.accent = 0; // Might not use? Would be related to changing languages. Might not work out. + } +})(); globalThis.EconomyDatatypeCleanup = function() { V.AProsperityCap = Math.max(+V.AProsperityCap, 0) || 0; diff --git a/src/events/intro/introSummary.js b/src/events/intro/introSummary.js index 4841494db14a3bddc92cbc3eb37678d63ff37afc..d1b201b38fa65a75671c694152c8ce1d447ad94e 100644 --- a/src/events/intro/introSummary.js +++ b/src/events/intro/introSummary.js @@ -3,7 +3,7 @@ App.Intro.summary = function() { V.neighboringArcologies = variableAsNumber(V.neighboringArcologies, 0, 8, 3); V.FSCreditCount = variableAsNumber(V.FSCreditCount, 4, 7, 5); - V.PC.actualAge = variableAsNumber(V.PC.actualAge, 14, 80, 35); + V.PC.actualAge = variableAsNumber(V.PC.actualAge, 10, 80, 35); V.PC.birthWeek = variableAsNumber(V.PC.birthWeek, 0, 51, 0); el.append(introContent()); @@ -372,28 +372,30 @@ App.Intro.summary = function() { } else if (V.PC.rumor === "force") { V.PC.muscles += 20; } - } + // I hope this works + PCDatatypeCleanup(V.PC); - if (V.PC.dick !== 0) { - V.PC.geneticQuirks.wellHung = 2; - } else { - V.PC.balls = 0; - V.PC.scrotum = 0; - V.PC.prostate = 0; - } - if (V.PC.title === 0) { - V.PC.hLength = 15; - V.PC.waist = -20; - V.PC.voice = 2; - V.PC.shoulders = -1; - V.PC.hips = 1; - } - if (V.PC.vagina === -1) { - V.PC.ovaries = 0; - } else if (V.PC.vagina > 0) { - V.PC.vaginaLube = 1; + if (V.PC.dick >= 3) { + V.PC.geneticQuirks.wellHung = 2; + } + if (V.PC.title === 0) { + V.PC.hLength = 15; + V.PC.waist = -20; + V.PC.voice = 2; + } + if (V.PC.eye.right.vision === 1 || V.PC.eye.left.vision === 1) { + V.PC.eyewear = "corrective glasses"; + } + if (V.PC.pubertyXX === 0 && V.PC.pubertyXY === 0) { + if (V.PC.age < 11) { + V.PC.energy = 20; + } else if (V.PC.age < 12) { + V.PC.energy = 30; + } else if (V.PC.age < 13) { + V.PC.energy = 40; + } + } } - V.PC.ovaryAge = V.PC.physicalAge; V.PC.birthName = V.PC.slaveName; V.PC.birthSurname = V.PC.slaveSurname; diff --git a/src/events/intro/pcAppearance.js b/src/events/intro/pcAppearance.js index 47f9ba6e9f959aa667032a0587569ec817ce169d..40c3d32f0bc150d14309019406f64af19ed59ed0 100644 --- a/src/events/intro/pcAppearance.js +++ b/src/events/intro/pcAppearance.js @@ -1,6 +1,8 @@ App.UI.Player = {}; -App.UI.Player.appearance = function(options) { +App.UI.Player.appearance = function(options, summary = false) { + let option; + options.addOption("Your nationality is", "nationality", V.PC).showTextBox() .addValueList(App.Data.misc.baseNationalities) .addComment("For best result capitalize it.").pulldown(); @@ -13,6 +15,23 @@ App.UI.Player.appearance = function(options) { .addValueList(Array.from(App.Data.misc.filterRaces, (k => [k[1], k[0]]))); } + options.addOption("You are genetically", "genes", V.PC) + .addValue("XY").addValue("XX"); + + options.addOption(`You are`, "height", V.PC).showTextBox({unit: "cm"}) + .addRange(145, 150, "<", "Petite") + .addRange(155, 160, "<", "Short") + .addRange(165, 170, "<", "Average") + .addRange(180, 185, "<", "Tall") + .addRange(190, 185, ">=", "Very tall") + .addComment(`Average height for a ${V.PC.actualAge} year old is ${heightToEitherUnit(Math.round(Height.mean(V.PC)))}`); + option = options.addCustomOption() + .addButton( + "Make average", + () => resyncSlaveHight(V.PC), + "" + ); + options.addOption("Your skin tone is", "skin", V.PC).showTextBox() .addValueList(makeAList(App.Medicine.Modification.naturalSkins)); @@ -21,12 +40,6 @@ App.UI.Player.appearance = function(options) { .addValueList(makeAList(App.Medicine.Modification.naturalSkins)); } - options.addOption("Your body", "markings", V.PC) - .addValueList([["Is clear of blemishes", "none"], ["Has light freckling", "freckles"], ["Has heavy freckling", "heavily freckled"]]); - - options.addOption("Your genetic eye color is", "origColor", V.PC.eye).showTextBox() - .addValueList(makeAList(App.Medicine.Modification.eyeColor.map(color => color.value))); - if (V.cheatMode) { options.addOption("Your original hair is", "origHColor", V.PC).showTextBox() .addValueList(makeAList(App.Medicine.Modification.Color.Primary.map(color => color.value))); @@ -35,11 +48,437 @@ App.UI.Player.appearance = function(options) { .addValueList(makeAList(App.Medicine.Modification.Color.Primary.map(color => color.value))); } + options.addOption("Your genetic eye color is", "origColor", V.PC.eye).showTextBox() + .addValueList(makeAList(App.Medicine.Modification.eyeColor.map(color => color.value))); + + options.addOption("You", "vision", V.PC.eye.right) + .addValueList([["Need glasses to see properly", 1, () => { V.PC.eye.right = 1; V.PC.eye.left = 1; }], ["have normal vision", 2, () => { V.PC.eye.right = 2; V.PC.eye.left = 2; }]]); + + options.addOption("Your face is", "faceShape", V.PC) + .addValueList([ + ["Normal", "normal"], + ["Androgynous", "androgynous"], + ["Masculine", "masculine"], + ["Cute", "cute"], + ["Sensual", "sensual"], + ["Exotic", "exotic"] + ]); + + options.addOption("Your body", "markings", V.PC) + .addValueList([["Is clear of blemishes", "none"], ["Has light freckling", "freckles"], ["Has heavy freckling", "heavily freckled"]]); + + options.addOption("You have", "lips", V.PC).addValue("Thin lips", 5) + .addValueList([ + ["Normal lips", 15], + ["Kissable lips", 25], + ["Plush lips", 45], + ]); + + /* Handled by career currently + options.addOption("You are", "weight", V.PC).addValue("Very thin", -50); + options.addValueList([ + ["Thin", -20], + ["Healthy", 0], + ["Curvy", 20], + ["Chubby", 60], + ["Fat", 100], + ]) + .showTextBox(); + */ + + option = options.addOption("Your shoulders are", "shoulders", V.PC).addValue("Very narrow", -2); + option.addValueList([ + ["Narrow", -1], + ["Average", 0], + ]); + if (V.PC.physicalAge > 13) { + option.addValue("Broad", 1); + } + if (V.PC.physicalAge > 18) { + option.addValue("Very broad", 2); + } + + if (V.PC.boobs >= 200 || summary) { + if (V.PC.title === 1 && V.PC.boobs <= 200) { + option = options.addOption("Your chest is", "boobs", V.PC).addValue("Manly", 200, () => { V.PC.boobsImplant = 0; V.PC.boobsImplantType = "none"; }); + } else { + option = options.addOption("Your breasts are", "boobs", V.PC).addValue("Non-existent", 200, () => { V.PC.boobsImplant = 0; V.PC.boobsImplantType = "none"; }); + } + option.addValueList([ + ["A-cups", 300], + ["B-cups", 400], + ["C-cups", 500], + ]); + if (V.PC.physicalAge <= 13) { + option.addValueList([ + ["hefty D-cups", 650], + ["heavy DD-cups", 900], + ]); + } else { + option.addValueList([ + ["D-cups", 650], + ["DD-cups", 900], + ["F-cups", 1100], + ["G-cups", 1300] + ]); + } + option.showTextBox({unit: "CCs"}); + if (V.PC.boobs >= 500) { + options.addOption("Your breasts are", "boobsImplant", V.PC) + .addValueList([ + ["All natural", 0, () => { V.PC.boobsImplant = 0; V.PC.boobsImplantType = "none"; }], + ["Fake", V.PC.boobs / 2, () => V.PC.boobsImplantType = "normal"] + ]); + } + if (V.PC.boobsImplant > 0) { + option = options.addOption("You have", "boobsImplantType", V.PC).addValue("Regular implants", "normal"); + if (V.PC.boobsImplant > 400) { + option.addValue("string implants", "string"); + } + if (V.PC.boobsImplant > 600) { + option.addValue("Fillable implants", "fillable"); + } + } + if (V.PC.boobs >= 300) { + option = options.addOption("Your nipples are", "nipples", V.PC).addValue("Tiny", "tiny"); + option.addValue("Cute", "cute"); + if (V.PC.boobs >= 500) { + option.addValue("Puffy", "puffy"); + option.addValue("Partially inverted", "partially inverted"); + } + if (V.PC.boobs >= 1000) { + option.addValue("Inverted", "inverted"); + option.addValue("Huge", "huge"); + } + } + } + + option = options.addOption("Your hips are", "hips", V.PC).addValue("Very narrow", -2); + option.addValueList([ + ["Narrow", -1], + ["Average", 0], + ]); + if (V.PC.physicalAge > 13) { + option.addValue("Wide", 1); + } + if (V.PC.physicalAge > 18) { + option.addValue("Very Wide", 2); + } + + + option = options.addOption("Your butt is", "butt", V.PC).addValue("Flat", 0, () => { V.PC.buttImplant = 0; V.PC.buttImplantType = "none"; }); + option.addValueList([ + ["Small", 1], + ["Plump", 2], + ["Big", 3], + ]); + if (V.PC.physicalAge > 13) { + option.addValue("Huge", 4); + } + if (V.PC.physicalAge > 18) { + option.addValueList([ + ["Enormous", 5], + ["Gigantic", 6], + ]); + } + if (V.PC.butt >= 3) { + options.addOption("Your ass is", "buttImplant", V.PC) + .addValueList([ + ["All natural", 0, () => V.PC.buttImplantType = "none"], + ["Fake", Math.round(V.PC.butt / 2), () => V.PC.buttImplantType = "normal"] + ]); + } + if (V.PC.buttImplant > 0) { + option = options.addOption("You have", "buttImplantType", V.PC).addValue("Regular implants", "normal"); + if (V.PC.buttImplant > 1) { + option.addValue("string implants", "string"); + option.addValue("Fillable implants", "fillable"); + } + } + + if (V.PC.dick !== 0) { + option = options.addOption("Your dick is", "dick", V.PC).addValue("Tiny", 1, () => V.PC.foreskin = 2); + option.addValueList([ + ["Small", 2, () => V.PC.foreskin = 3], + ["Average", 3, () => V.PC.foreskin = 3], + ["Big", 4, () => V.PC.foreskin = 4], + ]); + if (V.PC.physicalAge > 13) { + option.addValue("Huge", 5, () => V.PC.foreskin = 5); + } + if (V.PC.physicalAge > 18) { + option.addValue("Gigantic", 6, () => V.PC.foreskin = 5); + } + options.addOption("You are", "foreskin", V.PC) + .addValueList([ + ["Cut", 0], + ["Uncut", V.PC.dick] + ]) + .showTextBox() + .addComment("Any value above 0 is uncircumcised. For comfort, keep equal or one greater than dick size."); + } + + if (V.PC.balls !== 0) { + option = options.addOption("Your balls are", "balls", V.PC).addValue("Small", 2, () => V.PC.scrotum = 2); + option.addValueList([ + ["Average", 3, () => V.PC.scrotum = 4], + ["Large", 4, () => V.PC.scrotum = 5], + ]); + if (V.PC.physicalAge > 13) { + option.addValue("Massive", 5, () => V.PC.scrotum = 5); + } + if (V.PC.physicalAge > 18) { + option.addValue("Huge", 6, () => V.PC.scrotum = 6); + } + option.addComment("Small balls may be located internally."); + if (V.PC.balls <= 2) { + options.addOption("Your balls are", "scrotum", V.PC) + .addValueList([ + ["Internal", 0], + ["External", V.PC.balls] + ]) + .showTextBox() + .addComment("Any value above 0 is external. For comfort, keep equal or one greater than ball size."); + } + if (V.PC.physicalAge < 14) { + options.addOption("You are", "pubertyXY", V.PC) + .addValueList([["Not producing potent sperm yet", 0], ["Producing potent sperm", 1]]); + } + } + + if (V.PC.vagina !== -1) { + if (V.PC.dick === 0 && V.PC.physicalAge > 13) { + options.addOption("Your clit is", "clit", V.PC) + .addValueList([["Normal", 0], ["Large", 1], ["Huge", 2]]); + } + if (V.PC.physicalAge <= 18) { + options.addOption("You are", "vagina", V.PC) + .addValueList([["A virgin", 0], ["Not a virgin", 1]]); + if (V.PC.physicalAge < 14 && V.PC.preg <= 0) { + options.addOption("You have", "pubertyXX", V.PC) + .addValueList([["Not had your first period", 0], ["Had your first period", 1]]); + } + } + } + + options.addOption("You are", "anus", V.PC) + .addValueList([["An anal virgin", 0], ["Not an anal virgin", 1]]); + function makeAList(iterable) { return Array.from(iterable, (k => [capFirstChar(k), k])); } }; +App.UI.Player.syncAgeBasedParameters = function() { + V.PC.actualAge = Math.clamp(V.PC.actualAge, 10, 80); + V.PC.physicalAge = V.PC.actualAge; + V.PC.visualAge = V.PC.actualAge; + V.PC.ovaryAge = V.PC.actualAge; + V.PC.height = Math.round(Height.random(V.PC), {limitMult: [2, 4]}); + if (V.PC.genes === "XY") { + if (V.PC.physicalAge <= 13) { + V.PC.hips = -2; + V.PC.shoulders = -1; + V.PC.butt = 0; + V.PC.boobs = 100; + if (V.PC.vagina !== -1) { + V.PC.vagina = 0; + V.PC.vaginaLube = 0; + if (V.PC.preg <= 0) { + V.PC.pubertyXX = 0; + } + } + V.PC.pregAdaptation = 10; + if (V.PC.dick !== 0) { + V.PC.dick = 2; + V.PC.balls = 2; + V.PC.scrotum = V.PC.balls + 1; + V.PC.foreskin = V.PC.dick; + V.PC.pubertyXY = 0; + } + } else if (V.PC.physicalAge <= 18) { + V.PC.hips = -2; + V.PC.shoulders = 0; + V.PC.butt = 1; + V.PC.boobs = 200; + if (V.PC.vagina !== -1) { + V.PC.vagina = 1; + V.PC.vaginaLube = 0; + V.PC.pubertyXX = 1; + } + V.PC.pregAdaptation = 15; + if (V.PC.dick !== 0) { + V.PC.dick = 3; + V.PC.balls = 3; + V.PC.scrotum = V.PC.balls; + V.PC.foreskin = V.PC.dick; + V.PC.pubertyXY = 1; + } + } else { + V.PC.hips = -1; + V.PC.shoulders = 1; + V.PC.butt = 2; + V.PC.boobs = 200; + if (V.PC.vagina !== -1) { + V.PC.vagina = 1; + V.PC.vaginaLube = 1; + V.PC.pubertyXX = 1; + } + V.PC.pregAdaptation = 20; + if (V.PC.dick !== 0) { + V.PC.dick = 4; + V.PC.balls = 3; + V.PC.scrotum = V.PC.balls + 1; + V.PC.foreskin = V.PC.dick; + V.PC.pubertyXY = 1; + } + } + } else { + if (V.PC.physicalAge <= 13) { + V.PC.hips = -2; + V.PC.shoulders = -2; + V.PC.butt = 0; + V.PC.boobs = 350; + if (V.PC.vagina !== -1) { + V.PC.vagina = 0; + V.PC.vaginaLube = 0; + if (V.PC.preg <= 0) { + V.PC.pubertyXX = 0; + } + } + V.PC.pregAdaptation = 30; + if (V.PC.dick !== 0) { + V.PC.dick = 2; + V.PC.balls = 2; + V.PC.scrotum = V.PC.balls + 1; + V.PC.foreskin = V.PC.dick; + V.PC.pubertyXY = 0; + } + } else if (V.PC.physicalAge <= 18) { + V.PC.hips = 0; + V.PC.shoulders = -1; + V.PC.butt = 1; + V.PC.boobs = 600; + if (V.PC.vagina !== -1) { + V.PC.vagina = 1; + V.PC.vaginaLube = 1; + V.PC.pubertyXX = 1; + } + V.PC.pregAdaptation = 50; + if (V.PC.dick !== 0) { + V.PC.dick = 3; + V.PC.balls = 3; + V.PC.scrotum = V.PC.balls; + V.PC.foreskin = V.PC.dick; + V.PC.pubertyXY = 1; + } + } else { + V.PC.hips = 1; + V.PC.shoulders = 0; + V.PC.butt = 2; + V.PC.boobs = 900; + if (V.PC.vagina !== -1) { + V.PC.vagina = 1; + V.PC.vaginaLube = 1; + V.PC.pubertyXX = 1; + } + V.PC.pregAdaptation = 50; + if (V.PC.dick !== 0) { + V.PC.dick = 4; + V.PC.balls = 3; + V.PC.scrotum = V.PC.balls + 1; + V.PC.foreskin = V.PC.dick; + V.PC.pubertyXY = 1; + } + } + if (V.PC.boobs < 250) { + V.PC.nipples = "tiny"; + } else if (V.PC.boobs < 1000) { + V.PC.nipples = "cute"; + } else { + V.PC.nipples = "puffy"; + } + } +}; + +App.UI.Player.assignCareerByAge = function(selection) { + let career; + + if (V.disableForcedCareers || V.PC.actualAge >= 22) { + career = selection; + } else if (selection === "wealth") { + if (V.PC.actualAge < 14) { + career = "rich kid"; + } else { + career = "trust fund"; + } + } else if (selection === "capitalist") { + if (V.PC.actualAge < 14) { + career = "business kid"; + } else { + career = "entrepreneur"; + } + } else if (selection === "mercenary") { + if (V.PC.actualAge < 14) { + career = "child soldier"; + } else { + career = "recruit"; + } + } else if (selection === "slaver") { + if (V.PC.actualAge < 14) { + career = "slave tender"; + } else { + career = "slave overseer"; + } + } else if (selection === "engineer") { + if (V.PC.actualAge < 14) { + career = "worksite helper"; + } else { + career = "construction"; + } + } else if (selection === "medicine") { + if (V.PC.actualAge < 14) { + career = "nurse"; + } else { + career = "medical assistant"; + } + } else if (selection === "celebrity") { + if (V.PC.actualAge < 14) { + career = "child star"; + } else { + career = "rising star"; + } + } else if (selection === "BlackHat") { + if (V.PC.actualAge < 14) { + career = "script kiddy"; + } else { + career = "hacker"; + } + } else if (selection === "escort") { + if (V.PC.actualAge < 14) { + career = "child prostitute"; + } else { + career = "prostitute"; + } + } else if (selection === "servant") { + if (V.PC.actualAge < 14) { + career = "child servant"; + } else { + career = "handmaiden"; + } + } else if (selection === "gang") { + if (V.PC.actualAge < 14) { + career = "street urchin"; + } else { + career = "hoodlum"; + } + } + + V.disableForcedCareers = null; + + return career; +}; + App.UI.Player.refreshmentChoice = function(options) { let option = options.addOption("Your preferred refreshment is", "refreshmentType", V.PC); for (const [key, value] of App.Data.player.refreshmentType) { @@ -112,6 +551,12 @@ App.UI.Player.design = function() { .addRange(55, 65, "<", "Well into middle age").addRange(70, 65, ">=", "Old"); options.addOption(`Your birthday was <strong>${V.PC.birthWeek}</strong> weeks ago.`, "birthWeek", V.PC).showTextBox(); + option = options.addCustomOption() + .addButton( + "Adjust body to match age", + () => App.UI.Player.syncAgeBasedParameters(), + "" + ); } } else { r = []; @@ -123,15 +568,19 @@ App.UI.Player.design = function() { } r.push(`and everyone that matters calls you ${PlayerName()}.`); - r.push(`You are ${V.PC.actualAge} years old which is`); + r.push(`You are ${V.PC.actualAge} years old, which is`); if (V.PC.actualAge >= 65) { r.push(`<strong>old</strong>.`); } else if (V.PC.actualAge >= 50) { r.push(`<strong>well into middle age</strong>.`); } else if (V.PC.actualAge >= 35) { r.push(`<strong>entering middle age</strong>.`); - } else { + } else if (V.PC.actualAge >= 22) { r.push(`<strong>surprisingly young</strong>.`); + } else if (V.PC.actualAge >= 14) { + r.push(`<strong>exceedingly young</strong>.`); + } else { + r.push(`<strong>merely a child</strong>.`); } App.Events.addNode(el, r, "p"); } @@ -161,21 +610,51 @@ App.UI.Player.design = function() { // Appearance if (allowEdits) { - App.UI.Player.appearance(options); + if (V.PC.vagina !== -1 && V.PC.dick !== 0) { + State.temporary.vaginaPenis = 2; + } else if (V.PC.vagina !== -1) { + State.temporary.vaginaPenis = 1; + } else { + State.temporary.vaginaPenis = 0; + } - options.addOption("Your face is", "faceShape", V.PC) - .addValueList([ - ["Normal", "normal"], - ["Androgynous", "androgynous"], - ["Masculine", "masculine"], - ["Cute", "cute"], - ["Sensual", "sensual"], - ["Exotic", "exotic"] - ]); + option = options.addOption("You have a", "vaginaPenis", State.temporary) + .addValue("Penis", 0, () => { + V.PC.preg = 0; + V.PC.pregType = 0; + V.PC.dick = 4; + V.PC.balls = 3; + V.PC.scrotum = 3; + V.PC.prostate = 1; + V.PC.vagina = -1; + V.PC.ovaries = 0; + }).addValue("Vagina", 1, () => { + V.PC.dick = 0; + V.PC.balls = 0; + V.PC.scrotum = 0; + V.PC.prostate = 0; + V.PC.vagina = 1; + V.PC.ovaries = 1; + }).addValue("Penis and Vagina", 2, () => { + V.PC.dick = 4; + V.PC.balls = 3; + V.PC.scrotum = 3; + V.PC.prostate = 1; + V.PC.vagina = 1; + V.PC.ovaries = 1; + }); + if (State.temporary.vaginaPenis === 0) { + option.addComment("Standard sex scenes; easiest reputation maintenance."); + } else if (State.temporary.vaginaPenis === 1) { + option.addComment("Sex scene variations; most difficult reputation maintenance."); + } else { + option.addComment("Sex scene variations; more difficult reputation maintenance; some unique opportunities, especially with breasts."); + } + App.UI.Player.appearance(options, true); } else { r = []; - r.push(`You are a ${V.PC.nationality} ${V.PC.race} with`); + r.push(`You are a ${heightToEitherUnit(V.PC)} tall ${V.PC.nationality} ${V.PC.race} with`); if (V.PC.markings === "heavily freckled") { r.push(`heavily freckled`); } else if (V.PC.markings === "freckles") { @@ -183,7 +662,18 @@ App.UI.Player.design = function() { } else { r.push(`clear`); } - r.push(`${V.PC.skin} skin, ${V.PC.hColor} hair and ${App.Desc.eyesColor(V.PC)}. You have a ${V.PC.faceShape} face.`); + r.push(`${V.PC.skin} skin, ${V.PC.hColor} hair and ${App.Desc.eyesColor(V.PC)}. You have a ${V.PC.faceShape}`); + if (V.PC.lips > 95) { + r.push(`face with way too much lip; you can't shut your mouth properly anymore.`); + } else if (V.PC.lips > 70) { + r.push(`face with truly massive lips.`); + } else if (V.PC.lips > 40) { + r.push(`face with plump lips.`); + } else if (V.PC.lips > 20) { + r.push(`face with full lips.`); + } else { + r.push(`face.`); + } App.Events.addNode(el, r, "p"); } @@ -209,40 +699,35 @@ App.UI.Player.design = function() { ["Servant", "servant"], ["Gang leader", "gang"]] ); + option = options.addCustomOption() + .addButton( + "Adjust career for age", + () => V.PC.career = App.UI.Player.assignCareerByAge(V.PC.career), + "" + ); if (V.secExpEnabled > 0) { - switch (V.PC.career) { - case "capitalist": - option.addComment(`<div><span class="yellowgreen">The propaganda hub's upgrades will be cheaper.</span></div>`); - break; - case "mercenary": - option.addComment(`<div><span class="green">Easier to maintain security</span> and <span class="yellowgreen">the security HQ's upgrades will be cheaper.</span></div>`); - break; - case "slaver": - option.addComment(`<div><span class="green">Easier to maintain authority</span> and <span class="yellowgreen">the security HQ's upgrades will be cheaper.</span></div>`); - break; - case "engineer": - option.addComment(`<div><span class="yellowgreen">construction and upgrade of facilities will be cheaper.</span></div>`); - break; - case "medicine": - option.addComment(`<div><span class="yellowgreen">Drug upgrades will be cheaper.</span></div>`); - break; - case "celebrity": - option.addComment(`<div><span class="yellowgreen">The propaganda hub's upgrades will be cheaper.</span></div>`); - break; - case "escort": - option.addComment(`<div><span class="red">Harder to maintain authority.</span></div>`); - break; - case "servant": - option.addComment(`<div><span class="red">Harder to maintain authority.</span></div>`); - break; - case "gang": - option.addComment(`<div><span class="green">Easier to maintain authority</span> and <span class="yellowgreen">the security HQ's upgrades will be cheaper.</span></div>`); - break; - case "BlackHat": - option.addComment(`<div><span class="red">Harder to maintain authority.</span></div>`); - break; - default: - option.addComment(`<div><span class="red">Harder to maintain authority,</span> but <span class="yellowgreen">the propaganda hub's upgrades will be cheaper.</span></div>`); + if (isPCCareerInCategory("capitalist")) { + option.addComment(`<div><span class="yellowgreen">The propaganda hub's upgrades will be cheaper.</span></div>`); + } else if (isPCCareerInCategory("mercenary")) { + option.addComment(`<div><span class="green">Easier to maintain security</span> and <span class="yellowgreen">the security HQ's upgrades will be cheaper.</span></div>`); + } else if (isPCCareerInCategory("slaver")) { + option.addComment(`<div><span class="green">Easier to maintain authority</span> and <span class="yellowgreen">the security HQ's upgrades will be cheaper.</span></div>`); + } else if (isPCCareerInCategory("engineer")) { + option.addComment(`<div><span class="yellowgreen">construction and upgrade of facilities will be cheaper.</span></div>`); + } else if (isPCCareerInCategory("medicine")) { + option.addComment(`<div><span class="yellowgreen">Drug upgrades will be cheaper.</span></div>`); + } else if (isPCCareerInCategory("celebrity")) { + option.addComment(`<div><span class="yellowgreen">The propaganda hub's upgrades will be cheaper.</span></div>`); + } else if (isPCCareerInCategory("escort")) { + option.addComment(`<div><span class="red">Harder to maintain authority.</span></div>`); + } else if (isPCCareerInCategory("servant")) { + option.addComment(`<div><span class="red">Harder to maintain authority.</span></div>`); + } else if (isPCCareerInCategory("gang")) { + option.addComment(`<div><span class="green">Easier to maintain authority</span> and <span class="yellowgreen">the security HQ's upgrades will be cheaper.</span></div>`); + } else if (isPCCareerInCategory("BlackHat")) { + option.addComment(`<div><span class="red">Harder to maintain authority.</span></div>`); + } else { + option.addComment(`<div><span class="red">Harder to maintain authority,</span> but <span class="yellowgreen">the propaganda hub's upgrades will be cheaper.</span></div>`); } } } @@ -261,39 +746,81 @@ App.UI.Player.design = function() { r = []; switch (V.PC.career) { case "wealth": + case "trust fund": + case "rich kid": r.push(`Prior to being an arcology owner, you were a member of the idle wealthy.`); break; case "capitalist": r.push(`Prior to being an arcology owner, you were a business leader.`); break; + case "entrepreneur": + case "business kid": + r.push(`Prior to being an arcology owner, you were a cunning entrepreneur.`); + break; case "mercenary": + case "recruit": r.push(`Prior to being an arcology owner, you were a mercenary.`); break; + case "child soldier": + r.push(`Prior to being an arcology owner, you were a disposable conscript.`); + break; case "slaver": + case "slave overseer": r.push(`Prior to being an arcology owner, you were a slaver.`); break; + case "slave tender": + r.push(`Prior to being an arcology owner, you were a slaver tasked with looking after fresh captures.`); + break; case "engineer": r.push(`Prior to being an arcology owner, you were an engineer.`); break; + case "construction": + case "worksite helper": + r.push(`Prior to being an arcology owner, you built buildings.`); + break; case "medicine": r.push(`Prior to being an arcology owner, you were a surgeon.`); break; + case "medical assistant": + r.push(`Prior to being an arcology owner, you assisted with surgeries.`); + break; + case "nurse": + r.push(`Prior to being an arcology owner, you were a nurse.`); + break; case "celebrity": r.push(`Prior to being an arcology owner, you were a minor celebrity.`); break; + case "rising star": + r.push(`Prior to being an arcology owner, you were an up-and-coming star.`); + break; + case "child star": + r.push(`Prior to being an arcology owner, you were a child actor.`); + break; case "BlackHat": + case "hacker": + case "script kiddy": r.push(`Prior to being an arcology owner, you specialized in cracking databases and making mockeries of cyber security.`); break; case "arcology owner": r.push(`Being an arcology owner defines your life now.`); break; case "escort": + case "prostitute": r.push(`Prior to being an arcology owner, you knew how to survive off your looks and body.`); break; + case "child prostitute": + r.push(`Prior to being an arcology owner, you had no choice but to sell your body to survive.`); + break; case "servant": + case "handmaiden": + case "child servant": r.push(`Prior to being an arcology owner, you served a well-off`); - if (V.PC.counter.birthMaster >= 2) { + if (V.PC.counter.birthMaster >= 8) { + r.push(`master as his breeder.`); + } else if (V.PC.counter.birthMaster >= 2) { r.push(`master and bore him several children.`); + } else if (V.PC.counter.birthMaster >= 1) { + r.push(`master and bore him a child.`); } else { r.push(`master.`); } @@ -301,6 +828,12 @@ App.UI.Player.design = function() { case "gang": r.push(`Prior to being an arcology owner, you were the leader of a ruthless gang.`); break; + case "hoodlum": + r.push(`Prior to being an arcology owner, you were a troublemaker in a gang.`); + break; + case "street urchin": + r.push(`Prior to being an arcology owner, you lived a hard life on the streets.`); + break; } r.push(`Word in the arcology is you acquired it through`); @@ -330,47 +863,7 @@ App.UI.Player.design = function() { if (allowEdits) { options = new App.UI.OptionsGroup(); - if (V.PC.vagina !== -1 && V.PC.dick !== 0) { - State.temporary.vaginaPenis = 2; - } else if (V.PC.vagina !== -1) { - State.temporary.vaginaPenis = 1; - } else { - State.temporary.vaginaPenis = 0; - } - - option = options.addOption("You have a", "vaginaPenis", State.temporary) - .addValue("Penis", 0, () => { - V.PC.preg = 0; - V.PC.pregType = 0; - V.PC.dick = 4; - V.PC.balls = 3; - V.PC.scrotum = 3; - V.PC.prostate = 1; - V.PC.vagina = -1; - V.PC.ovaries = 0; - }).addValue("Vagina", 1, () => { - V.PC.dick = 0; - V.PC.balls = 0; - V.PC.scrotum = 0; - V.PC.prostate = 0; - V.PC.vagina = 1; - V.PC.ovaries = 1; - }).addValue("Penis and Vagina", 2, () => { - V.PC.dick = 4; - V.PC.balls = 3; - V.PC.scrotum = 3; - V.PC.prostate = 1; - V.PC.vagina = 1; - V.PC.ovaries = 1; - }); - if (State.temporary.vaginaPenis === 0) { - option.addComment("Standard sex scenes; easiest reputation maintenance."); - } else if (State.temporary.vaginaPenis === 1) { - option.addComment("Sex scene variations; most difficult reputation maintenance."); - } else { - option.addComment("Sex scene variations; more difficult reputation maintenance; some unique opportunities, especially with breasts."); - } - + // obsolete? if (V.cheatMode) { options.addOption("Vagina", "vagina", V.PC).showTextBox(); options.addOption("New vagina", "newVag", V.PC).showTextBox(); @@ -385,7 +878,7 @@ App.UI.Player.design = function() { options.addOption("Balls implant", "ballsImplant", V.PC).showTextBox(); } - if (V.PC.vagina !== -1) { + if (V.PC.vagina !== -1 && V.PC.pubertyXX === 1) { option = options.addOption("You are", "preg", V.PC) .addValue("Taking contraceptives", -1, () => { V.PC.pregType = 0; V.PC.labor = 0; }) .addValue("Not taking contraceptives", 0, () => { V.PC.pregType = 0; V.PC.labor = 0; }) @@ -438,83 +931,201 @@ App.UI.Player.design = function() { } } - if (V.PC.title === 1 && V.PC.boobs <= 100) { - option = options.addOption("Your chest is", "boobs", V.PC).addValue("Manly", 100, () => V.PC.boobsImplant = 0); + el.append(options.render()); + } else { + r = []; + + if (V.PC.boobs >= 300) { + r.push(`You have a`); + if (V.PC.title > 0) { + r.push(`masculine`); + } else { + r.push(`feminine`); + } + r.push(`body with`); + if (V.PC.shoulders > 1) { + r.push(`very broad shoulders`); + } else if (V.PC.shoulders > 0) { + r.push(`broad shoulders`); + } else if (V.PC.shoulders < -1) { + r.push(`very narrow shoulders`); + } else if (V.PC.shoulders < 0) { + r.push(`narrow shoulders`); + } + if (V.PC.shoulders !== 0) { + r.push(`and`); + } + let breastShapeDesc; + if (V.PC.boobShape === "saggy") { + breastShapeDesc = ` that sag a bit`; + } else if (V.PC.boobShape === "spherical") { + breastShapeDesc = ` that might just be a little too much implant now.`; + } + if (V.PC.boobs >= 1400) { + r.push(`giant${(V.PC.boobsImplant !== 0) ? `, fake` : ``} cow tits${breastShapeDesc}.`); + } else if (V.PC.boobs >= 1200) { + r.push(`huge`); + if (V.PC.boobsImplant !== 0) { + r.push(`fake`); + } + r.push(`breasts${breastShapeDesc}.`); + } else if (V.PC.boobs >= 1000) { + r.push(`big`); + if (V.PC.boobsImplant !== 0) { + r.push(`fake`); + } + r.push(`breasts${breastShapeDesc}.`); + } else if (V.PC.boobs >= 800) { + r.push(`noticeable breasts${breastShapeDesc}.`); + } else if (V.PC.boobs >= 650) { + r.push(`unremarkable breasts${breastShapeDesc}.`); + } else if (V.PC.boobs >= 500) { + r.push(`average breasts${breastShapeDesc}.`); + } else { + r.push(`small breasts${breastShapeDesc}.`); + } } else { - option = options.addOption("Your breasts are", "boobs", V.PC).addValue("Flat", 100, () => V.PC.boobsImplant = 0); + if (V.PC.title > 0) { + r.push(`You have a manly chest.`); + } else { + r.push(`You are flat as a board.`); + } } - option.addValueList([ - ["C-cups", 500], - ["DD-cups", 900], - ["F-cups", 1100], - ["G-cups", 1300] - ]); - option.showTextBox("CCs"); - - if (V.PC.boobs >= 500) { - options.addOption("Your breasts are", "boobsImplant", V.PC) - .addValueList([ - ["All natural", 0], - ["Fake", 400] - ]) - .showTextBox("CCs"); + r.push(`Around back, you have`); + if (V.PC.butt > 10) { + r.push(`a disproportionate swelling of flesh`); + } else if (V.PC.butt > 7) { + r.push(`an absurdly large butt`); + } else if (V.PC.butt > 6) { + r.push(`a ridiculous ass`); + } else if (V.PC.butt > 5) { + r.push(`a gigantic ass`); + } else if (V.PC.butt > 4) { + r.push(`an enormous ass`); + } else if (V.PC.butt > 3) { + r.push(`a huge ass`); + } else if (V.PC.butt > 2) { + r.push(`a big butt`); + } else if (V.PC.butt > 1) { + r.push(`a shapely rear`); + } else if (V.PC.butt > 0) { + r.push(`a trim rear`); + } else { + r.push(`a flat ass`); } - - if (V.cheatMode) { - if (V.PC.boobs >= 500) { - options.addOption("Your breasts are", "lactation", V.PC) - .addValueList([ - ["Lactating", 1], - ["Not Lactating", 0] - ]); - } + r.push(`attached to a pair of`); + if (V.PC.hips > 2) { + r.push(`inhumanly wide hips.`); + } else if (V.PC.hips > 1) { + r.push(`very wide hips.`); + } else if (V.PC.hips > 0) { + r.push(`wide hips.`); + } else if (V.PC.hips > -1) { + r.push(`average hips.`); + } else if (V.PC.hips > -2) { + r.push(`narrow hips.`); + } else { + r.push(`very narrow hips.`); } - options.addOption("Your butt size", "butt", V.PC) - .addValueList([ - ["Normal", 2], - ["Big", 3], - ["Huge", 4], - ["Enormous", 5], - ]) - .showTextBox(); - - options.addOption("Your butt is", "buttImplant", V.PC) - .addValueList([ - ["All natural", 0], - ["Fake", 1] - ]) - .showTextBox("CCs"); - - - options.addOption("You are genetically", "genes", V.PC) - .addValue("XY").addValue("XX"); - - el.append(options.render()); - } else { - r = []; - r.push(`You have a`); - if (V.PC.vagina !== -1 && V.PC.dick !== 0) { - r.push(`penis and vagina`); - } else if (V.PC.dick !== 0) { - r.push(`penis.`); - } else if (V.PC.vagina !== -1) { - r.push(`vagina`); + r.push(`Between your legs, you have`); + if (V.PC.dick !== 0) { + if (V.PC.dick === 1) { + r.push(`a tiny, humilating`); + } else if (V.PC.dick === 2) { + r.push(`a small`); + } else if (V.PC.dick === 3) { + r.push(`an average`); + } else if (V.PC.dick === 4) { + r.push(`a big`); + } else if (V.PC.dick === 5) { + r.push(`a huge`); + } else if (V.PC.dick === 6) { + r.push(`a pussy wrecking`); + } else if (V.PC.dick === 7) { + r.push(`a massive, unusable`); + } else if (V.PC.dick === 8) { + r.push(`an imposing, if unusable,`); + } else if (V.PC.dick === 9) { + r.push(`a monster of a`); + } else if (V.PC.dick === 10) { + r.push(`an inhuman`); + } else { + r.push(`an unusable slab of sensetive flesh you call a`); + } + r.push(`dick`); + if (V.PC.balls !== 0) { + r.push(r.pop() + ","); + } + if (V.PC.balls === 1) { + if (V.PC.scrotum === 0) { + r.push(`a tiny pair of internal balls`); + } else { + r.push(`vestigial testicles`); + } + } else if (V.PC.balls === 2) { + if (V.PC.scrotum === 0) { + r.push(`a pair of internal balls`); + } else { + r.push(`a pair of small testicles`); + } + } else if (V.PC.balls === 3) { + r.push(`a pair of average testicles`); + } else if (V.PC.balls === 4) { + r.push(`a dangling pair of large balls`); + } else if (V.PC.balls === 5) { + r.push(`a dangling pair of heavy testicles`); + } else if (V.PC.balls === 6) { + r.push(`a heavy pair of huge balls`); + } else if (V.PC.balls === 7) { + r.push(`a ponderous set of giant testicles`); + } else if (V.PC.balls === 8) { + r.push(`a ponderous set of enormous testicles`); + } else if (V.PC.balls === 9) { + r.push(`a monstrous pair of testicles`); + } else { + r.push(`an inhuman pair of testicles`); + } + if (V.PC.vagina !== -1) { + r.push(`and`); + } else { + r.push(r.pop() + "."); + } } if (V.PC.vagina !== -1) { - r.push(`and are`); + if (V.PC.vagina === 0) { + r.push(`an unsullied`); + } else if (V.PC.vagina === 1 || V.PC.newVag === 1) { + // nothing + } else if (V.PC.vagina === 2) { + r.push(`an experienced`); + } else if (V.PC.vagina === 3) { + r.push(`a loose`); + } else if (V.PC.vagina === 4) { + r.push(`a very well-traveled`); + } else { + r.push(`a ruined`); + } + r.push(`vagina.`); + } + if (V.PC.vagina !== -1 && V.PC.mpreg !== 0) { + r.push(`You are`); if (V.PC.pregWeek < 0) { - r.push(`recovering from your last pregnancy.`); + r.push(`currently recovering from your last pregnancy.`); } else if (V.PC.preg === -2) { - r.push(`infertile.`); + r.push(`infertile and can't get pregnant.`); } else if (V.PC.preg === -1) { - r.push(`taking contraceptives.`); + r.push(`taking contraceptives to avoid potential pregnancy.`); } else if (V.PC.preg === 0) { - r.push(`fertile.`); + if (V.PC.pubertyXX === 0) { + r.push(`not yet fertile.`); + } else { + r.push(`fertile and capable of becoming pregnant.`); + } } else if (V.PC.preg > 37) { - r.push(`extremely pregnant.`); + r.push(`extremely pregnant and likely to give birth soon.`); } else if (V.PC.preg > 0) { - r.push(`pregnant.`); + r.push(`currently pregnant.`); } linkArray = []; @@ -548,44 +1159,6 @@ App.UI.Player.design = function() { } } - if (V.PC.boobs >= 300) { - r.push(`You have a`); - if (V.PC.title > 0) { - r.push(`masculine`); - } else { - r.push(`feminine`); - } - r.push(`body with`); - if (V.PC.boobs >= 1400) { - r.push(`giant${(V.PC.boobsImplant !== 0) ? `, fake` : ``} cow tits.`); - } else if (V.PC.boobs >= 1200) { - r.push(`huge`); - if (V.PC.boobsImplant !== 0) { - r.push(`fake`); - } - r.push(`breasts.`); - } else if (V.PC.boobs >= 1000) { - r.push(`big`); - if (V.PC.boobsImplant !== 0) { - r.push(`fake`); - } - r.push(`breasts.`); - } else if (V.PC.boobs >= 800) { - r.push(`noticeable breasts.`); - } else if (V.PC.boobs >= 650) { - r.push(`unremarkable breasts.`); - } else if (V.PC.boobs >= 500) { - r.push(`average breasts.`); - } else { - r.push(`small breasts.`); - } - } else { - if (V.PC.title > 0) { - r.push(`You have a manly chest.`); - } else { - r.push(`You are flat as a board.`); - } - } App.Events.addNode(el, r, "p"); } diff --git a/src/events/intro/pcAppearanceIntro.tw b/src/events/intro/pcAppearanceIntro.tw index 3854ab1ddaba89663f214985123f95b35b00ad02..e982aa0d9f2fba6a8a77381876e23bbf9fe15557 100644 --- a/src/events/intro/pcAppearanceIntro.tw +++ b/src/events/intro/pcAppearanceIntro.tw @@ -3,7 +3,7 @@ <p> Race and appearance are largely irrelevant in the Free Cities; there are only the free and the enslaved. <div class="indent note"> - Appearance only, no effect on gameplay (unless you make a big deal out of it). + Appearance only, will mostly have a superficial effect (unless you make a big deal out of it). </div> </p> <<set _options = new App.UI.OptionsGroup()>> @@ -11,5 +11,9 @@ <<includeDOM _options.render()>> <p> - [[Finish player character customization|PC Experience Intro][resetEyeColor($PC)]] + <<if isFertile(V.PC)>> + [[Continue player character customization|PC Preg Intro][resetEyeColor($PC)]] + <<else>> + [[Finish player character customization|PC Experience Intro][resetEyeColor($PC)]] + <</if>> </p> diff --git a/src/events/intro/pcBodyIntro.js b/src/events/intro/pcBodyIntro.js index 187dd896654d64c5c0566bd03ea4b485aac01227..4e79456cceec29f98b1a28a135513a1d6ef14dbe 100644 --- a/src/events/intro/pcBodyIntro.js +++ b/src/events/intro/pcBodyIntro.js @@ -1,7 +1,6 @@ App.Intro.PCBodyIntro = function() { + V.PC.actualAge = Math.clamp(V.PC.actualAge, 14, 80); - V.PC.physicalAge = V.PC.actualAge; - V.PC.visualAge = V.PC.actualAge; const el = new DocumentFragment(); let r = []; @@ -121,19 +120,23 @@ App.Intro.PCBodyIntro = function() { App.UI.DOM.appendNewElement("div", el, `How old are you?`, ["intro", "question"]); const r = []; - r.push(`I'm`); + r.push(`You're`); if (V.PC.actualAge >= 65) { - r.push(`getting up in years. I've made a legacy for myself, and I'm not done yet.`); + r.push(`getting up in years. You've made a legacy for myself, and not done with life just yet.`); } else if (V.PC.actualAge >= 50) { - r.push(`well into middle age. I've made a name for myself, and I've still got it.`); + r.push(`well into middle age. You've made a name for myself, and still got your groove.`); } else if (V.PC.actualAge >= 35) { - r.push(`entering middle age. I'm accomplished, and I retain some youthful vigor.`); + r.push(`entering middle age. You're accomplished, and retain some youthful vigor.`); + } else if (V.PC.actualAge >= 22) { + r.push(`surprisingly young. You'll need to prove myself, but you've got energy to burn.`); + } else if (V.PC.actualAge >= 14) { + r.push(`exceedingly young. You're nobody, but you're full of youthful vigor and ready to make the world yours.`); } else { - r.push(`surprisingly young. I'll need to prove myself, but I've got energy to burn.`); + r.push(`just a child. You may be emancipated, but society won't accept you as a leader.`); } r.push(`My age:`); options.addOption(r.join(" "), "actualAge", V.PC).showTextBox() - .addComment(`Older player characters start with more reputation and maintain reputation somewhat more easily, but have slightly less sexual energy.`); + .addComment(`Older player characters start with more reputation and maintain reputation somewhat more easily, but have slightly less sexual energy. Exceedingly young characters will not be accepted by society, even more so if underage, and will face additional hurdles and complications.`); el.append(options.render()); @@ -156,12 +159,17 @@ App.Intro.PCBodyIntro = function() { function endScene() { const el = document.createElement("p"); - const linkTitle = "Confirm player character customization"; - if (V.PC.vagina !== -1) { - el.append(App.UI.DOM.passageLink(linkTitle, "PC Preg Intro")); - } else { - el.append(App.UI.DOM.passageLink(linkTitle, "PC Appearance Intro")); - } + el.append( + App.UI.DOM.link( + "Confirm player character overview", + () => { + App.UI.Player.syncAgeBasedParameters(); + }, + [], + "PC Appearance Intro" + ) + ); + return el; } }; diff --git a/src/events/intro/pcExperienceIntro.tw b/src/events/intro/pcExperienceIntro.tw index 422ae0db6cbf415fac6867c2f070259de93e027b..137604a09654c94de2023a77bb4342327cc7eb83 100644 --- a/src/events/intro/pcExperienceIntro.tw +++ b/src/events/intro/pcExperienceIntro.tw @@ -3,6 +3,10 @@ <<if $PC.career == "arcology owner">> <<goto "PC Rumor Intro">> <<else>> + <<if !$disableForcedCareers>> + <<set $disableForcedCareers = $PC.actualAge >= 22 ? 1 : 0>> + <</if>> + <p> You're a relative unknown in the Free Cities, but it's clear you're already accomplished. The meek and average cannot aspire to acquire arcologies. You've got all the necessary skills to take over an arcology and succeed as its owner, but you should be able to leverage the skills and experience you retain from your past, too. <span class="intro question"> @@ -11,7 +15,7 @@ </p> <div> - [[Idle wealth|PC Rumor Intro][$PC.career = "wealth"]] + [[Idle wealth|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("wealth")]] </div> <div class="indent note"> Start with <span class="cash inc">extra money.</span> @@ -22,7 +26,7 @@ </div> <div> - [[Venture capitalism|PC Rumor Intro][$PC.career = "capitalist"]] + [[Venture capitalism|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("capitalist")]] </div> <div class="indent note"> You will be more @@.green;effective at business pursuits.@@ @@ -33,7 +37,7 @@ </div> <div> - [[Private military work|PC Rumor Intro][$PC.career = "mercenary"]] + [[Private military work|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("mercenary")]] </div> <div class="indent note"> You retain mercenary contacts @@ -46,7 +50,7 @@ </div> <div> - [[Slaving|PC Rumor Intro][$PC.career = "slaver"]] + [[Slaving|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("slaver")]] </div> <div class="indent note"> Your slave breaking experience will be useful. @@ -57,21 +61,21 @@ </div> <div> - [[Arcology engineering|PC Rumor Intro][$PC.career = "engineer"]] + [[Engineering|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("engineer")]] </div> <div class="indent note"> <span class="cash inc">Upgrading the arcology will be cheaper.</span> Also, the arcology will start with <span class="cash inc">basic economic upgrades</span> already installed. </div> <div> - [[Slave surgery|PC Rumor Intro][$PC.career = "medicine"]] + [[Surgery|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("medicine")]] </div> <div class="indent note"> Surgery will be <span class="cash inc">cheaper</span> and @@.green;healthier@@ and <span class="cash inc">drug upgrades will be cheaper.</span> Your starting slaves will have free implants available. </div> <div> - [[Minor celebrity|PC Rumor Intro][$PC.career = "celebrity"]] + [[Minor celebrity|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("celebrity")]] </div> <div class="indent note"> Start with @@.green;extra reputation.@@ @@ -82,7 +86,7 @@ </div> <div> - [[High class escort|PC Rumor Intro][$PC.career = "escort"]] + [[Sex industry|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("escort")]] </div> <div class="indent note"> As an ex-whore, you will find it @@.red;hard to maintain reputation@@<<if $showSecExp == 1>>, @@.red;in addition to authority@@<</if>>. @@ -90,7 +94,7 @@ </div> <div> - [[Servant|PC Rumor Intro][$PC.career = "servant"]] + [[Servant|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("servant")]] </div> <div class="indent note"> As an ex-servant, you will find it @@.red;hard to maintain reputation@@<<if $showSecExp == 1>>, @@.red;in addition to authority@@<</if>>. @@ -98,10 +102,10 @@ </div> <div> - [[Gang Leader|PC Rumor Intro][$PC.career = "gang"]] + [[Gang affiliation|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("gang")]] </div> <div class="indent note"> - As an ex-gang leader, you know how to haggle slaves. + As an ex-gang member, you know how to haggle slaves. <<if $showSecExp == 1>> In addition, asserting your authority @@.green;will be easier@@ and <span class="cash inc">security HQ upgrades will be cheaper.</span> <</if>> @@ -109,10 +113,10 @@ </div> <div> - [[Incursion Specialist|PC Rumor Intro][$PC.career = "BlackHat"]] + [[Incursion Specialist|PC Rumor Intro][$PC.career = App.UI.Player.assignCareerByAge("BlackHat")]] </div> <div class="indent note"> - As an ex-hacker for hire, you know how to gain access computer systems and other devices. @@.green;Certain upgrades will be cheaper@@ and you may find alternative approaches to problems. + As an ex-hacker, you know how to gain access computer systems and other devices. @@.green;Certain upgrades will be cheaper@@ and you may find alternative approaches to problems. <<if $showSecExp == 1>> However, you will @@.red;find authority quite hard@@ to maintain. <</if>> @@ -130,4 +134,29 @@ <<set $showSecExp = 1>> <</link>> <</if>> +</p> + +<p> + <<if $disableForcedCareers != 1>> + <<link "Disable forced career choices" "PC Experience Intro">> + <<set $disableForcedCareers = 1>> + <</link>> + <div class="indent note"> + <<if $PC.actualAge < 14>> + Due to your young age, you will be given the child variant of your chosen career line. + <<elseif $PC.actualAge < 22>> + Due to your age, you will be given the inexperienced variant of your chosen career line. + <</if>> + Over time and with effort, you will be capable of achieving everything of importance in the adult careers. + </div> + <<else>> + <<if $PC.actualAge < 22>> + <<link "Enable forced career choices" "PC Experience Intro">> + <<set $disableForcedCareers = 0>> + <</link>> + <div class="indent note"> + Use age based careers. + </div> + <</if>> + <</if>> </p> \ No newline at end of file diff --git a/src/events/intro/pcPregIntro.tw b/src/events/intro/pcPregIntro.tw index 71d6886523392ae37b5375261bf849c69ec9a7ef..78ffe760712e87a063df04f0cf8f60a1c576f4a7 100644 --- a/src/events/intro/pcPregIntro.tw +++ b/src/events/intro/pcPregIntro.tw @@ -54,5 +54,5 @@ </div> </p> <p> - [[Confirm player character customization|PC Appearance Intro]] + [[Confirm player character customization|PC Experience Intro]] </p> diff --git a/src/events/nonRandom/pAbducted.js b/src/events/nonRandom/pAbducted.js index 4067dd1b46a36f9635ab6bdc7c18a1dc14ce351e..18eb7c21c7445626c2e7084d961244a9a9681b02 100644 --- a/src/events/nonRandom/pAbducted.js +++ b/src/events/nonRandom/pAbducted.js @@ -87,7 +87,8 @@ App.Events.pAbducted = class pAbducted extends App.Events.BaseEvent { cashX(-1000, "event"); } continueButton(node); - // injury code here + V.PC.health.shortDamage = 2; + V.PC.health.longDamage = 1; } else { r.push(`Once your vision is obscured, your attacker sweeps your legs and tosses you into a waiting crate.`); r.push(Spoken(abductor, `"Be a good little ${girlP} and keep quiet. Wouldn't want anything bad to happen to ya, eh? I'd really hate to damage the merchandise."`)); diff --git a/src/gui/mainMenu/AlphaDisclaimer.tw b/src/gui/mainMenu/AlphaDisclaimer.tw index a911ece80df19776e74e4e23ff5982471fda3f82..0a8d2f9cf61d42b6e21fabcc7c99e37b5094920c 100644 --- a/src/gui/mainMenu/AlphaDisclaimer.tw +++ b/src/gui/mainMenu/AlphaDisclaimer.tw @@ -32,6 +32,9 @@ <div class="note"> version: $ver, mod version: $pmodVer, build: $releaseID<<if App.Version.commitHash>>, commit: <<= App.Version.commitHash>><</if>> </div> + <span style="font-weight:Bold"> /* remove me with 4.0.0! */ + 4.0.0 is in alpha release. This means the new player content has minimal implementation. + </span> <div id="version"> <<link "More version info">> <<replace "#version">> diff --git a/src/js/statsChecker/statsChecker.js b/src/js/statsChecker/statsChecker.js index fd9c58062c802844409818e16f4936a31eed1edf..8ca229103b20d9a2c1958fd9c8bddfa62e7a6e39 100644 --- a/src/js/statsChecker/statsChecker.js +++ b/src/js/statsChecker/statsChecker.js @@ -900,6 +900,14 @@ globalThis.isHindered = function(slave) { } else if (slave.muscles < -30) { return true; } + // player exclusives + if (slave.ID === -1) { + if (onBedRest(slave)) { + return true; + } else if (slave.criticalDamage !== 0) { + return true; + } + } return false; }; diff --git a/src/js/utilsPC.js b/src/js/utilsPC.js index 845579e23f79e57db65befdaf0cb518180b905c7..905c6c460f3b62101e772ec62bbea6df2ce17b44 100644 --- a/src/js/utilsPC.js +++ b/src/js/utilsPC.js @@ -627,6 +627,8 @@ globalThis.onBedRest = function(actor) { // consider player health and injury in the future! if (!actor) { return null; + } else if (actor.health.shortDamage > 0) { + return true; } else if (!canMove(actor)) { return true; } else if (actor.preg > actor.pregData.normalBirth / 1.33 && actor.womb.find((ft) => ft.genetics.geneticQuirks.polyhydramnios === 2 && ft.age >= 20)) { diff --git a/src/player/js/PlayerState.js b/src/player/js/PlayerState.js index befb2e66c94e4b8f9bc05aa7ca1b03bc6fecdd58..dd4173e855497fa45df1def71a10920719d7c37c 100644 --- a/src/player/js/PlayerState.js +++ b/src/player/js/PlayerState.js @@ -312,7 +312,7 @@ App.Entity.PlayerState = class PlayerState { * * 90 - : Unnaturally healthy */ condition: 0, - /** your short term health damage */ + /** your short term health damage, used to determine how long you are in recovery */ shortDamage: 0, /** your long term health damage */ longDamage: 0, @@ -609,7 +609,7 @@ App.Entity.PlayerState = class PlayerState { * * 70000-89999 - door-crowding * * 90000-100000 - door-jamming */ - this.boobs = 100; + this.boobs = 200; /** breast engorgement from unmilked tits */ this.boobsMilk = 0; /** @@ -1879,13 +1879,13 @@ App.Entity.PlayerState = class PlayerState { /** Have you gone through female puberty. * @type {FC.Bool} * 0: no; 1: yes */ - this.pubertyXX = 1; + this.pubertyXX = 0; /** Target .physicalAge for male puberty to occur. */ this.pubertyAgeXY = 13; /** Have you slave gone through male puberty. * @type {FC.Bool} * 0: no; 1: yes */ - this.pubertyXY = 1; + this.pubertyXY = 0; /** * scar * Sub-object: