From d09592f15ef7df768ed67cda31c80d7d8902c79e Mon Sep 17 00:00:00 2001 From: Svornost <11434-svornost@users.noreply.gitgud.io> Date: Thu, 23 Feb 2023 20:09:49 -0500 Subject: [PATCH] Add an art seed and natural growth target for height. 1. Adds a dedicated art seed to each slave. When WebGL art is active, you can change it manually in Starting Girls or in SI Customize. The art seed correctly duplicates onto clones and twins, and is randomized in other cases. BC copies the ID into the seed so that existing art stays the same. Fixes #3647, obsoletes and closes !10432. 2. Sets a natural growth target for height. BC copies from existing height (minus implants) for adult slaves; a new target height is generated for child/teen slaves. Slaves that are supposed to be genetically tall or short (for example, child/teen slaves bought from neighboring arcologies with Petite Admiration or Statuesque Glorification) will now *stay* tall or short throughout their development. Fixes #3838 properly. Also fixes #3813. 3. Adjusted physical development to directly attempt to reach the genetic target height (and in the process, dropped about 1500 lines of code). Supports growth spurts, etc. 4. Height is now heritable, with a heritability factor of 79% as per recent peer-reviewed research (cited in comments). Activated gigantism or dwarfism will reset height inheritance. --- devTools/types/FC/human.d.ts | 7 + src/Mods/Catmod/generateCatgirl.js | 6 +- src/art/webgl/art.js | 107 +- .../backwardsCompatibility.js | 28 +- .../updateSlaveObject.js | 17 + src/endWeek/nextWeek/nextWeek.js | 2 +- src/endWeek/player/prDrugs.js | 4 +- src/endWeek/reports/incubatorReport.js | 18 +- src/endWeek/saDrugs.js | 4 +- src/endWeek/shared/physicalDevelopment.js | 1623 +---------------- src/events/intro/acquisition.js | 2 + src/events/intro/introSummary.js | 1 + src/events/intro/pcAppearance.js | 41 +- src/events/nonRandom/pAidResult.js | 3 +- src/events/reRecruit/orphanFemboy.js | 3 +- src/events/reRecruit/racerDgChaser.js | 3 +- src/events/reRecruit/racerLoser.js | 3 +- src/events/reRecruit/racerWinner.js | 3 +- src/events/reRecruit/starvingArtist.js | 3 +- .../recETS/recetsIncestBrotherBrother.js | 1 - src/events/recETS/recetsIncestTwinBrother.js | 1 - src/events/recETS/recetsIncestTwinSister.js | 1 - src/events/recETS/recetsIncestTwinsMixed.js | 1 - src/events/recFS/recfsPetiteAdmiration.js | 13 +- src/events/recFS/recfsPetiteAdmirationTwo.js | 3 +- src/events/recFS/recfsSlimnessEnthusiast.js | 3 +- .../recFS/recfsSlimnessEnthusiastTwo.js | 3 +- .../recFS/recfsStatuesqueGlorification.js | 3 +- .../recFS/recfsStatuesqueGlorificationTwo.js | 3 +- src/events/scheduled/assholeKnight.js | 3 +- src/events/scheduled/seCustomSlaveDelivery.js | 11 +- src/events/scheduled/seRecruiterSuccess.js | 3 +- src/facilities/nursery/utils/nurseryUtils.js | 2 +- src/facilities/surgery/analyzePregnancy.js | 4 + src/interaction/siCustom.js | 27 +- src/js/SlaveState.js | 12 + src/js/utilsSlave.js | 27 +- src/js/wombJS.js | 8 + src/markets/specificMarkets/eliteSlave.js | 5 +- .../specificMarkets/prestigiousSlave.js | 3 +- src/npc/children/ChildState.js | 2 + src/npc/databases/cheatmodeDatabase.js | 6 + src/npc/generate/generateGenetics.js | 37 +- src/npc/generate/generateLeadershipSlave.js | 6 +- src/npc/generate/generateMarketSlave.js | 36 +- src/npc/generate/generateNewSlaveJS.js | 14 +- src/npc/generate/generateRelatedSlave.js | 8 +- src/npc/generate/heroCreator.js | 11 +- src/npc/generate/lawCompliance.js | 12 +- src/npc/infants/InfantState.js | 2 + src/npc/startingGirls/startingGirls.js | 28 +- src/npc/startingGirls/startingGirlsPassage.js | 3 +- src/npc/surgery/bodySwap/bodySwap.js | 1 + src/player/js/PlayerState.js | 2 + 54 files changed, 499 insertions(+), 1684 deletions(-) diff --git a/devTools/types/FC/human.d.ts b/devTools/types/FC/human.d.ts index c804ce0d262..8a2776e8ea9 100644 --- a/devTools/types/FC/human.d.ts +++ b/devTools/types/FC/human.d.ts @@ -405,6 +405,8 @@ declare global { * * **macromastia + gigantomastia** - Breasts never stop growing. Increased growth rate, no shrink rate. */ gigantomastia: GeneticQuirk | 3; + /** sperm is much more likely to knock someone up */ + potent: GeneticQuirk; /** is prone to having twins, shorter pregnancy recovery rate */ fertility: GeneticQuirk; /** is prone to having multiples, even shorter pregnancy recovery rate @@ -441,6 +443,9 @@ declare global { mGain: GeneticQuirk; /** constantly loses muscle mass, easier to gain muscle. mGain + mLoss - muscle gain/loss amplified, passively lose muscle unless building */ mLoss: GeneticQuirk; + /** ova will split if room is available + * only affects fetuses */ + twinning: GeneticQuirk; /** slave can only ever birth girls */ girlsOnly: GeneticQuirk; /** abnormal production of amniotic fluid @@ -482,6 +487,8 @@ declare global { fetish: Fetish; spermY: number; inbreedingCoeff?: number; + adultHeight: number; + artSeed: number; } //#endregion diff --git a/src/Mods/Catmod/generateCatgirl.js b/src/Mods/Catmod/generateCatgirl.js index 2bd8936d82b..5724ff6500e 100644 --- a/src/Mods/Catmod/generateCatgirl.js +++ b/src/Mods/Catmod/generateCatgirl.js @@ -41,9 +41,11 @@ globalThis.growCatgirl = function(sex, { // they're genetically engineered and very expensive, so go ahead and make their genes conform a bit better to local expectations... const arc = V.arcologies[0]; if (arc.FSStatuesqueGlorification !== "unset") { - slave.height = Math.min(slave.height + 10, 274); + slave.natural.height = Math.min(slave.natural.height + 10, 274); + slave.height = Height.forAge(slave.natural.height, slave); } else if (arc.FSPetiteAdmiration !== "unset") { - slave.height = Math.max(slave.height - 10, 85); + slave.natural.height = Math.max(slave.natural.height - 10, 85); + slave.height = Height.forAge(slave.natural.height, slave); } if (arc.FSIntellectualDependency !== "unset") { slave.intelligence = Math.max(slave.intelligence - 15, -100); diff --git a/src/art/webgl/art.js b/src/art/webgl/art.js index d1ca2f14c22..d3d801ba068 100644 --- a/src/art/webgl/art.js +++ b/src/art/webgl/art.js @@ -9,6 +9,11 @@ App.Art.hexToRgb = function(hex) { App.Art.seed = 0; +App.Art.setSeed = function(slave, offset) { + App.Art.seed = slave.natural.artSeed + offset; + return App.Art.seed; +}; + App.Art.random = function() { App.Art.seed += 1; let x = Math.sin(App.Art.seed) * 10000; @@ -82,7 +87,7 @@ App.Art.getArtParams = function(slave) { }; App.Art.applyFigures = function(slave, scene, p) { - App.Art.seed = slave.ID; + App.Art.seed = App.Art.setSeed(slave, 0); let figures = []; switch (slave.clothes) { @@ -1133,7 +1138,7 @@ App.Art.applyFigures = function(slave, scene, p) { }; App.Art.applySurfaces = function(slave, scene, p) { - App.Art.seed = slave.ID + 1000; + App.Art.seed = App.Art.setSeed(slave, 1000); let glansFutaliciousShellLayers = []; let shaftFutaliciousShellLayers = []; @@ -1294,28 +1299,30 @@ App.Art.applySurfaces = function(slave, scene, p) { } let pubicStyle = ""; - switch (slave.pubicHStyle) { - case "hairless": - case "waxed": - case "bald": - break; - case "neat": - pubicStyle = "PubicNeat"; - break; - case "in a strip": - pubicStyle = "PubicStrip"; - break; - case "bushy": - pubicStyle = "PubicBushy"; - break; - case "very bushy": - pubicStyle = "PubicVeryBushy"; - break; - case "bushy in the front and neat in the rear": - pubicStyle = "PubicBushyFront"; - break; - default: - break; + if (slave.physicalAge >= slave.pubertyAge) { + switch (slave.pubicHStyle) { + case "hairless": + case "waxed": + case "bald": + break; + case "neat": + pubicStyle = "PubicNeat"; + break; + case "in a strip": + pubicStyle = "PubicStrip"; + break; + case "bushy": + pubicStyle = "PubicBushy"; + break; + case "very bushy": + pubicStyle = "PubicVeryBushy"; + break; + case "bushy in the front and neat in the rear": + pubicStyle = "PubicBushyFront"; + break; + default: + break; + } } if (pubicStyle !== "") { @@ -1637,7 +1644,7 @@ App.Art.applySurfaces = function(slave, scene, p) { }; App.Art.applyMaterials = function(slave, scene, p) { - App.Art.seed = slave.ID + 2000; + App.Art.seed = App.Art.setSeed(slave, 2000); let materials = []; @@ -2172,29 +2179,31 @@ App.Art.applyMaterials = function(slave, scene, p) { materials.push(["TemplateGenitalia", "Ni", Ni]); materials.push(["TemplateGenitalia", "map_Ka", "base/skin/" + skin + "Torso.jpg"]); - let pubicColor = App.Art.hexToRgb(extractColor(slave.pubicHColor)); - switch (slave.pubicHStyle) { - case "hairless": - case "waxed": - case "bald": - break; - case "neat": - materials.push(["PubicNeat", "Ka", pubicColor]); - break; - case "in a strip": - materials.push(["PubicStrip", "Ka", pubicColor]); - break; - case "bushy": - materials.push(["PubicBushy", "Ka", pubicColor]); - break; - case "very bushy": - materials.push(["PubicVeryBushy", "Ka", pubicColor]); - break; - case "bushy in the front and neat in the rear": - materials.push(["PubicBushyFront", "Ka", pubicColor]); - break; - default: - break; + if (slave.physicalAge >= slave.pubertyAge) { + const pubicColor = App.Art.hexToRgb(extractColor(slave.pubicHColor)); + switch (slave.pubicHStyle) { + case "hairless": + case "waxed": + case "bald": + break; + case "neat": + materials.push(["PubicNeat", "Ka", pubicColor]); + break; + case "in a strip": + materials.push(["PubicStrip", "Ka", pubicColor]); + break; + case "bushy": + materials.push(["PubicBushy", "Ka", pubicColor]); + break; + case "very bushy": + materials.push(["PubicVeryBushy", "Ka", pubicColor]); + break; + case "bushy in the front and neat in the rear": + materials.push(["PubicBushyFront", "Ka", pubicColor]); + break; + default: + break; + } } switch (slave.vaginaLube) { @@ -2596,7 +2605,7 @@ App.Art.getAnimState = function(slave, scene, p, morphs, isAnimTick) { }; App.Art.applyMorphs = function(slave, scene, p, isAnimating) { - App.Art.seed = slave.ID + 3000; + App.Art.seed = App.Art.setSeed(slave, 3000); let morphs = []; diff --git a/src/data/backwardsCompatibility/backwardsCompatibility.js b/src/data/backwardsCompatibility/backwardsCompatibility.js index 5a46884413b..033ec6041b4 100644 --- a/src/data/backwardsCompatibility/backwardsCompatibility.js +++ b/src/data/backwardsCompatibility/backwardsCompatibility.js @@ -1546,6 +1546,16 @@ App.Update.slaveRecords = function(node) { if (child.spermY === undefined) { child.spermY = normalRandInt(50, 5); } + if (!child.natural) { + child.natural = new App.Entity.GeneticState(); + if (child.geneticQuirks.dwarfism === 2 && child.geneticQuirks.gigantism !== 2) { + child.natural.height = Height.randomAdult(child, {limitMult: [-4, -1], spread: 0.15}); + } else if (child.geneticQuirks.gigantism === 2) { + child.natural.height = Height.randomAdult(child, {limitMult: [3, 10], spread: 0.15}); + } else { + child.natural.height = Height.randomAdult(child); + } + } App.Facilities.Nursery.InfantDatatypeCleanup(child); child.inbreedingCoeff = ibc.coeff(child); } else { @@ -2391,8 +2401,6 @@ App.Update.oldVersions = function(node) { } } - WombInit(newPC); - V.PC = clone(newPC); if (typeof V.PC.name === "undefined") { @@ -2445,6 +2453,22 @@ App.Update.oldVersions = function(node) { V.PC.skill.combat = 10; } } + if (!V.PC.natural) { + V.PC.natural = new App.Entity.GeneticState(); + if (V.PC.physicalAge >= 20) { + V.PC.natural.height = V.PC.height - V.PC.heightImplant * 10; + } else { + // find and set a reasonable natural height for this immature player + if (V.PC.geneticQuirks.dwarfism === 2 && V.PC.geneticQuirks.gigantism !== 2) { + V.PC.natural.height = Height.randomAdult(V.PC, {limitMult: [-4, -1], spread: 0.15}); + } else if (V.PC.geneticQuirks.gigantism === 2) { + V.PC.natural.height = Height.randomAdult(V.PC, {limitMult: [3, 10], spread: 0.15}); + } else { + V.PC.natural.height = Height.randomAdult(V.PC); + } + } + } + WombInit(V.PC); if (V.releaseID < 1185) { if (V.nurseryNannies > 0) { diff --git a/src/data/backwardsCompatibility/updateSlaveObject.js b/src/data/backwardsCompatibility/updateSlaveObject.js index 23cfd18dde5..75ca7a5ff0d 100644 --- a/src/data/backwardsCompatibility/updateSlaveObject.js +++ b/src/data/backwardsCompatibility/updateSlaveObject.js @@ -1437,4 +1437,21 @@ App.Update.Slave = function(slave, genepool = false) { slave.skill.combat = 70; } } + + if (!slave.natural) { + slave.natural = new App.Entity.GeneticState(); + slave.natural.artSeed = slave.ID; // used to use the ID as the seed; copy it on old slaves so they don't suddenly change appearance + if (slave.physicalAge >= 20) { + slave.natural.height = slave.height - slave.heightImplant * 10; + } else { + // find and set a reasonable natural height for this immature slave + if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2) { + slave.natural.height = Height.randomAdult(slave, {limitMult: [-4, -1], spread: 0.15}); + } else if (slave.geneticQuirks.gigantism === 2) { + slave.natural.height = Height.randomAdult(slave, {limitMult: [3, 10], spread: 0.15}); + } else { + slave.natural.height = Height.randomAdult(slave); + } + } + } }; diff --git a/src/endWeek/nextWeek/nextWeek.js b/src/endWeek/nextWeek/nextWeek.js index f4d433d5478..7fee8127228 100644 --- a/src/endWeek/nextWeek/nextWeek.js +++ b/src/endWeek/nextWeek/nextWeek.js @@ -39,7 +39,7 @@ App.EndWeek.nextWeek = function() { V.PC.visualAge++; V.PC.ovaryAge += either(0.8, 0.9, 0.9, 1.0, 1.0, 1.0, 1.1); } - if (V.PC.physicalAge <= 18 && V.loliGrow > 0) { + if (V.PC.physicalAge <= 20 && V.loliGrow > 0) { App.EndWeek.Shared.physicalDevelopment(V.PC, true); } agePCEffects(); diff --git a/src/endWeek/player/prDrugs.js b/src/endWeek/player/prDrugs.js index 7385a8de254..eb3188b48b8 100644 --- a/src/endWeek/player/prDrugs.js +++ b/src/endWeek/player/prDrugs.js @@ -879,9 +879,9 @@ App.EndWeek.Player.drugs = function(PC = V.PC) { // evaluate against expected height, with neoteny comparing against expected height for 12 year olds... let heightDiff; if (PC.geneticQuirks.neoteny === 2 && PC.physicalAge > 12) { - heightDiff = (PC.height - PC.heightImplant * 10) / Height.mean(PC.nationality, PC.race, PC.genes, 12); + heightDiff = (PC.height - PC.heightImplant * 10) / Height.forAge(PC.natural.height, 12, PC.genes); } else { - heightDiff = (PC.height - PC.heightImplant * 10) / Height.mean(PC); + heightDiff = (PC.height - PC.heightImplant * 10) / Height.forAge(PC.natural.height, PC); } // if you are taller than the expected height the growth is reduced, if shorter accelerated proportionally to the distance from the expected height heightDiff = 1 - heightDiff; diff --git a/src/endWeek/reports/incubatorReport.js b/src/endWeek/reports/incubatorReport.js index ac5dc09d1fc..a3f138fee6a 100644 --- a/src/endWeek/reports/incubatorReport.js +++ b/src/endWeek/reports/incubatorReport.js @@ -156,23 +156,23 @@ App.EndWeek.incubatorReport = function() { r = []; if (V.incubator.upgrade.growthStims === 1 && V.incubator.setting.growthStims !== 0) { - let heightLimit = Math.clamp((Height.mean(tank) * 1.25), 0, 274); - let heightLimitAge = Height.mean(tank); + let heightLimit = Math.clamp((Height.forAge(tank.natural.height, tank) * 1.25), 0, 274); + let heightLimitAge = Height.forAge(tank.natural.height, tank); if (tank.geneticQuirks.dwarfism === 2 && tank.geneticQuirks.gigantism !== 2) { - heightLimit = Math.clamp((Height.mean(tank) * 0.95), 0, 160); + heightLimit = Math.clamp((Height.forAge(tank.natural.height, tank) * 0.95), 0, 160); } else if (tank.geneticQuirks.gigantism === 2 && tank.geneticQuirks.dwarfism !== 2) { - heightLimit = Math.clamp((Height.mean(tank) * 1.75), 0, 274); + heightLimit = Math.clamp((Height.forAge(tank.natural.height, tank) * 1.75), 0, 274); } if (tank.geneMods.NCS === 1) { /* NCS should block physical growth beyond that of a toddler, but some players might like * a little more or less. So using V.minimumSlaveAge or 8, whichever is lesser. */ const limitAge = Math.min(8, V.minimumSlaveAge); - /* Generate new average height for slave of age limitAge */ - heightLimitAge = Height.mean(tank.nationality, tank.race, tank.genes, limitAge); - heightLimit = heightLimitAge; /* TODO: Add some variation, right now all NCS slaves will be the exact same height */ + /* scale height to age 8 */ + heightLimitAge = Height.forAge(tank.natural.height, limitAge); + heightLimit = heightLimitAge; } else if (tank.geneticQuirks.neoteny === 2 && tank.physicalAge > 12) { - /* Generate new average height for slave of age 12 */ - heightLimitAge = Height.mean(tank.nationality, tank.race, tank.genes, 12); + /* scale height to age 12 */ + heightLimitAge = Height.forAge(tank.natural.height, 12); heightLimit = Math.clamp((heightLimitAge * 1.25), 0, 274); } if (tank.height >= heightLimit) { diff --git a/src/endWeek/saDrugs.js b/src/endWeek/saDrugs.js index c03bba400e0..13c74177ab9 100644 --- a/src/endWeek/saDrugs.js +++ b/src/endWeek/saDrugs.js @@ -930,9 +930,9 @@ App.SlaveAssignment.drugs = function saDrugs(slave) { // evaluate against slave expected height, with neoteny slaves comparing against expected height for 12 year olds... let heightDiff; if (slave.geneticQuirks.neoteny === 2 && slave.physicalAge > 12) { - heightDiff = (slave.height - slave.heightImplant * 10) / Height.mean(slave.nationality, slave.race, slave.genes, 12); + heightDiff = (slave.height - slave.heightImplant * 10) / Height.forAge(slave.natural.height, 12, slave.genes); } else { - heightDiff = (slave.height - slave.heightImplant * 10) / Height.mean(slave); + heightDiff = (slave.height - slave.heightImplant * 10) / Height.forAge(slave.natural.height, slave); } // if ${he} is taller than the expected height the growth is reduced, if shorter accelerated proportionally to the distance from the expected height heightDiff = 1 - heightDiff; diff --git a/src/endWeek/shared/physicalDevelopment.js b/src/endWeek/shared/physicalDevelopment.js index 6b7e98562c4..3765d58dfe0 100644 --- a/src/endWeek/shared/physicalDevelopment.js +++ b/src/endWeek/shared/physicalDevelopment.js @@ -5,7 +5,6 @@ App.EndWeek.Shared.physicalDevelopment = function(actor, player = false) { const rearQuirkDivider = rearQuirk === 0 ? 1 : rearQuirk; const dickMod = (actor.geneticQuirks.wellHung === 2 ? 2 : 1); let physicalAgeSwap; - const tallerPC = (player && actor.height >= Height.mean(actor) + 5 && actor.bodySwap === 0); if (actor.geneticQuirks.progeria === 2) { // since progeria increases .physicalAge, we need to work around it. @@ -15,1557 +14,109 @@ App.EndWeek.Shared.physicalDevelopment = function(actor, player = false) { physicalAgeSwap = actor.physicalAge; } if (actor.geneMods.NCS !== 1) { - /* NCS completely blocks all natural physical growth: no height increases. It also blocks all hormonal secondary sexual * characteristics. So, on the female side: no boobs, no butt, no hips, and no labia. And on the male side: no dick, no clit, no balls, no scrotum, no shoulders. */ + /* NCS completely blocks all natural physical growth: no height increases. It also blocks all hormonal secondary sexual + * characteristics. So, on the female side: no boobs, no butt, no hips, and no labia. And on the male side: no dick, no clit, no balls, no scrotum, no shoulders. */ /* so this is a big old NO-OP to skip the physical development. */ - if (actor.geneticQuirks.androgyny === 2) { /* takes a mix of both to create a very androgynous slave */ - if (actor.geneticQuirks.dwarfism === 2 && actor.geneticQuirks.gigantism !== 2) { - increaseHeightDwarf(actor); - } else if (actor.geneticQuirks.gigantism === 2) { - increaseHeightGiant(actor); - } else if (actor.geneticQuirks.neoteny === 2) { - increaseHeightNeoteny(actor); - } else { - increaseHeightXX(actor); - } - if (actor.geneticQuirks.neoteny !== 2) { - if (actor.boobs - actor.boobsImplant <= 300) { - increaseBoobsXX(actor); - } - if (actor.dick.isBetween(0, 3) || actor.geneticQuirks.wellHung === 2) { - increaseDick(actor); - } - if (actor.balls.isBetween(0, 3)) { - increaseBalls(actor); - } - if (actor.vagina > 0 && actor.ovaries > 0 && physicalAgeSwap > actor.pubertyAgeXX) { - increaseWetness(actor); - } - if (actor.waist < 10) { - increaseWaistXY(actor); - } - if (actor.hips - actor.hipsImplant < 0) { - increaseHipsXX(actor); - } - if (actor.butt - actor.buttImplant < 3) { - increaseButtXX(actor); - } - } - increasePregAdaptationXX(actor); - } else if (actor.genes === "XX") { /* loli becoming a woman */ - if (actor.geneticQuirks.dwarfism === 2 && actor.geneticQuirks.gigantism !== 2) { - increaseHeightDwarf(actor); - } else if (actor.geneticQuirks.gigantism === 2) { - increaseHeightGiant(actor); - } else if (actor.geneticQuirks.neoteny === 2) { - increaseHeightNeoteny(actor); - } else { - increaseHeightXX(actor); - } - if (physicalAgeSwap === 13 || (physicalAgeSwap > 13 && (actor.hormoneBalance >= 100 || actor.hormoneBalance <= -100))) { - increaseFaceXX(actor); - if (actor.voice > 1) { - increaseVoiceXX(actor); - } - } - if (actor.geneticQuirks.neoteny !== 2) { - increaseBoobsXX(actor); - if (actor.clit > 0) { - increaseClit(actor); - } - if (actor.vagina > 0 && actor.ovaries > 0 && physicalAgeSwap > actor.pubertyAgeXX) { - increaseWetness(actor); - } - increaseWaistXX(actor); - increaseHipsXX(actor); - increaseButtXX(actor); - } - increasePregAdaptationXX(actor); - } else { - /* shota becoming a man */ - if (actor.geneticQuirks.dwarfism === 2 && actor.geneticQuirks.gigantism !== 2) { - increaseHeightDwarf(actor); - } else if (actor.geneticQuirks.gigantism === 2) { - increaseHeightGiant(actor); - } else if (actor.geneticQuirks.neoteny === 2) { - increaseHeightNeoteny(actor); - } else { - increaseHeightXY(actor); - } - if (physicalAgeSwap === 13 || (physicalAgeSwap > 13 && (actor.hormoneBalance >= 100 || actor.hormoneBalance <= -100))) { - increaseFaceXY(actor); - if (actor.voice > 1) { - increaseVoiceXY(actor); - } - } - if (actor.geneticQuirks.neoteny !== 2) { - increaseBoobsXY(actor); - if (actor.dick > 0) { - increaseDick(actor); - } - if (actor.balls > 0) { - increaseBalls(actor); - } - increaseWaistXY(actor); - increaseHipsXY(actor); - increaseButtXY(actor); - } - increasePregAdaptationXY(actor); - } - } - - /** - * @param {FC.HumanState} actor - */ - function increaseHeightXX(actor) { - if (actor.hormoneBalance >= 200) { - if (physicalAgeSwap === 3) { - if (actor.height <= 91) { - actor.height += jsEither([8, 8, 9, 9]); - } else if (actor.height <= 101) { - actor.height += 5; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 101) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 109) { - actor.height += 4; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 109) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 116) { - actor.height += 4; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 116) { - actor.height += jsEither([5, 5, 6, 6]); - } else if (actor.height <= 124) { - actor.height += 3; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 124) { - actor.height += jsEither([7, 7, 8, 8]); - } else if (actor.height <= 131) { - actor.height += 3; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 131) { - actor.height += jsEither([5, 5, 6, 6]); - } else if (actor.height <= 137) { - actor.height += 3; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 137) { - actor.height += jsEither([4, 4, 5, 5]); - } else if (actor.height <= 144) { - actor.height += 3; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 144) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 156) { - actor.height += 3; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 156) { - actor.height += jsEither([5, 5, 6, 6]); - } else if (actor.height <= 163) { - actor.height += 3; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 163) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 168) { - actor.height += 3; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 168) { - actor.height += jsEither([5, 5, 6, 6]); - } else if (actor.height <= 171) { - actor.height += 3; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 171) { - actor.height += jsEither([4, 4, 5, 5]); - } else if (actor.height <= 173) { - actor.height += 3; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1]); - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1]); - } - } - } else if (actor.hormoneBalance >= 100) { - if (physicalAgeSwap === 3) { - if (actor.height <= 91) { - actor.height += jsEither([8, 8, 9, 9, 9]); - } else if (actor.height <= 101) { - actor.height += 5; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 101) { - actor.height += jsEither([6, 6, 7, 7, 7]); - } else if (actor.height <= 109) { - actor.height += 4; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 109) { - actor.height += jsEither([6, 6, 7, 7, 7]); - } else if (actor.height <= 116) { - actor.height += 4; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 116) { - actor.height += jsEither([5, 5, 6, 6, 6]); - } else if (actor.height <= 124) { - actor.height += 3; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 124) { - actor.height += jsEither([7, 7, 8, 8, 8]); - } else if (actor.height <= 131) { - actor.height += 3; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 131) { - actor.height += jsEither([5, 5, 6, 6, 6]); - } else if (actor.height <= 137) { - actor.height += 3; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 137) { - actor.height += jsEither([4, 4, 5, 5, 5]); - } else if (actor.height <= 144) { - actor.height += 3; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 144) { - actor.height += jsEither([6, 6, 7, 7, 7]); - } else if (actor.height <= 156) { - actor.height += 3; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 156) { - actor.height += jsEither([5, 5, 6, 6, 6]); - } else if (actor.height <= 163) { - actor.height += 3; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 163) { - actor.height += jsEither([6, 6, 7, 7, 7]); - } else if (actor.height <= 168) { - actor.height += 3; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 168) { - actor.height += jsEither([5, 5, 6, 6, 6]); - } else if (actor.height <= 171) { - actor.height += 3; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 171) { - actor.height += jsEither([4, 4, 5, 5, 5]); - } else if (actor.height <= 173) { - actor.height += 3; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1, 1]); - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1, 1]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1, 1]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1, 1]); - } - } - } else if (actor.hormoneBalance <= -200) { - if (physicalAgeSwap === 3) { - if (actor.height <= 91) { - actor.height += jsEither([9, 9, 9, 10, 10]); - } else if (actor.height <= 101) { - actor.height += 5; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 101) { - actor.height += jsEither([7, 7, 7, 8, 8]); - } else if (actor.height <= 109) { - actor.height += 4; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 109) { - actor.height += jsEither([7, 7, 7, 8, 8]); - } else if (actor.height <= 116) { - actor.height += 4; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 116) { - actor.height += jsEither([6, 6, 6, 7, 7]); - } else if (actor.height <= 124) { - actor.height += 3; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 124) { - actor.height += jsEither([8, 8, 8, 9, 9]); - } else if (actor.height <= 131) { - actor.height += 3; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 131) { - actor.height += jsEither([6, 6, 6, 7, 7]); - } else if (actor.height <= 137) { - actor.height += 3; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 137) { - actor.height += jsEither([5, 5, 5, 6, 6]); - } else if (actor.height <= 144) { - actor.height += 3; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 144) { - actor.height += jsEither([7, 7, 7, 8, 8]); - } else if (actor.height <= 156) { - actor.height += 3; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 156) { - actor.height += jsEither([6, 6, 6, 7, 7]); - } else if (actor.height <= 163) { - actor.height += 3; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 163) { - actor.height += jsEither([7, 7, 7, 8, 8]); - } else if (actor.height <= 168) { - actor.height += 3; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 168) { - actor.height += jsEither([6, 6, 6, 7, 7]); - } else if (actor.height <= 171) { - actor.height += 3; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 171) { - actor.height += jsEither([5, 5, 5, 6, 6]); - } else if (actor.height <= 173) { - actor.height += 3; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 174) { - actor.height += jsEither([1, 1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 174) { - actor.height += jsEither([1, 1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 174) { - actor.height += jsEither([1, 1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 174) { - actor.height += jsEither([1, 1, 1, 2, 2]); - } - } - } else if (actor.hormoneBalance <= -100) { - if (physicalAgeSwap === 3) { - if (actor.height <= 91) { - actor.height += jsEither([8, 9, 9, 10, 10]); - } else if (actor.height <= 101) { - actor.height += 5; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 101) { - actor.height += jsEither([6, 7, 7, 8, 8]); - } else if (actor.height <= 109) { - actor.height += 4; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 109) { - actor.height += jsEither([6, 7, 7, 8, 8]); - } else if (actor.height <= 116) { - actor.height += 4; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 116) { - actor.height += jsEither([5, 6, 6, 7, 7]); - } else if (actor.height <= 124) { - actor.height += 3; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 124) { - actor.height += jsEither([7, 8, 8, 9, 9]); - } else if (actor.height <= 131) { - actor.height += 3; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 131) { - actor.height += jsEither([5, 6, 6, 7, 7]); - } else if (actor.height <= 137) { - actor.height += 3; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 137) { - actor.height += jsEither([4, 5, 5, 6, 6]); - } else if (actor.height <= 144) { - actor.height += 3; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 144) { - actor.height += jsEither([6, 7, 7, 8, 8]); - } else if (actor.height <= 156) { - actor.height += 3; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 156) { - actor.height += jsEither([5, 6, 6, 7, 7]); - } else if (actor.height <= 163) { - actor.height += 3; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 163) { - actor.height += jsEither([6, 7, 7, 8, 8]); - } else if (actor.height <= 168) { - actor.height += 3; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 168) { - actor.height += jsEither([5, 6, 6, 7, 7]); - } else if (actor.height <= 171) { - actor.height += 3; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 171) { - actor.height += jsEither([4, 5, 5, 6, 6]); - } else if (actor.height <= 173) { - actor.height += 3; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 174) { - actor.height += jsEither([0, 1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 174) { - actor.height += jsEither([0, 1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 174) { - actor.height += jsEither([0, 1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 174) { - actor.height += jsEither([0, 1, 1, 2, 2]); - } - } + if (actor.geneticQuirks.neoteny === 2) { + // special case for neoteny (genetic target height does not take it into account) + increaseHeightNeoteny(actor); } else { - if (physicalAgeSwap === 3) { - if (actor.height <= 91) { - actor.height += jsEither([8, 8, 9, 9, 9, 10]); - } else if (actor.height <= 101) { - actor.height += 5; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 101) { - actor.height += jsEither([6, 6, 7, 7, 8, 8]); - } else if (actor.height <= 109) { - actor.height += 4; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 109) { - actor.height += jsEither([6, 6, 7, 7, 7, 8]); - } else if (actor.height <= 116) { - actor.height += 4; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 116) { - actor.height += jsEither([5, 5, 6, 6, 6, 7]); - } else if (actor.height <= 124) { - actor.height += 3; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 124) { - actor.height += jsEither([7, 7, 8, 8, 8, 9]); - } else if (actor.height <= 131) { - actor.height += 3; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 131) { - actor.height += jsEither([5, 5, 6, 6, 6, 7]); - } else if (actor.height <= 137) { - actor.height += 3; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 137) { - actor.height += jsEither([4, 4, 5, 5, 5, 6]); - } else if (actor.height <= 144) { - actor.height += 3; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 144) { - actor.height += jsEither([6, 6, 7, 7, 7, 8]); - } else if (actor.height <= 156) { - actor.height += 3; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 156) { - actor.height += jsEither([5, 5, 6, 6, 6, 7]); - } else if (actor.height <= 163) { - actor.height += 3; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 163) { - actor.height += jsEither([6, 6, 7, 7, 7, 8]); - } else if (actor.height <= 168) { - actor.height += 3; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 168) { - actor.height += jsEither([5, 5, 6, 6, 6, 7]); - } else if (actor.height <= 171) { - actor.height += 3; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 171) { - actor.height += jsEither([4, 4, 5, 5, 5, 6]); - } else if (actor.height <= 173) { - actor.height += 3; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1, 1, 2]); - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1, 1, 2]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1, 1, 2]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 174) { - actor.height += jsEither([0, 0, 1, 1, 1, 2]); - } - } + // giant/dwarf/sex/race/etc is already taken into account by the target height. just need to take one step towards it. + increaseHeight(actor); } - // experiment - Let's see if this keeps players on average above average height or if it makes them too tall in the long run. - if (tallerPC) { - actor.height += random(0, 3); - } - } - - /** - * @param {FC.HumanState} actor - */ - function increaseHeightXY(actor) { - if (actor.hormoneBalance >= 200) { - if (physicalAgeSwap === 3) { - if (actor.height <= 93) { - actor.height += jsEither([9, 9, 10, 10]); - } else if (actor.height <= 103) { - actor.height += 6; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 103) { - actor.height += jsEither([7, 7, 8, 8]); - } else if (actor.height <= 110) { - actor.height += 5; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 110) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 117) { - actor.height += 4; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 117) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 124) { - actor.height += 4; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 124) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 131) { - actor.height += 4; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 131) { - actor.height += jsEither([5, 5, 6, 6]); - } else if (actor.height <= 137) { - actor.height += 3; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 137) { - actor.height += jsEither([4, 4, 5, 5]); - } else if (actor.height <= 144) { - actor.height += 3; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 144) { - actor.height += jsEither([5, 5, 6, 6]); - } else if (actor.height <= 150) { - actor.height += 3; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 150) { - actor.height += jsEither([5, 5, 6, 6]); - } else if (actor.height <= 156) { - actor.height += 3; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 156) { - actor.height += jsEither([5, 5, 6, 6]); - } else if (actor.height <= 162) { - actor.height += 3; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 162) { - actor.height += jsEither([7, 7, 8, 8]); - } else if (actor.height <= 170) { - actor.height += 5; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 170) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 177) { - actor.height += 4; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 177) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 184) { - actor.height += 4; - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 184) { - actor.height += jsEither([2, 2, 3, 3]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 185) { - actor.height += jsEither([1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 186) { - actor.height += jsEither([0, 0, 1, 1]); - } - } - } else if (actor.hormoneBalance >= 100) { - if (physicalAgeSwap === 3) { - if (actor.height <= 93) { - actor.height += jsEither([9, 9, 9, 10, 10]); - } else if (actor.height <= 103) { - actor.height += 6; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 103) { - actor.height += jsEither([7, 7, 8, 8, 8]); - } else if (actor.height <= 110) { - actor.height += 5; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 110) { - actor.height += jsEither([6, 6, 7, 7, 7]); - } else if (actor.height <= 117) { - actor.height += 4; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 117) { - actor.height += jsEither([6, 6, 7, 7, 7]); - } else if (actor.height <= 124) { - actor.height += 4; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 124) { - actor.height += jsEither([6, 6, 7, 7, 7]); - } else if (actor.height <= 131) { - actor.height += 4; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 131) { - actor.height += jsEither([5, 5, 6, 6, 6]); - } else if (actor.height <= 137) { - actor.height += 3; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 137) { - actor.height += jsEither([4, 4, 5, 5, 5]); - } else if (actor.height <= 144) { - actor.height += 3; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 144) { - actor.height += jsEither([5, 5, 6, 6, 6]); - } else if (actor.height <= 150) { - actor.height += 3; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 150) { - actor.height += jsEither([5, 5, 6, 6, 6]); - } else if (actor.height <= 156) { - actor.height += 3; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 156) { - actor.height += jsEither([5, 5, 6, 6, 6]); - } else if (actor.height <= 162) { - actor.height += 3; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 162) { - actor.height += jsEither([7, 7, 8, 8, 8]); - } else if (actor.height <= 170) { - actor.height += 5; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 170) { - actor.height += jsEither([6, 6, 7, 7, 7]); - } else if (actor.height <= 177) { - actor.height += 4; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 177) { - actor.height += jsEither([6, 6, 7, 7, 7]); - } else if (actor.height <= 184) { - actor.height += 4; - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 184) { - actor.height += jsEither([2, 2, 3, 3, 3]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 185) { - actor.height += jsEither([1, 1, 2, 2, 2]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 186) { - actor.height += jsEither([0, 0, 1, 1, 1]); - } - } - } else if (actor.hormoneBalance <= -200) { - if (physicalAgeSwap === 3) { - if (actor.height <= 93) { - actor.height += jsEither([10, 10, 11, 11]); - } else if (actor.height <= 103) { - actor.height += 6; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 103) { - actor.height += jsEither([8, 8, 9, 9]); - } else if (actor.height <= 110) { - actor.height += 5; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 110) { - actor.height += jsEither([7, 7, 8, 8]); - } else if (actor.height <= 117) { - actor.height += 4; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 117) { - actor.height += jsEither([7, 7, 8, 8]); - } else if (actor.height <= 124) { - actor.height += 4; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 124) { - actor.height += jsEither([7, 7, 8, 8]); - } else if (actor.height <= 131) { - actor.height += 4; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 131) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 137) { - actor.height += 3; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 137) { - actor.height += jsEither([5, 5, 6, 6]); - } else if (actor.height <= 144) { - actor.height += 3; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 144) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 150) { - actor.height += 3; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 150) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 156) { - actor.height += 3; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 156) { - actor.height += jsEither([6, 6, 7, 7]); - } else if (actor.height <= 162) { - actor.height += 3; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 162) { - actor.height += jsEither([8, 8, 9, 9]); - } else if (actor.height <= 170) { - actor.height += 5; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 170) { - actor.height += jsEither([7, 7, 8, 8]); - } else if (actor.height <= 177) { - actor.height += 4; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 177) { - actor.height += jsEither([7, 7, 8, 8]); - } else if (actor.height <= 184) { - actor.height += 4; - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 184) { - actor.height += jsEither([3, 3, 4, 4]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 185) { - actor.height += jsEither([2, 2, 3, 3]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 186) { - actor.height += jsEither([1, 1, 2, 2]); - } - } - } else if (actor.hormoneBalance <= -100) { - if (physicalAgeSwap === 3) { - if (actor.height <= 93) { - actor.height += jsEither([10, 10, 10, 11, 11]); - } else if (actor.height <= 103) { - actor.height += 6; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 103) { - actor.height += jsEither([8, 8, 8, 9, 9]); - } else if (actor.height <= 110) { - actor.height += 5; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 110) { - actor.height += jsEither([7, 7, 7, 8, 8]); - } else if (actor.height <= 117) { - actor.height += 4; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 117) { - actor.height += jsEither([7, 7, 7, 8, 8]); - } else if (actor.height <= 124) { - actor.height += 4; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 124) { - actor.height += jsEither([7, 7, 7, 8, 8]); - } else if (actor.height <= 131) { - actor.height += 4; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 131) { - actor.height += jsEither([6, 6, 6, 7, 7]); - } else if (actor.height <= 137) { - actor.height += 3; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 137) { - actor.height += jsEither([5, 5, 5, 6, 6]); - } else if (actor.height <= 144) { - actor.height += 3; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 144) { - actor.height += jsEither([6, 6, 6, 7, 7]); - } else if (actor.height <= 150) { - actor.height += 3; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 150) { - actor.height += jsEither([6, 6, 6, 7, 7]); - } else if (actor.height <= 156) { - actor.height += 3; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 156) { - actor.height += jsEither([6, 6, 6, 7, 7]); - } else if (actor.height <= 162) { - actor.height += 3; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 162) { - actor.height += jsEither([8, 8, 8, 9, 9]); - } else if (actor.height <= 170) { - actor.height += 5; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 170) { - actor.height += jsEither([7, 7, 7, 8, 8]); - } else if (actor.height <= 177) { - actor.height += 4; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 177) { - actor.height += jsEither([7, 7, 7, 8, 8]); - } else if (actor.height <= 184) { - actor.height += 4; - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 184) { - actor.height += jsEither([3, 3, 3, 4, 4]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 185) { - actor.height += jsEither([2, 2, 2, 3, 3]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 186) { - actor.height += jsEither([1, 1, 1, 2, 2]); - } - } - } else { - if (physicalAgeSwap === 3) { - if (actor.height <= 93) { - actor.height += jsEither([9, 9, 10, 10, 10, 11]); - } else if (actor.height <= 103) { - actor.height += 6; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 103) { - actor.height += jsEither([7, 7, 8, 8, 9, 9]); - } else if (actor.height <= 110) { - actor.height += 5; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 110) { - actor.height += jsEither([6, 6, 7, 7, 8, 8]); - } else if (actor.height <= 117) { - actor.height += 4; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 117) { - actor.height += jsEither([6, 6, 7, 7, 8, 8]); - } else if (actor.height <= 124) { - actor.height += 4; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 124) { - actor.height += jsEither([6, 6, 7, 7, 8, 8]); - } else if (actor.height <= 131) { - actor.height += 4; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 131) { - actor.height += jsEither([5, 5, 6, 6, 7, 7]); - } else if (actor.height <= 137) { - actor.height += 3; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 137) { - actor.height += jsEither([4, 4, 5, 5, 5, 6]); - } else if (actor.height <= 144) { - actor.height += 3; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 144) { - actor.height += jsEither([5, 5, 6, 6, 7, 7]); - } else if (actor.height <= 150) { - actor.height += 3; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 150) { - actor.height += jsEither([5, 5, 6, 6, 6, 7]); - } else if (actor.height <= 156) { - actor.height += 3; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 156) { - actor.height += jsEither([5, 5, 6, 6, 7, 7]); - } else if (actor.height <= 162) { - actor.height += 3; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 162) { - actor.height += jsEither([7, 7, 8, 8, 9, 9]); - } else if (actor.height <= 170) { - actor.height += 5; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 170) { - actor.height += jsEither([6, 6, 7, 7, 8, 8]); - } else if (actor.height <= 177) { - actor.height += 4; + // physical development EXCEPT for height stops at 18; height keeps going until 20. + if (physicalAgeSwap <= 18) { + if (actor.geneticQuirks.androgyny === 2) { /* takes a mix of both to create a very androgynous slave */ + if (actor.geneticQuirks.neoteny !== 2) { + if (actor.boobs - actor.boobsImplant <= 300) { + increaseBoobsXX(actor); + } + if (actor.dick.isBetween(0, 3) || actor.geneticQuirks.wellHung === 2) { + increaseDick(actor); + } + if (actor.balls.isBetween(0, 3)) { + increaseBalls(actor); + } + if (actor.vagina > 0 && actor.ovaries > 0 && physicalAgeSwap > actor.pubertyAgeXX) { + increaseWetness(actor); + } + if (actor.waist < 10) { + increaseWaistXY(actor); + } + if (actor.hips - actor.hipsImplant < 0) { + increaseHipsXX(actor); + } + if (actor.butt - actor.buttImplant < 3) { + increaseButtXX(actor); + } } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 177) { - actor.height += jsEither([6, 6, 7, 7, 8, 8]); - } else if (actor.height <= 184) { - actor.height += 4; + increasePregAdaptationXX(actor); + } else if (actor.genes === "XX") { /* loli becoming a woman */ + if (physicalAgeSwap === 13 || (physicalAgeSwap > 13 && (actor.hormoneBalance >= 100 || actor.hormoneBalance <= -100))) { + increaseFaceXX(actor); + if (actor.voice > 1) { + increaseVoiceXX(actor); + } } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 184) { - actor.height += jsEither([2, 2, 3, 3, 4, 4]); + if (actor.geneticQuirks.neoteny !== 2) { + increaseBoobsXX(actor); + if (actor.clit > 0) { + increaseClit(actor); + } + if (actor.vagina > 0 && actor.ovaries > 0 && physicalAgeSwap > actor.pubertyAgeXX) { + increaseWetness(actor); + } + increaseWaistXX(actor); + increaseHipsXX(actor); + increaseButtXX(actor); } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 185) { - actor.height += jsEither([1, 1, 2, 2, 3, 3]); + increasePregAdaptationXX(actor); + } else { /* shota becoming a man */ + if (physicalAgeSwap === 13 || (physicalAgeSwap > 13 && (actor.hormoneBalance >= 100 || actor.hormoneBalance <= -100))) { + increaseFaceXY(actor); + if (actor.voice > 1) { + increaseVoiceXY(actor); + } } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 186) { - actor.height += jsEither([0, 0, 1, 1, 2, 2]); + if (actor.geneticQuirks.neoteny !== 2) { + increaseBoobsXY(actor); + if (actor.dick > 0) { + increaseDick(actor); + } + if (actor.balls > 0) { + increaseBalls(actor); + } + increaseWaistXY(actor); + increaseHipsXY(actor); + increaseButtXY(actor); } + increasePregAdaptationXY(actor); } } - // experiment - Let's see if this keeps players on average above average height or if it makes them too tall in the long run. - if (tallerPC) { - actor.height += random(0, 3); - } } /** * @param {FC.HumanState} actor */ - function increaseHeightDwarf(actor) { - if (actor.hormoneBalance >= 200) { - if (physicalAgeSwap === 3) { - if (actor.height <= 80) { - actor.height += jsEither([1, 1, 2, 2]); - } else if (actor.height <= 84) { - actor.height += 1; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 84) { - actor.height += jsEither([4, 4, 5, 5]); - } else if (actor.height <= 90) { - actor.height += 2; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 90) { - actor.height += jsEither([8, 8, 9, 9]); - } else if (actor.height <= 100) { - actor.height += 5; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 100) { - actor.height += jsEither([3, 3, 4, 4]); - } else if (actor.height <= 105) { - actor.height += 2; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 105) { - actor.height += jsEither([2, 2, 3, 3]); - } else if (actor.height <= 109) { - actor.height += 1; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 109) { - actor.height += jsEither([3, 3, 4, 4]); - } else if (actor.height <= 114) { - actor.height += 1; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 114) { - actor.height += jsEither([2, 2, 3, 3]); - } else if (actor.height <= 118) { - actor.height += 1; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 118) { - actor.height += jsEither([2, 2, 3, 3]); - } else if (actor.height <= 122) { - actor.height += 1; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 122) { - actor.height += jsEither([3, 3, 4, 4]); - } else if (actor.height <= 127) { - actor.height += 2; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 127) { - actor.height += jsEither([3, 3, 4, 4]); - } else if (actor.height <= 132) { - actor.height += 2; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 132) { - actor.height += jsEither([1, 1, 2, 2]); - } else if (actor.height <= 135) { - actor.height += 1; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 135) { - actor.height += jsEither([1, 1, 2, 2]); - } else if (actor.height <= 138) { - actor.height += 1; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 138) { - actor.height += jsEither([1, 1, 2, 2]); - } else if (actor.height <= 141) { - actor.height += 1; - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 143) { - actor.height += jsEither([0, 0, 1, 1]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 143) { - actor.height += jsEither([0, 0, 1, 1]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 143) { - actor.height += jsEither([0, 0, 1, 1]); - } - } - } else if (actor.hormoneBalance >= 100) { - if (physicalAgeSwap === 3) { - if (actor.height <= 80) { - actor.height += jsEither([1, 1, 2, 2, 2]); - } else if (actor.height <= 84) { - actor.height += 1; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 84) { - actor.height += jsEither([4, 4, 5, 5, 5]); - } else if (actor.height <= 90) { - actor.height += 2; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 90) { - actor.height += jsEither([8, 8, 9, 9, 9]); - } else if (actor.height <= 100) { - actor.height += 5; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 100) { - actor.height += jsEither([3, 3, 4, 4, 4]); - } else if (actor.height <= 105) { - actor.height += 2; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 105) { - actor.height += jsEither([2, 2, 3, 3, 3]); - } else if (actor.height <= 109) { - actor.height += 1; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 109) { - actor.height += jsEither([3, 3, 4, 4, 4]); - } else if (actor.height <= 114) { - actor.height += 1; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 114) { - actor.height += jsEither([2, 2, 3, 3, 3]); - } else if (actor.height <= 118) { - actor.height += 1; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 118) { - actor.height += jsEither([2, 2, 3, 3, 3]); - } else if (actor.height <= 122) { - actor.height += 1; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 122) { - actor.height += jsEither([3, 3, 4, 4, 4]); - } else if (actor.height <= 127) { - actor.height += 2; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 127) { - actor.height += jsEither([3, 3, 4, 4, 4]); - } else if (actor.height <= 132) { - actor.height += 2; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 132) { - actor.height += jsEither([1, 1, 2, 2, 2]); - } else if (actor.height <= 135) { - actor.height += 1; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 135) { - actor.height += jsEither([1, 1, 2, 2, 2]); - } else if (actor.height <= 138) { - actor.height += 1; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 138) { - actor.height += jsEither([1, 1, 2, 2, 2]); - } else if (actor.height <= 141) { - actor.height += 1; - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 143) { - actor.height += jsEither([0, 0, 1, 1, 1]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 143) { - actor.height += jsEither([0, 0, 1, 1, 1]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 143) { - actor.height += jsEither([0, 0, 1, 1, 1]); - } - } - } else if (actor.hormoneBalance <= -200) { - if (physicalAgeSwap === 3) { - if (actor.height <= 80) { - actor.height += jsEither([2, 2, 3, 3]); - } else if (actor.height <= 84) { - actor.height += 1; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 84) { - actor.height += jsEither([5, 5, 6, 6]); - } else if (actor.height <= 90) { - actor.height += 2; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 90) { - actor.height += jsEither([9, 9, 10, 10]); - } else if (actor.height <= 100) { - actor.height += 5; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 100) { - actor.height += jsEither([4, 4, 5, 5]); - } else if (actor.height <= 105) { - actor.height += 2; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 105) { - actor.height += jsEither([3, 3, 4, 4]); - } else if (actor.height <= 109) { - actor.height += 1; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 109) { - actor.height += jsEither([4, 4, 5, 5]); - } else if (actor.height <= 114) { - actor.height += 1; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 114) { - actor.height += jsEither([3, 3, 4, 4]); - } else if (actor.height <= 118) { - actor.height += 1; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 118) { - actor.height += jsEither([3, 3, 4, 4]); - } else if (actor.height <= 122) { - actor.height += 1; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 122) { - actor.height += jsEither([4, 4, 5, 5]); - } else if (actor.height <= 127) { - actor.height += 2; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 127) { - actor.height += jsEither([4, 4, 5, 5]); - } else if (actor.height <= 132) { - actor.height += 2; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 132) { - actor.height += jsEither([2, 2, 3, 3]); - } else if (actor.height <= 135) { - actor.height += 1; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 135) { - actor.height += jsEither([2, 2, 3, 3]); - } else if (actor.height <= 138) { - actor.height += 1; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 138) { - actor.height += jsEither([2, 2, 3, 3]); - } else if (actor.height <= 141) { - actor.height += 1; - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 143) { - actor.height += jsEither([1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 143) { - actor.height += jsEither([1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 143) { - actor.height += jsEither([1, 1, 2, 2]); - } - } - } else if (actor.hormoneBalance <= -100) { - if (physicalAgeSwap === 3) { - if (actor.height <= 80) { - actor.height += jsEither([2, 2, 2, 3, 3]); - } else if (actor.height <= 84) { - actor.height += 1; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 84) { - actor.height += jsEither([5, 5, 5, 6, 6]); - } else if (actor.height <= 90) { - actor.height += 2; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 90) { - actor.height += jsEither([9, 9, 9, 10, 10]); - } else if (actor.height <= 100) { - actor.height += 5; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 100) { - actor.height += jsEither([4, 4, 4, 5, 5]); - } else if (actor.height <= 105) { - actor.height += 2; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 105) { - actor.height += jsEither([3, 3, 3, 4, 4]); - } else if (actor.height <= 109) { - actor.height += 1; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 109) { - actor.height += jsEither([4, 4, 4, 5, 5]); - } else if (actor.height <= 114) { - actor.height += 1; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 114) { - actor.height += jsEither([3, 3, 3, 4, 4]); - } else if (actor.height <= 118) { - actor.height += 1; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 118) { - actor.height += jsEither([3, 3, 3, 4, 4]); - } else if (actor.height <= 122) { - actor.height += 1; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 122) { - actor.height += jsEither([4, 4, 4, 5, 5]); - } else if (actor.height <= 127) { - actor.height += 2; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 127) { - actor.height += jsEither([4, 4, 4, 5, 5]); - } else if (actor.height <= 132) { - actor.height += 2; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 132) { - actor.height += jsEither([2, 2, 2, 3, 3]); - } else if (actor.height <= 135) { - actor.height += 1; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 135) { - actor.height += jsEither([2, 2, 2, 3, 3]); - } else if (actor.height <= 138) { - actor.height += 1; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 138) { - actor.height += jsEither([2, 2, 2, 3, 3]); - } else if (actor.height <= 141) { - actor.height += 1; - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 143) { - actor.height += jsEither([1, 1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 143) { - actor.height += jsEither([1, 1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 143) { - actor.height += jsEither([1, 1, 1, 2, 2]); - } - } - } else { - if (physicalAgeSwap === 3) { - if (actor.height <= 80) { - actor.height += jsEither([1, 1, 2, 2, 3, 3]); - } else if (actor.height <= 84) { - actor.height += 1; - } - } else if (physicalAgeSwap === 4) { - if (actor.height <= 84) { - actor.height += jsEither([4, 4, 5, 5, 6, 6]); - } else if (actor.height <= 90) { - actor.height += 2; - } - } else if (physicalAgeSwap === 5) { - if (actor.height <= 90) { - actor.height += jsEither([8, 8, 9, 9, 10, 10]); - } else if (actor.height <= 100) { - actor.height += 5; - } - } else if (physicalAgeSwap === 6) { - if (actor.height <= 100) { - actor.height += jsEither([3, 3, 4, 4, 5, 5]); - } else if (actor.height <= 105) { - actor.height += 2; - } - } else if (physicalAgeSwap === 7) { - if (actor.height <= 105) { - actor.height += jsEither([2, 2, 3, 3, 4, 4]); - } else if (actor.height <= 109) { - actor.height += 1; - } - } else if (physicalAgeSwap === 8) { - if (actor.height <= 109) { - actor.height += jsEither([3, 3, 4, 4, 5, 5]); - } else if (actor.height <= 114) { - actor.height += 1; - } - } else if (physicalAgeSwap === 9) { - if (actor.height <= 114) { - actor.height += jsEither([2, 2, 3, 3, 4, 4]); - } else if (actor.height <= 118) { - actor.height += 1; - } - } else if (physicalAgeSwap === 10) { - if (actor.height <= 118) { - actor.height += jsEither([2, 2, 3, 3, 4, 4]); - } else if (actor.height <= 122) { - actor.height += 1; - } - } else if (physicalAgeSwap === 11) { - if (actor.height <= 122) { - actor.height += jsEither([3, 3, 4, 4, 5, 5]); - } else if (actor.height <= 127) { - actor.height += 2; - } - } else if (physicalAgeSwap === 12) { - if (actor.height <= 127) { - actor.height += jsEither([3, 3, 4, 4, 5, 5]); - } else if (actor.height <= 132) { - actor.height += 2; - } - } else if (physicalAgeSwap === 13) { - if (actor.height <= 132) { - actor.height += jsEither([1, 1, 2, 2, 3, 3]); - } else if (actor.height <= 135) { - actor.height += 1; - } - } else if (physicalAgeSwap === 14) { - if (actor.height <= 135) { - actor.height += jsEither([1, 1, 2, 2, 3, 3]); - } else if (actor.height <= 138) { - actor.height += 1; - } - } else if (physicalAgeSwap === 15) { - if (actor.height <= 138) { - actor.height += jsEither([1, 1, 2, 2, 3, 3]); - } else if (actor.height <= 141) { - actor.height += 1; - } - } else if (physicalAgeSwap === 16) { - if (actor.height <= 143) { - actor.height += jsEither([0, 0, 1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 17) { - if (actor.height <= 143) { - actor.height += jsEither([0, 0, 1, 1, 2, 2]); - } - } else if (physicalAgeSwap === 18) { - if (actor.height <= 143) { - actor.height += jsEither([0, 0, 1, 1, 2, 2]); - } - } + function increaseHeight(actor) { + const unalteredHeight = actor.height - actor.heightImplant * 10; + const lastYearsTarget = Height.forAge(actor.natural.height, physicalAgeSwap - 1, actor.genes); + const thisYearsTarget = Height.forAge(actor.natural.height, physicalAgeSwap, actor.genes); + // by default, grow by the difference in natural height targets, +1/-2 cm + // slightly undershooting on average is intentional, since we can't shrink but we CAN have growth spurts + let thisYearsGrowth = thisYearsTarget - lastYearsTarget + jsRandom(-2, 1); + // if we're way ahead of target or way behind target, adjust towards it a bit harder + // if the player doesn't interfere, this mechanism should always end up within 2cm of the target at age 20, with slightly "spurty" growth + const deltaFromTarget = thisYearsTarget - (unalteredHeight + thisYearsGrowth); + const yearsLeft = Math.min(5, 21 - physicalAgeSwap); + if (deltaFromTarget >= yearsLeft) { + thisYearsGrowth = Math.max(0, thisYearsGrowth) + 2; + } else if (deltaFromTarget <= -yearsLeft) { + thisYearsGrowth = Math.min(0, thisYearsGrowth) - 2; } - } - - /** - * @param {FC.HumanState} actor - */ - function increaseHeightGiant(actor) { - if (actor.hormoneBalance >= 200) { - if (physicalAgeSwap < 16) { - if (actor.height <= 270) { - actor.height += random(5, 12); - } - } else { - if (actor.height <= 270) { - actor.height += random(3, 7); - } - } - } else if (actor.hormoneBalance >= 100) { - if (physicalAgeSwap < 16) { - if (actor.height <= 270) { - actor.height += random(7, 15); - } - } else { - if (actor.height <= 270) { - actor.height += random(5, 7); - } - } - } else if (actor.hormoneBalance <= -200) { - if (physicalAgeSwap < 16) { - if (actor.height <= 270) { - actor.height += random(10, 25); - } - } else { - if (actor.height <= 270) { - actor.height += random(7, 13); - } - } - } else if (actor.hormoneBalance <= -100) { - if (physicalAgeSwap < 16) { - if (actor.height <= 270) { - actor.height += random(7, 22); - } - } else { - if (actor.height <= 270) { - actor.height += random(7, 12); - } - } - } else { - if (physicalAgeSwap < 16) { - if (actor.height <= 270) { - actor.height += random(7, 20); - } - } else { - if (actor.height <= 270) { - actor.height += random(5, 10); - } - } + // never shrink + if (thisYearsGrowth > 0) { + actor.height += Math.round(thisYearsGrowth); } } diff --git a/src/events/intro/acquisition.js b/src/events/intro/acquisition.js index 1129083c2b8..bd2c6d258f6 100644 --- a/src/events/intro/acquisition.js +++ b/src/events/intro/acquisition.js @@ -1003,6 +1003,7 @@ App.Intro.acquisition = function() { slave.geneticQuirks.dwarfism = 2; } } + slave.natural.height = slave.height; } slave.skill.oral = random(35, 65); slave.skill.anal = random(15, 35); @@ -1035,6 +1036,7 @@ App.Intro.acquisition = function() { slave.geneticQuirks.gigantism = 2; } } + slave.natural.height = slave.height; } slave.skill.oral = random(15, 35); slave.skill.anal = random(15, 35); diff --git a/src/events/intro/introSummary.js b/src/events/intro/introSummary.js index b4e33818e10..5baa94df043 100644 --- a/src/events/intro/introSummary.js +++ b/src/events/intro/introSummary.js @@ -5,6 +5,7 @@ App.Intro.summary = function() { V.FSCreditCount = variableAsNumber(V.FSCreditCount, 4, 7, 5); V.PC.actualAge = variableAsNumber(V.PC.actualAge, 10, 80, 35); V.PC.height = variableAsNumber(V.PC.height, 85, 305, 185); + V.PC.natural.height = variableAsNumber(V.PC.natural.height, 85, 305, 185); V.PC.boobs = variableAsNumber(V.PC.boobs, 100, 50000, 200); V.PC.pubertyAgeXX = variableAsNumber(V.PC.pubertyAgeXX, 8, 13, 13); V.PC.pubertyAgeXY = variableAsNumber(V.PC.pubertyAgeXY, 8, 13, 13); diff --git a/src/events/intro/pcAppearance.js b/src/events/intro/pcAppearance.js index ad43fb8b35d..8439650ad9d 100644 --- a/src/events/intro/pcAppearance.js +++ b/src/events/intro/pcAppearance.js @@ -18,19 +18,44 @@ App.UI.Player.appearance = function(options, summary = false) { 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.physicalAge} year old is ${heightToEitherUnit(Height.mean(V.PC))}`); + if (V.PC.physicalAge >= 20) { + options.addOption(`You are`, "height", V.PC.natural).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 is ${heightToEitherUnit(Height.mean(V.PC))}`) + .addCallback(() => V.PC.height = V.PC.natural.height); + } else { + options.addOption(`When full-grown, you will be`, "height", V.PC.natural).showTextBox({unit: "cm"}) + .addRange(145, 150, "<", "Petite") + .addRange(155, 160, "<", "Short") + .addRange(165, 170, "<", "Average") + .addRange(180, 185, "<", "Tall") + .addRange(190, 185, ">=", "Very tall"); + } option = options.addCustomOption() .addButton( "Make average", () => resyncSlaveHeight(V.PC), "" ); + if (V.PC.physicalAge < 20) { + options.addOption(`But right now, you are`, "height", V.PC).showTextBox({unit: "cm"}) + .addRange(Height.forAge(145, V.PC), Height.forAge(150, V.PC), "<", "Petite for your age") + .addRange(Height.forAge(155, V.PC), Height.forAge(160, V.PC), "<", "Short for your age") + .addRange(Height.forAge(165, V.PC), Height.forAge(170, V.PC), "<", "Average for your age") + .addRange(Height.forAge(180, V.PC), Height.forAge(185, V.PC), "<", "Tall for your age") + .addRange(Height.forAge(190, V.PC), Height.forAge(185, V.PC), ">=", "Very tall for your age") + .addComment(`Average height for a ${V.PC.physicalAge} year old is ${heightToEitherUnit(Height.mean(V.PC))}`); + option = options.addCustomOption() + .addButton( + "Scale for age from adult height", + () => V.PC.height = Height.forAge(V.PC.natural.height, V.PC), + "" + ); + } options.addOption("Your skin tone is", "skin", V.PC).showTextBox() .addValueList(makeAList(V.PC.race === "catgirl" ? App.Medicine.Modification.catgirlNaturalSkins : App.Medicine.Modification.naturalSkins)); @@ -298,7 +323,7 @@ App.UI.Player.syncAgeBasedParameters = function() { V.PC.physicalAge = V.PC.actualAge; V.PC.visualAge = V.PC.actualAge; V.PC.ovaryAge = V.PC.actualAge; - V.PC.height = Height.random(V.PC, {limitMult: [1, 2]}); + V.PC.height = Height.forAge(V.PC.natural.height, V.PC); if (V.PC.genes === "XY") { if (V.PC.physicalAge <= 13) { V.PC.hips = -2; diff --git a/src/events/nonRandom/pAidResult.js b/src/events/nonRandom/pAidResult.js index 7882f1e68ce..b845aa3e635 100644 --- a/src/events/nonRandom/pAidResult.js +++ b/src/events/nonRandom/pAidResult.js @@ -249,7 +249,8 @@ App.Events.pAidResult = class pAidResult extends App.Events.BaseEvent { slave = GenerateNewSlave("XX", { disableDisability: 1, ageOverridesPedoMode: 1, minAge: 18, maxAge: 18 }); - slave.height = Height.random(slave, {skew: 1, limitMult: [0, 2]}); + slave.natural.height = Height.randomAdult(slave, {skew: 1, limitMult: [0.5, 2.5]}); + slave.height = Height.forAge(slave.natural.height, slave); slave.origin = "$He was a volleyball player you enslaved when you evacuated $him from a broken down bus."; slave.career = "a student athlete"; generateSalonModifications(slave); diff --git a/src/events/reRecruit/orphanFemboy.js b/src/events/reRecruit/orphanFemboy.js index 3224281851e..c7c8ca064a4 100644 --- a/src/events/reRecruit/orphanFemboy.js +++ b/src/events/reRecruit/orphanFemboy.js @@ -73,7 +73,8 @@ App.Events.recOrphanFemboy = class recOrphanFemboy extends App.Events.BaseEvent slave.scrotum = slave.balls; slave.pubicHStyle = "waxed"; slave.underArmHStyle = "waxed"; - slave.height = random(140, 170); + slave.natural.height = random(140, 170); + slave.height = Height.forAge(slave.natural.height, slave); slave.hips = random(-1, 0); slave.butt = 1; slave.anus = 1; diff --git a/src/events/reRecruit/racerDgChaser.js b/src/events/reRecruit/racerDgChaser.js index 06347da66a3..ab40f18f094 100644 --- a/src/events/reRecruit/racerDgChaser.js +++ b/src/events/reRecruit/racerDgChaser.js @@ -74,7 +74,8 @@ App.Events.recRacerDgChaser = class recRacerDgChaser extends App.Events.BaseEven slave.dick = random(4, 5); slave.balls = random(3, 4); slave.scrotum = slave.balls; - slave.height = Height.forAge(random(180, 200), slave); + slave.natural.height = random(180, 200); + slave.height = Height.forAge(slave.natural.height, slave); slave.weight = 0; slave.muscles = 50; slave.intelligence = random(-50, 50); diff --git a/src/events/reRecruit/racerLoser.js b/src/events/reRecruit/racerLoser.js index dd73371cc02..59e9a315772 100644 --- a/src/events/reRecruit/racerLoser.js +++ b/src/events/reRecruit/racerLoser.js @@ -85,7 +85,8 @@ App.Events.recRacerLoser = class recRacerLoser extends App.Events.BaseEvent { WombImpregnate(slave, slave.pregType, slave.pregSource, 0); slave.pubicHStyle = "waxed"; slave.underArmHStyle = "waxed"; - slave.height = Height.forAge(random(180, 200), slave); + slave.natural.height = random(180, 200); + slave.height = Height.forAge(slave.natural.height, slave); slave.hips = -1; slave.butt = 0; slave.anus = 0; diff --git a/src/events/reRecruit/racerWinner.js b/src/events/reRecruit/racerWinner.js index 7f6fce10e2d..911dadacc49 100644 --- a/src/events/reRecruit/racerWinner.js +++ b/src/events/reRecruit/racerWinner.js @@ -84,7 +84,8 @@ App.Events.recRacerWinner = class recRacerWinner extends App.Events.BaseEvent { slave.preg = -1; slave.pubicHStyle = "waxed"; slave.underArmHStyle = "waxed"; - slave.height = Height.forAge(random(180, 200), slave); + slave.natural.height = random(180, 200); + slave.height = Height.forAge(slave.natural.height, slave); slave.shoulders = random(-1, 1); slave.hips = -1; slave.butt = 0; diff --git a/src/events/reRecruit/starvingArtist.js b/src/events/reRecruit/starvingArtist.js index 4b62ba3121a..372a873f9ed 100644 --- a/src/events/reRecruit/starvingArtist.js +++ b/src/events/reRecruit/starvingArtist.js @@ -59,7 +59,8 @@ App.Events.recStarvingArtist = class recStarvingArtist extends App.Events.BaseEv slave.origin = "$He offered $himself to you for enslavement out of devotion to $his artistic 'craft'."; slave.boobs = random(4, 6) * 50; slave.weight = -20; - slave.height = Height.forAge(random(160, 200), slave); + slave.natural.height = random(160, 200); + slave.height = Height.forAge(slave.natural.height, slave); slave.face = random(15, 100); slave.butt = random(1, 2); slave.lips = 0; diff --git a/src/events/recETS/recetsIncestBrotherBrother.js b/src/events/recETS/recetsIncestBrotherBrother.js index f32c9036ae9..3744891a088 100644 --- a/src/events/recETS/recetsIncestBrotherBrother.js +++ b/src/events/recETS/recetsIncestBrotherBrother.js @@ -37,7 +37,6 @@ App.Events.recetsIncestBrotherBrother = class recetsIncestBrotherBrother extends brother1.relationship = 3; const brother2 = generateRelatedSlave(brother1, "younger brother"); - brother2.height += random(-5, 5); brother2.pubicHStyle = "shaved"; brother2.dick += 2; brother2.balls += 2; diff --git a/src/events/recETS/recetsIncestTwinBrother.js b/src/events/recETS/recetsIncestTwinBrother.js index 8ab785f0125..c7f204555c0 100644 --- a/src/events/recETS/recetsIncestTwinBrother.js +++ b/src/events/recETS/recetsIncestTwinBrother.js @@ -37,7 +37,6 @@ App.Events.recetsIncestTwinBrother = class recetsIncestTwinBrother extends App.E brother1.relationship = 3; const brother2 = generateRelatedSlave(brother1, "twin"); - brother2.height += random(-5, 5); brother2.energy = Math.max(brother2.energy, 40); brother2.attrXY = Math.max(brother2.attrXY, 70); if (brother2.behavioralFlaw === "hates men") { diff --git a/src/events/recETS/recetsIncestTwinSister.js b/src/events/recETS/recetsIncestTwinSister.js index 091551daba1..8ee9b516188 100644 --- a/src/events/recETS/recetsIncestTwinSister.js +++ b/src/events/recETS/recetsIncestTwinSister.js @@ -39,7 +39,6 @@ App.Events.recetsIncestTwinSister = class recetsIncestTwinSister extends App.Eve const sis2 = generateRelatedSlave(sis1, "twin"); sis2.slaveName = sis2.birthName; - sis2.height += random(-5, 5); sis2.energy = Math.max(sis2.energy, 40); sis2.attrXX = Math.max(sis2.attrXX, 70); if (sis2.behavioralFlaw === "hates women") { diff --git a/src/events/recETS/recetsIncestTwinsMixed.js b/src/events/recETS/recetsIncestTwinsMixed.js index b8f46f391e7..6bcb38c8bae 100644 --- a/src/events/recETS/recetsIncestTwinsMixed.js +++ b/src/events/recETS/recetsIncestTwinsMixed.js @@ -40,7 +40,6 @@ App.Events.recetsIncestTwinsMixed = class recetsIncestTwinsMixed extends App.Eve sis.relationship = 3; const bro = generateRelatedSlave(sis, "twin", true); - bro.height += random(-5, 5); bro.vagina = -1; bro.dick = 2; bro.foreskin = 2; diff --git a/src/events/recFS/recfsPetiteAdmiration.js b/src/events/recFS/recfsPetiteAdmiration.js index c016347525b..5d7e091ed0c 100644 --- a/src/events/recFS/recfsPetiteAdmiration.js +++ b/src/events/recFS/recfsPetiteAdmiration.js @@ -11,15 +11,16 @@ App.Events.recFSPetiteAdmiration = class recFSPetiteAdmiration extends App.Event const slave = GenerateNewSlave(null, {minAge: 13, maxAge: 22, disableDisability: 1}); generateSalonModifications(slave); slave.origin = "$He offered $himself for voluntary enslavement to avoid being singled out by ruthless slavers."; - if (slave.height >= Height.forAge(150, slave)) { - slave.height = Height.random(slave, {limitMult: [-2, 0]}); - if (slave.height >= Height.forAge(150, slave)) { - slave.height = Height.random(slave, {limitMult: [-3, -1]}); - if (slave.height >= Height.forAge(150, slave)) { - slave.height = Height.forAge(random(90, 130), slave); + if (slave.natural.height >= 150) { + slave.natural.height = Height.randomAdult(slave, {limitMult: [-2, 0]}); + if (slave.natural.height >= 150) { + slave.natural.height = Height.randomAdult(slave, {limitMult: [-3, -1]}); + if (slave.natural.height >= 150) { + slave.natural.height = random(90, 130); slave.geneticQuirks.dwarfism = 2; } } + slave.height = Height.forAge(slave.natural.height, slave); } setHealth(slave, jsRandom(20, 40), undefined, undefined, 0, 0); slave.face = Math.clamp(slave.face+80, -100, 100); diff --git a/src/events/recFS/recfsPetiteAdmirationTwo.js b/src/events/recFS/recfsPetiteAdmirationTwo.js index 4f1bf7ca5f1..294e5574337 100644 --- a/src/events/recFS/recfsPetiteAdmirationTwo.js +++ b/src/events/recFS/recfsPetiteAdmirationTwo.js @@ -20,7 +20,8 @@ App.Events.recFSPetiteAdmirationTwo = class recFSPetiteAdmirationTwo extends App slave.career = "a porn star"; generateSalonModifications(slave); slave.origin = "$He offered $himself to you for enslavement because $he felt your arcology would be a nice place to retire to."; - slave.height = random(90, 100); + slave.natural.height = random(90, 100); + slave.height = slave.natural.height; slave.geneticQuirks.dwarfism = 2; slave.boobsImplant += random(4, 6)*200; slave.boobs += slave.boobsImplant; diff --git a/src/events/recFS/recfsSlimnessEnthusiast.js b/src/events/recFS/recfsSlimnessEnthusiast.js index 64dd26301cd..c0a04697fd1 100644 --- a/src/events/recFS/recfsSlimnessEnthusiast.js +++ b/src/events/recFS/recfsSlimnessEnthusiast.js @@ -22,7 +22,8 @@ App.Events.recFSSlimnessEnthusiast = class recFSSlimnessEnthusiast extends App.E slave.origin = "$He offered $himself to you for enslavement because $he felt your arcology was the best place for a $woman of $his appearance."; slave.boobs = random(4, 6)*50; slave.weight = -20; - slave.height = random(160, 200); + slave.natural.height = random(160, 200); + slave.height = slave.natural.height; slave.face = random(15, 100); slave.butt = random(1, 2); slave.lips = 0; diff --git a/src/events/recFS/recfsSlimnessEnthusiastTwo.js b/src/events/recFS/recfsSlimnessEnthusiastTwo.js index 069960a74a3..b8660fa09b4 100644 --- a/src/events/recFS/recfsSlimnessEnthusiastTwo.js +++ b/src/events/recFS/recfsSlimnessEnthusiastTwo.js @@ -13,7 +13,8 @@ App.Events.recFSSlimnessEnthusiastTwo = class recFSSlimnessEnthusiastTwo extends slave.origin = "$He offered $himself to you for enslavement to escape having plastic surgery foisted on $him."; slave.boobs = random(4, 6)*50; slave.weight = -20; - slave.height = random(160, 200); + slave.natural.height = random(160, 200); + slave.height = slave.natural.height; slave.face = random(15, 100); slave.butt = random(1, 2); slave.lips = 0; diff --git a/src/events/recFS/recfsStatuesqueGlorification.js b/src/events/recFS/recfsStatuesqueGlorification.js index a8701cd3b7b..9e22ea676ca 100644 --- a/src/events/recFS/recfsStatuesqueGlorification.js +++ b/src/events/recFS/recfsStatuesqueGlorification.js @@ -18,7 +18,8 @@ App.Events.recFSStatuesqueGlorification = class recFSStatuesqueGlorification ext const slave = GenerateNewSlave(null, {disableDisability: 1}); generateSalonModifications(slave); slave.origin = "$He offered $himself for voluntary enslavement to avoid being singled out by ruthless slavers."; - slave.height = Height.forAge(random(200, 264), slave); + slave.natural.height = random(200, 264); + slave.height = Height.forAge(slave.natural.height, slave); setHealth(slave, jsRandom(20, 40), undefined, undefined, 0, 0); slave.geneticQuirks.gigantism = 2; slave.devotion = random(15, 20); diff --git a/src/events/recFS/recfsStatuesqueGlorificationTwo.js b/src/events/recFS/recfsStatuesqueGlorificationTwo.js index 7ba3ebf7ab0..dfd7bcefebb 100644 --- a/src/events/recFS/recfsStatuesqueGlorificationTwo.js +++ b/src/events/recFS/recfsStatuesqueGlorificationTwo.js @@ -10,7 +10,8 @@ App.Events.recFSStatuesqueGlorificationTwo = class recFSStatuesqueGlorificationT let r = []; const slave = GenerateNewSlave(null, {disableDisability: 1}); slave.origin = "$He offered $himself for voluntary enslavement knowing $he would only fit in with your help."; - slave.height = 165; + slave.natural.height = 165; + slave.height = Height.forAge(slave.natural.height, slave); setHealth(slave, jsRandom(20, 40), undefined, undefined, 0, 0); slave.shoes = "extreme heels"; slave.devotion = random(30, 45); diff --git a/src/events/scheduled/assholeKnight.js b/src/events/scheduled/assholeKnight.js index 98014450cd2..77123c11534 100644 --- a/src/events/scheduled/assholeKnight.js +++ b/src/events/scheduled/assholeKnight.js @@ -23,7 +23,8 @@ App.Events.SEAssholeKnight = class SEAssholeKnight extends App.Events.BaseEvent assholeKnight.behavioralQuirk = "none"; assholeKnight.trust = random(-30, -20); assholeKnight.butt = random(0, 1); - assholeKnight.height = random(175, 195); + assholeKnight.natural.height = random(175, 195); + assholeKnight.height = assholeKnight.natural.height; assholeKnight.fetish = "sadist"; assholeKnight.fetishStrength = 80; assholeKnight.preg = 0; diff --git a/src/events/scheduled/seCustomSlaveDelivery.js b/src/events/scheduled/seCustomSlaveDelivery.js index 3fc0fa58f97..6fce1c98df4 100644 --- a/src/events/scheduled/seCustomSlaveDelivery.js +++ b/src/events/scheduled/seCustomSlaveDelivery.js @@ -193,16 +193,17 @@ App.Events.SEcustomSlaveDelivery = class SEcustomSlaveDelivery extends App.Event /* I have no clue what I'm doing here */ if (V.customSlave.heightMod === "greatly below average") { - delivery.height = Height.random(delivery, {skew: -5, spread: 0.15, limitMult: [-5, -2]}); + delivery.natural.height = Height.randomAdult(delivery, {skew: -5, spread: 0.15, limitMult: [-5, -2]}); } else if (V.customSlave.heightMod === "below average") { - delivery.height = Height.random(delivery, {skew: -1, limitMult: [-2, 0]}); + delivery.natural.height = Height.randomAdult(delivery, {skew: -1, limitMult: [-2, 0]}); } else if (V.customSlave.heightMod === "normal") { - delivery.height = Height.random(delivery, {limitMult: [-1, 1]}); + delivery.natural.height = Height.randomAdult(delivery, {limitMult: [-1, 1]}); } else if (V.customSlave.heightMod === "above average") { - delivery.height = Height.random(delivery, {skew: 1, limitMult: [0, 2]}); + delivery.natural.height = Height.randomAdult(delivery, {skew: 1, limitMult: [0, 2]}); } else { - delivery.height = Height.random(delivery, {skew: 5, spread: 0.15, limitMult: [2, 5]}); + delivery.natural.height = Height.randomAdult(delivery, {skew: 5, spread: 0.15, limitMult: [2, 5]}); } + delivery.height = Height.forAge(delivery.natural.height, delivery); if (V.customSlave.intelligence === 3) { delivery.intelligence = random(96, 100); diff --git a/src/events/scheduled/seRecruiterSuccess.js b/src/events/scheduled/seRecruiterSuccess.js index 68e7acbdab7..3855c82e52d 100644 --- a/src/events/scheduled/seRecruiterSuccess.js +++ b/src/events/scheduled/seRecruiterSuccess.js @@ -141,7 +141,8 @@ App.Events.SERecruiterSuccess = class SERecruiterSuccess extends App.Events.Base slave.intelligence = Intelligence.random({limitIntelligence: [40, 100]}); } if (V.policies.SMR.eugenics.heightSMR === 1) { - slave.height = Height.mean(slave) + random(15, 30); + slave.natural.height = Height.mean(slave.nationality, slave.race, slave.genes, 20) + random(15, 30); + slave.height = Height.forAge(slave.natural.height, slave); } if (V.policies.SMR.eugenics.faceSMR === 1) { slave.face = random(40, 100); diff --git a/src/facilities/nursery/utils/nurseryUtils.js b/src/facilities/nursery/utils/nurseryUtils.js index 914c006e347..7240d517b2f 100644 --- a/src/facilities/nursery/utils/nurseryUtils.js +++ b/src/facilities/nursery/utils/nurseryUtils.js @@ -200,7 +200,6 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) { setHealth(child, jsRandom(80, 100), 0, 0, 0, 0); child.hears = 0; child.heels = 0; - child.height = jsRandom(85, 105); child.hips = 0; child.hormoneBalance = 0; child.hormones = 0; @@ -354,6 +353,7 @@ App.Facilities.Nursery.infantToChild = function infantToChild(child) { child.wombImplant = "none"; resetEyeColor(child, "both"); generatePronouns(child); + child.height = Height.forAge(child.natural.height, child); return child; }; diff --git a/src/facilities/surgery/analyzePregnancy.js b/src/facilities/surgery/analyzePregnancy.js index d8ca35ebedb..5f25ca40354 100644 --- a/src/facilities/surgery/analyzePregnancy.js +++ b/src/facilities/surgery/analyzePregnancy.js @@ -62,6 +62,10 @@ globalThis.analyzePregnancies = function(mother, cheat) { if (cheat) { option.showTextBox(); } + option = options.addOption(`Expected adult height: ${heightToEitherUnit(genes.adultHeight)}`, "adultHeight", genes); + if (cheat) { + option.showTextBox(); + } option = options.addOption(`Eye Color: ${capFirstChar(genes.eyeColor)}`, "eyeColor", genes); if (cheat) { option.showTextBox().pulldown(); diff --git a/src/interaction/siCustom.js b/src/interaction/siCustom.js index 71418245b01..1afa30bea50 100644 --- a/src/interaction/siCustom.js +++ b/src/interaction/siCustom.js @@ -16,7 +16,8 @@ App.UI.SlaveInteract.custom = function(slave, refresh) { App.UI.DOM.appendNewElement("h3", el, `Art`); el.append( customSlaveImage(), - customHairImage() + customHairImage(), + artSeed() ); App.UI.DOM.appendNewElement("h3", el, `Names`); @@ -674,6 +675,30 @@ App.UI.SlaveInteract.custom = function(slave, refresh) { return el; } + function artSeed() { + const frag = new DocumentFragment(); + if (V.imageChoice === 4) { // webGL only right now + App.UI.DOM.appendNewElement("p", frag, `WebGL rendering uses a "seed value" to make small changes to the appearance of your slaves. If you're dissatisfied with this slave's appearance and correcting ${his} physical parameters doesn't seem to help, you can try replacing the seed value. Slaves with identical seeds will look identical; the game carefully preserves this value for clones and identical twins, but if you change it here it becomes your responsibility.`); + + const setArtSeed = (/** @type {number} */ num) => { + slave.natural.artSeed = num; + refresh(); + App.Events.refreshEventArt(slave); + }; + const button = App.UI.DOM.makeElement("button", "Randomize"); + button.onclick = () => setArtSeed(jsRandom(0, 10 ** 14)); + const textbox = App.UI.DOM.makeTextBox(slave.natural.artSeed, (num) => setArtSeed(num), true); + textbox.style.maxWidth = "12em"; + textbox.style.minWidth = "12em"; + App.UI.DOM.appendNewElement("p", frag, App.UI.DOM.combineNodes( + "Art seed: ", + textbox, + button + )); + } + return frag; + } + function customSlaveImage() { let el = document.createElement('p'); el.append(`Assign ${him} a custom image: `); diff --git a/src/js/SlaveState.js b/src/js/SlaveState.js index 5224aead3fb..65f660557e4 100644 --- a/src/js/SlaveState.js +++ b/src/js/SlaveState.js @@ -601,6 +601,16 @@ App.Entity.EyeState = class EyeState { } }; +/** Genetic "natural targets" for this individual when full grown, without influence from drugs, surgery, etc */ +App.Entity.GeneticState = class GeneticState { + constructor() { + // TODO: move origHColor, origSkin, origRace here, as hColor, skin, race? + this.height = 170; // new - almost done. need to rewrite physical development for both player and slave. + // this.boobs = 500; // TODO: for pregmodder + this.artSeed = jsRandom(0, 10 ** 14); + } +}; + App.Entity.SlaveState = class SlaveState { constructor() { /** Slave's current name */ @@ -618,6 +628,8 @@ App.Entity.SlaveState = class SlaveState { this.genes = "XX"; /** @type {number} */ this.pronoun = App.Data.Pronouns.Kind.female; + /** slave's natural genetic properties */ + this.natural = new App.Entity.GeneticState(); /** game week slave was acquired. * * _0: Obtained prior to game start / at game start_ */ diff --git a/src/js/utilsSlave.js b/src/js/utilsSlave.js index 9c0c46f67e8..200b1f3d13f 100644 --- a/src/js/utilsSlave.js +++ b/src/js/utilsSlave.js @@ -637,6 +637,27 @@ globalThis.Height = (function() { return applyAge(result, age, genes); } + /** + * @param {{nationality: string, race: FC.Race, genes: string, physicalAge: number, birthWeek: number}} slave + * @param {Partial<heightConfig>} [conf] + * @returns {number} + */ + function _randomAdultHeight(slave, conf) { + const mean = _meanHeight({ + nationality: slave.nationality, + race: slave.race, + genes: slave.genes, + physicalAge: 20, + birthWeek: 0 + }); + if (conf) { + const localConfig = Object.assign({}, defaultConfig); + Object.assign(localConfig, conf); + return heightGenerator(localConfig, mean); + } + return heightGenerator(defaultConfig, mean); + } + /** * @param {{nationality: string, race: FC.Race, genes: string, physicalAge: number, birthWeek: number}} slave * @param {Partial<heightConfig>} [conf] @@ -670,6 +691,7 @@ globalThis.Height = (function() { return { mean: _meanHeight, random: _randomHeight, + randomAdult: _randomAdultHeight, forAge: _forAge, config: _config, }; @@ -959,7 +981,8 @@ globalThis.randomCareer = function(slave) { * @param {FC.HumanState} slave */ globalThis.resyncSlaveHeight = function(slave) { - slave.height = Height.random(slave); + slave.natural.height = Height.randomAdult(slave); + slave.height = Height.forAge(slave.natural.height, slave); }; /** @@ -2843,7 +2866,7 @@ globalThis.ageSlave = function(slave, forceDevelopment = false) { if (slave.broodmother === 1) { slave.ovaryAge += 0.2; } - if (slave.physicalAge <= 18 && (forceDevelopment || V.loliGrow > 0)) { + if (slave.physicalAge <= 20 && (forceDevelopment || V.loliGrow > 0)) { App.EndWeek.Shared.physicalDevelopment(slave); } }; diff --git a/src/js/wombJS.js b/src/js/wombJS.js index 00b724f1be4..b73dbee7883 100644 --- a/src/js/wombJS.js +++ b/src/js/wombJS.js @@ -101,6 +101,13 @@ globalThis.WombInit = function(actor) { {ID: null, mother: f.genetics.mother, father: f.genetics.father} ); } + if (!jsDef(f.genetics.artSeed)) { + // probably could detect and fix clones/twins here too, but I'm not bothering + f.genetics.artSeed = jsRandom(0, 10 ** 14); + } + if (!jsDef(f.genetics.adultHeight)) { + f.genetics.adultHeight = Height.randomAdult({nationality: f.genetics.nationality, race: f.genetics.race, genes: f.genetics.gender, physicalAge: 20, birthWeek: 0}); + } }); }; @@ -197,6 +204,7 @@ globalThis.WombImpregnateClone = function(actor, fCount, mother, age) { tf.genetics.faceShape = motherOriginal.faceShape; tf.genetics.geneticQuirks = clone(mother.geneticQuirks); tf.genetics.skin = motherOriginal.skin; + tf.genetics.artSeed = mother.natural.artSeed; try { if (actor.womb.length === 0) { diff --git a/src/markets/specificMarkets/eliteSlave.js b/src/markets/specificMarkets/eliteSlave.js index 6aa670ec4e3..8e5a2e99f01 100644 --- a/src/markets/specificMarkets/eliteSlave.js +++ b/src/markets/specificMarkets/eliteSlave.js @@ -37,10 +37,11 @@ App.Markets["Elite Slave"] = function() { slave.devotion = random(60, 100); if (!heightPass(slave)) { if (V.arcologies[0].FSPetiteAdmiration > 20) { - slave.height = Height.random(slave, {limitMult: [-4, -2]}); + slave.natural.height = Height.randomAdult(slave, {limitMult: [-4, -2]}); } else if (V.arcologies[0].FSStatuesqueGlorification > 20) { - slave.height = Height.random(slave, {limitMult: [3, 5]}); + slave.natural.height = Height.randomAdult(slave, {limitMult: [3, 5]}); } + slave.height = Height.forAge(slave.natural.height, slave); } if (V.arcologies[0].FSPaternalist > 20) { setHealth(slave, 100, 0, 0, 0, 0); diff --git a/src/markets/specificMarkets/prestigiousSlave.js b/src/markets/specificMarkets/prestigiousSlave.js index a14e42781f7..550f2ffc585 100644 --- a/src/markets/specificMarkets/prestigiousSlave.js +++ b/src/markets/specificMarkets/prestigiousSlave.js @@ -823,7 +823,8 @@ App.Markets["Prestigious Slave"] = function() { slave.prestigeDesc = "$He was once a rising old world politician, but was forced to flee from the increasingly dangerous politics common in a stressed world, and was subsequently enslaved."; slave.career = "a politician"; slave.muscles = random(10, 50); - slave.height = random(160, 200); + slave.natural.height = random(160, 200); + slave.height = slave.natural.height; slave.face = Math.clamp(slave.face + 20, -100, 100); slave.faceImplant += 20; slave.faceShape = "masculine"; diff --git a/src/npc/children/ChildState.js b/src/npc/children/ChildState.js index 67143dd75b9..27388ac6e51 100644 --- a/src/npc/children/ChildState.js +++ b/src/npc/children/ChildState.js @@ -19,6 +19,8 @@ App.Facilities.Nursery.ChildState = class ChildState { this.genes = "XX"; /** @type {number} */ this.pronoun = App.Data.Pronouns.Kind.female; + /** slave's natural genetic properties */ + this.natural = new App.Entity.GeneticState(); /** Game week slave was acquired. * * _0: Obtained prior to game start / at game start_ */ diff --git a/src/npc/databases/cheatmodeDatabase.js b/src/npc/databases/cheatmodeDatabase.js index 919e7945e8a..60baa376607 100644 --- a/src/npc/databases/cheatmodeDatabase.js +++ b/src/npc/databases/cheatmodeDatabase.js @@ -23,6 +23,7 @@ App.Intro.cheatModeSlaves = function() { setHealth(cheatSlave, 50); cheatSlave.devotion = 100; cheatSlave.nationality = "Stateless"; + cheatSlave.natural.height = 175; cheatSlave.height = 175; cheatSlave.race = "white"; cheatSlave.eye.origColor = "green"; @@ -92,6 +93,7 @@ App.Intro.cheatModeSlaves = function() { cheatSlave.devotion = 100; cheatSlave.nationality = "Stateless"; cheatSlave.muscles = 20; + cheatSlave.natural.height = 190; cheatSlave.height = 190; cheatSlave.race = "black"; cheatSlave.origHColor = "black"; @@ -161,6 +163,7 @@ App.Intro.cheatModeSlaves = function() { setHealth(cheatSlave, 10); cheatSlave.devotion = 60; cheatSlave.nationality = "Stateless"; + cheatSlave.natural.height = 175; cheatSlave.height = 175; cheatSlave.race = "black"; cheatSlave.pubicHColor = "black"; @@ -227,6 +230,7 @@ App.Intro.cheatModeSlaves = function() { cheatSlave.devotion = 60; cheatSlave.nationality = "Stateless"; cheatSlave.muscles = 50; + cheatSlave.natural.height = 190; cheatSlave.height = 190; cheatSlave.race = "black"; cheatSlave.origHColor = "black"; @@ -299,6 +303,7 @@ App.Intro.cheatModeSlaves = function() { cheatSlave.devotion = 30; cheatSlave.nationality = "Stateless"; cheatSlave.muscles = 50; + cheatSlave.natural.height = 175; cheatSlave.height = 175; cheatSlave.race = "white"; cheatSlave.eye.origColor = "green"; @@ -359,6 +364,7 @@ App.Intro.cheatModeSlaves = function() { cheatSlave.devotion = 60; cheatSlave.nationality = "Stateless"; cheatSlave.muscles = 50; + cheatSlave.natural.height = 190; cheatSlave.height = 190; cheatSlave.race = "black"; cheatSlave.origHColor = "black"; diff --git a/src/npc/generate/generateGenetics.js b/src/npc/generate/generateGenetics.js index 23cfcc48ee8..1a0a13c3deb 100644 --- a/src/npc/generate/generateGenetics.js +++ b/src/npc/generate/generateGenetics.js @@ -49,7 +49,9 @@ globalThis.generateGenetics = (function() { cloneID: 0, geneticQuirks: {}, fetish: "none", - spermY: 50 + spermY: 50, + adultHeight: 170, + artSeed: jsRandom(0, 10 ** 14) }; if (actor1.ID > 0) { mother = V.genePool.find(s => s.ID === actor1.ID); @@ -109,10 +111,40 @@ globalThis.generateGenetics = (function() { genes.behavioralFlaw = setBehavioralFlaw(father, mother); genes.fetish = setFetish(father, mother); genes.spermY = setSpermY(father, mother); + genes.adultHeight = setAdultHeight(father, mother, genes.gender, genes.race, genes.nationality, genes.geneticQuirks); return genes; } + /** set expected adult height for the fetus + * @param {FC.Zeroable<FC.HumanState>} father + * @param {FC.HumanState} mother + * @param {string} gender + * @param {FC.Race} race + * @param {string} nationality + * @param {Partial<FC.GeneticQuirks>} quirks + * @returns {number} + */ + function setAdultHeight(father, mother, gender, race, nationality, quirks) { + const randomPart = Height.random({nationality, race, genes: gender, physicalAge: 20, birthWeek: 0}); + if ((quirks.dwarfism === 2) !== (mother.geneticQuirks.dwarfism === 2) || + (quirks.gigantism === 2) !== (mother.geneticQuirks.gigantism === 2) || + father && ((quirks.dwarfism === 2) !== (father.geneticQuirks.dwarfism === 2)) || + father && ((quirks.gigantism === 2) !== (father.geneticQuirks.gigantism === 2))) { + // we have a height quirk change compared to one of our parents. better to just start over with a completely random target height. + return randomPart; + } + // global average: men are 7% taller than women. natural heights contain this bias. + const genderScalingFactor = 1.07; + // heritance ratio for height in humans is currently estimated at 79% (Yengo, L., Vedantam, S., Marouli, E., et al. "A saturated map of common genetic variants associated with human height." Nature 610, 704–712 (2022)) + const heritanceRatio = 0.79; + // assemble! + const motherPart = mother.natural.height * (gender === "XX" ? 1.0 : genderScalingFactor); + const fatherPart = father ? father.natural.height * (gender === "XY" ? 1.0 : (1 / genderScalingFactor)) : motherPart; + const inheritedPart = (motherPart + fatherPart) * 0.5; + return Math.round((heritanceRatio * inheritedPart) + ((1 - heritanceRatio) * randomPart)); + } + // get spermY value of the parent that's donating the Y chromosome function getSpermY(father, mother) { let sourceSpermY = 50; // default if no inherited Y chromosome (should be impossible, but the Adam Principle is optional, so it can happen) @@ -1088,6 +1120,7 @@ globalThis.generateGenetics = (function() { * @returns {App.Entity.SlaveState|App.Facilities.Nursery.InfantState} */ globalThis.generateChild = function(mother, ovum, incubator = false) { + /** @type {FC.FetusGenetics} */ let genes = ovum.genetics; // TODO: maybe just argument this? We'll see. let child; @@ -1129,6 +1162,7 @@ globalThis.generateChild = function(mother, ovum, incubator = false) { child.skin = getGeneticSkinColor(child); child.hColor = getGeneticHairColor(child); child.spermY = genes.spermY; + child.natural.height = genes.adultHeight; child.pubicHColor = child.hColor; child.underArmHColor = child.hColor; child.eyebrowHColor = child.hColor; @@ -1219,6 +1253,7 @@ globalThis.generateChild = function(mother, ovum, incubator = false) { child.tailColor = child.hColor; } child.spermY = genes.spermY; + child.natural.height = genes.adultHeight; resetEyeColor(child, "both"); child.pubicHColor = child.hColor; child.underArmHColor = child.hColor; diff --git a/src/npc/generate/generateLeadershipSlave.js b/src/npc/generate/generateLeadershipSlave.js index 4862b4c8e60..0f395edb91a 100644 --- a/src/npc/generate/generateLeadershipSlave.js +++ b/src/npc/generate/generateLeadershipSlave.js @@ -66,7 +66,8 @@ globalThis.generateLeadershipSlave = function(input, location) { slave.devotion = jsRandom(51, 85); slave.trust = jsRandom(51, 85); slave.muscles = jsRandom(30, 70); - slave.height = Height.random(slave, {skew: 3, spread: .2, limitMult: [1, 4]}); + slave.natural.height = Height.randomAdult(slave, {skew: 3, spread: .2, limitMult: [1, 4]}); + slave.height = Height.forAge(slave.natural.height, slave); slave.weight = jsRandom(-10, 10); slave.teeth = either("normal", "pointy"); slave.skill.combat = 70; @@ -164,7 +165,8 @@ globalThis.generateLeadershipSlave = function(input, location) { slave.muscles = jsRandom(41, 70); slave.sexualQuirk = "caring"; slave.weight = jsRandom(0, 30); - slave.height = Height.random(slave, {skew: 3, spread: .2, limitMult: [1, 4]}); + slave.natural.height = Height.randomAdult(slave, {skew: 3, spread: .2, limitMult: [1, 4]}); + slave.height = Height.forAge(slave.natural.height, slave); applyMaleGenitalia({dick: jsRandom(3, 5), balls: jsRandom(4, 9), prostate: either(1, 1, 1, 2)}); slave.career = either(App.Data.Careers.Leader.farmer); break; diff --git a/src/npc/generate/generateMarketSlave.js b/src/npc/generate/generateMarketSlave.js index 22843621dcd..84f4c115e5e 100644 --- a/src/npc/generate/generateMarketSlave.js +++ b/src/npc/generate/generateMarketSlave.js @@ -112,7 +112,8 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1 r += `The corporation specifically targets incredibly tall slaves. `; maxMult = 5; // do not limit tallness } - slave.height = Height.random(slave, {skew: V.corp.SpecHeight - 3, limitMult: [minMult, maxMult]}); + slave.natural.height = Height.randomAdult(slave, {skew: V.corp.SpecHeight - 3, limitMult: [minMult, maxMult]}); + slave.height = Height.forAge(slave.natural.height, slave); } if (V.corp.SpecVirgin === 1) { r += `The corporation ensures its slaves are virgins. `; @@ -865,27 +866,29 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1 } if (neighbor.FSPetiteAdmiration > 20) { r += `They tend to be short, some far more than others. `; - if (slave.height >= Height.forAge(160, slave)) { - slave.height = Height.random(slave, {limitMult: [-2, 0]}); - if (slave.height >= Height.forAge(160, slave)) { - slave.height = Height.random(slave, {limitMult: [-3, -1]}); - if (slave.height >= Height.forAge(160, slave)) { - slave.height = Height.forAge(jsRandom(90, 130), slave); + if (slave.natural.height >= 160) { + slave.natural.height = Height.random(slave, {limitMult: [-2, 0]}); + if (slave.natural.height >= 160) { + slave.natural.height = Height.random(slave, {limitMult: [-3, -1]}); + if (slave.natural.height >= 160) { + slave.natural.height = jsRandom(90, 130); slave.geneticQuirks.dwarfism = 2; } } + slave.height = Height.forAge(slave.natural.height, slave); } } else if (neighbor.FSStatuesqueGlorification > 20) { r += `They tend to be tall, if not unbelievably so. `; - if (slave.height < Height.forAge(170, slave)) { - slave.height = Height.random(slave, {limitMult: [0, 2]}); - if (slave.height < Height.forAge(170, slave)) { - slave.height = Height.random(slave, {limitMult: [1, 3]}); - if (slave.height < Height.forAge(170, slave)) { - slave.height = Height.forAge(jsRandom(200, 264), slave); + if (slave.natural.height < 170) { + slave.natural.height = Height.random(slave, {limitMult: [0, 2]}); + if (slave.natural.height < 170) { + slave.natural.height = Height.random(slave, {limitMult: [1, 3]}); + if (slave.natural.height < 170) { + slave.natural.height = jsRandom(200, 264); slave.geneticQuirks.gigantism = 2; } } + slave.height = Height.forAge(slave.natural.height, slave); } } if (neighbor.FSSlimnessEnthusiast > 20) { @@ -1599,7 +1602,7 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1 } else { setHealth(slave, jsRandom(-50, 100), Math.max(normalRandInt(0, 4), 0), Math.max(normalRandInt(10, 4), 0), Math.max(normalRandInt(0, 0.5), 0), jsRandom(10, 20)); } - slave.height = jsRandom(160, 210); + slave.height = Math.max(jsRandom(160, 210), slave.natural.height); slave.butt = jsRandom(4, 10); if (V.GRI.schoolUpgrade === 2) { slave.boobs = 200 * jsRandom(15, 30); @@ -2227,15 +2230,16 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1 setHealth(slave, jsRandom(60, 80), 0, Math.max(normalRandInt(0, 2), 0), 0, jsRandom(5, 20)); const minHeight = jsRandom(170, 180); if (V.HA.schoolUpgrade === 2) { - slave.height = Math.clamp(Height.random(slave, { + slave.natural.height = Math.clamp(Height.random(slave, { limitMult: [2, 15], spread: 0.1 }), minHeight, 274); slave.muscles = jsRandom(40, 80); } else { - slave.height = Math.clamp(Height.random(slave, {limitMult: [1, 4]}), minHeight, 274); + slave.natural.height = Math.clamp(Height.random(slave, {limitMult: [1, 4]}), minHeight, 274); slave.muscles = jsRandom(20, 40); } + slave.height = slave.natural.height; if (V.HA.schoolUpgrade === 3) { slave.weight = jsEither([10, 20, 20, 30, 30, 40, 40, 50]); slave.waist = jsRandom(-10, 40); diff --git a/src/npc/generate/generateNewSlaveJS.js b/src/npc/generate/generateNewSlaveJS.js index 771360302c3..da75bca2f20 100644 --- a/src/npc/generate/generateNewSlaveJS.js +++ b/src/npc/generate/generateNewSlaveJS.js @@ -167,12 +167,13 @@ globalThis.GenerateNewSlave = (function() { function generateXXBodyProportions() { if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2) { - slave.height = Height.random(slave, {limitMult: [-4, -1], spread: 0.15}); + slave.natural.height = Height.randomAdult(slave, {limitMult: [-4, -1], spread: 0.15}); } else if (slave.geneticQuirks.gigantism === 2) { - slave.height = Height.random(slave, {limitMult: [3, 10], spread: 0.15}); + slave.natural.height = Height.randomAdult(slave, {limitMult: [3, 10], spread: 0.15}); } else { - slave.height = Height.random(slave); + slave.natural.height = Height.randomAdult(slave); } + slave.height = Height.forAge(slave.natural.height, slave); if (slave.height >= Height.mean(slave) * 170 / 162.5) { slave.hips = jsEither([-1, 0, 0, 1, 1, 2, 2]); slave.shoulders = jsEither([-1, -1, 0, 0, 0, 1]); @@ -200,12 +201,13 @@ globalThis.GenerateNewSlave = (function() { function generateXYBodyProportions() { if (slave.geneticQuirks.dwarfism === 2 && slave.geneticQuirks.gigantism !== 2) { - slave.height = Height.random(slave, {limitMult: [-4, -1], spread: 0.15}); + slave.natural.height = Height.randomAdult(slave, {limitMult: [-4, -1], spread: 0.15}); } else if (slave.geneticQuirks.gigantism === 2) { - slave.height = Height.random(slave, {limitMult: [3, 10], spread: 0.15}); + slave.natural.height = Height.randomAdult(slave, {limitMult: [3, 10], spread: 0.15}); } else { - slave.height = Height.random(slave); + slave.natural.height = Height.randomAdult(slave); } + slave.height = Height.forAge(slave.natural.height, slave); if (slave.physicalAge <= 13) { if (slave.height > Height.mean(slave) * 170 / 172.5) { slave.hips = jsEither([-2, -1, -1, 0, 1]); diff --git a/src/npc/generate/generateRelatedSlave.js b/src/npc/generate/generateRelatedSlave.js index 9d9dd98adf8..95fc244f2af 100644 --- a/src/npc/generate/generateRelatedSlave.js +++ b/src/npc/generate/generateRelatedSlave.js @@ -260,6 +260,12 @@ globalThis.generateRelatedSlave = (function() { if (slave.butt > 1) { slave.butt += random(-1, 1); } + // fuzz height + const heightAdjust = random(-5, Math.min(maxHeight(slave) - slave.height, 5)); + slave.natural.height += heightAdjust; + slave.height += heightAdjust; + // reset art seed + slave.natural.artSeed = jsRandom(0, 10 ** 14); } /** @@ -290,7 +296,7 @@ globalThis.generateRelatedSlave = (function() { } // reset height - slave.height = Height.random(slave); + slave.height = Height.forAge(slave.natural.height, slave); // reset puberty status generatePuberty(slave); diff --git a/src/npc/generate/heroCreator.js b/src/npc/generate/heroCreator.js index 8ebe65004b8..b7426305047 100644 --- a/src/npc/generate/heroCreator.js +++ b/src/npc/generate/heroCreator.js @@ -100,10 +100,10 @@ App.Utils.getHeroSlave = function(heroSlave) { repairLimbs(newSlave); generatePuberty(newSlave); newSlave.weekAcquired = V.week; - if (!newSlave.pubicHColor) { + if (!heroSlave.pubicHColor) { newSlave.pubicHColor = newSlave.hColor; } - if (!newSlave.underArmHColor) { + if (!heroSlave.underArmHColor) { newSlave.underArmHColor = newSlave.hColor; } if (newSlave.override_Race !== 1) { @@ -127,6 +127,13 @@ App.Utils.getHeroSlave = function(heroSlave) { if (newSlave.override_Skin !== 1) { newSlave.skin = getGeneticSkinColor(newSlave); } + if (!heroSlave.natural?.height) { + // assumes adult - child hero slaves MUST specify natural height separately! + newSlave.natural.height = newSlave.height - newSlave.heightImplant * 10; + } + if (!heroSlave.natural?.artSeed) { + newSlave.natural.artSeed = jsRandom(0, 10 ** 14); + } setHealth(newSlave, newSlave.health.condition, 0, 0, 0, newSlave.health.tired); SetBellySize(newSlave); diff --git a/src/npc/generate/lawCompliance.js b/src/npc/generate/lawCompliance.js index d67ff08d971..050138c0eab 100644 --- a/src/npc/generate/lawCompliance.js +++ b/src/npc/generate/lawCompliance.js @@ -320,14 +320,16 @@ App.Desc.lawCompliance = function(slave, market = 0) { function FSPetiteAdmirationSMR() { if (!heightPass(slave)) { - slave.height = Height.random(slave, {skew: -1, limitMult: [-5, -2]}); + slave.natural.height = Height.randomAdult(slave, {skew: -1, limitMult: [-5, -2]}); + slave.height = Height.forAge(slave.natural.height, slave); } return `${His} height was meticulously taken before being allowed into the markets.`; } function FSStatuesqueGlorificationSMR() { if (!heightPass(slave)) { - slave.height = Height.random(slave, {skew: 1, limitMult: [2, 5]}); + slave.natural.height = Height.randomAdult(slave, {skew: 1, limitMult: [2, 5]}); + slave.height = Height.forAge(slave.natural.height, slave); } return `${His} height, as well as ${his} potential for growth, were meticulously taken before being allowed into the markets.`; } @@ -672,10 +674,11 @@ App.Desc.lawCompliance = function(slave, market = 0) { } function heightAdvancedSMRup() { - slave.height = Height.random(slave, { + slave.natural.height = Height.randomAdult(slave, { skew: V.policies.SMR.height.advancedSMR, limitMult: [0, 5 * V.policies.SMR.height.advancedSMR] }); + slave.height = Height.forAge(slave.natural.height, slave); let t = [`While ${he} was in the slave pens, ${he} saw that slaves on the shorter end of the height curve were immediately designated as menials and Fuckdolls.`]; if (slave.physicalAge < 16) { t.push(`${He} is <span class="gold">terrified</span> that if ${he} doesn't keep growing, ${he}'ll be reassigned on the spot without a second thought.`); @@ -688,10 +691,11 @@ App.Desc.lawCompliance = function(slave, market = 0) { } function heightAdvancedSMRdown() { - slave.height = Height.random(slave, { + slave.natural.height = Height.randomAdult(slave, { skew: V.policies.SMR.height.advancedSMR, limitMult: [0, 5 * V.policies.SMR.height.advancedSMR] }); + slave.height = Height.forAge(slave.natural.height, slave); let t = [`While ${he} was in the slave pens, ${he} saw that slaves on the taller end of the height curve were immediately designated as menials and Fuckdolls.`]; if (slave.physicalAge < 16) { t.push(`${He} is <span class="gold">terrified</span> that if ${he} goes through a growth spurt, ${he}'ll be reassigned on the spot without a second thought.`); diff --git a/src/npc/infants/InfantState.js b/src/npc/infants/InfantState.js index 1d74fcd36de..b0c36f76a85 100644 --- a/src/npc/infants/InfantState.js +++ b/src/npc/infants/InfantState.js @@ -13,6 +13,8 @@ App.Facilities.Nursery.InfantState = class InfantState { /** @type {FC.GenderGenes} */ this.genes = "XX"; this.pronoun = App.Data.Pronouns.Kind.female; + /** slave's natural genetic properties */ + this.natural = new App.Entity.GeneticState(); /** game week child was acquired. * * _0: Obtained prior to game start / at game start_ */ diff --git a/src/npc/startingGirls/startingGirls.js b/src/npc/startingGirls/startingGirls.js index 00d1aa92736..42021b2aa1b 100644 --- a/src/npc/startingGirls/startingGirls.js +++ b/src/npc/startingGirls/startingGirls.js @@ -66,6 +66,7 @@ App.StartingGirls.cleanup = function(slave) { slave.indenture = Math.clamp(slave.indenture, 26, 208) || 26; } + slave.natural.height = Math.clamp(slave.natural.height, 85, 274) || 140; slave.height = Math.clamp(slave.height, 85, 274) || 140; slave.boobs = Math.clamp(Math.trunc(slave.boobs / 50) * 50, 0, 50000) || 200; slave.hLength = Math.clamp(slave.hLength, 0, 500) || 40; @@ -714,13 +715,13 @@ App.StartingGirls.physical = function(slave, cheat = false) { .showTextBox().pulldown(); } - options.addOption(`Height: ${heightToEitherUnit(slave.height)}`, "height", slave).showTextBox({unit: "cm"}) + options.addOption(`Natural Adult Height: ${heightToEitherUnit(slave.natural.height)}`, "height", slave.natural).showTextBox({unit: "cm"}) .addRange(145, 150, "<", "Petite") .addRange(155, 160, "<", "Short") .addRange(165, 170, "<", "Average") .addRange(180, 185, "<", "Tall") .addRange(190, 185, ">=", "Very tall"); - option = options.addCustomOption(`Average height for a ${slave.physicalAge} year old is ${heightToEitherUnit(Height.mean(slave))}`) + option = options.addCustomOption(`Average natural adult height is ${heightToEitherUnit(Height.mean(slave.nationality, slave.race, slave.genes, 20))}`) .addButton( "Make average", () => resyncSlaveHeight(slave), @@ -729,17 +730,29 @@ App.StartingGirls.physical = function(slave, cheat = false) { if (cheat || slave.geneticQuirks.dwarfism === 2) { option.addButton( "Make dwarf", - () => slave.height = Height.random(slave, {limitMult: [-4, -1], spread: 0.15}), + () => slave.natural.height = Height.random(slave, {limitMult: [-4, -1], spread: 0.15}), "" ); } if (cheat || slave.geneticQuirks.gigantism === 2) { option.addButton( "Make giant", - () => slave.height = Height.random(slave, {limitMult: [3, 10], spread: 0.15}), + () => slave.natural.height = Height.random(slave, {limitMult: [3, 10], spread: 0.15}), "" ); } + options.addOption(`Current Height: ${heightToEitherUnit(slave.height)}`, "height", slave).showTextBox({unit: "cm"}) + .addRange(Height.forAge(145, slave), Height.forAge(150, slave), "<", `Petite for age`) + .addRange(Height.forAge(155, slave), Height.forAge(160, slave), "<", "Short for age") + .addRange(Height.forAge(165, slave), Height.forAge(170, slave), "<", "Average for age") + .addRange(Height.forAge(180, slave), Height.forAge(185, slave), "<", "Tall for age") + .addRange(Height.forAge(190, slave), Height.forAge(185, slave), ">=", "Very tall for age"); + options.addCustomOption(`Average height for a ${slave.physicalAge} year old is ${heightToEitherUnit(Height.mean(slave))}`) + .addButton( + "Scale for age from adult height", + () => slave.height = Height.forAge(slave.natural.height, slave), + "" + ); if (cheat) { options.addOption("Height implant", "heightImplant", slave) @@ -1714,7 +1727,7 @@ App.StartingGirls.profile = function(slave, cheat = false) { options.addOption("Age", "actualAge", slave).showTextBox() .customButton("Resync characteristics to age", () => resyncSlaveToAge(slave), "") - .customButton("Resync only height to age", () => slave.height = Height.random(slave), "") + .customButton("Resync only height to age", () => resyncSlaveHeight(slave), "") .addComment("It is recommended to resync if you change age significantly"); if (cheat) { options.addOption("Physical age", "physicalAge", slave).showTextBox(); @@ -1821,6 +1834,11 @@ App.StartingGirls.profile = function(slave, cheat = false) { options.addOption("Description", "desc", slave.custom).showTextBox({large: true}) .addComment("Use complete, capitalized and punctuated sentences."); options.addOption("Label", "label", slave.custom).showTextBox().addComment("Use a short phrase"); + if (V.imageChoice === 4) { + options.addOption("Art Seed", "artSeed", slave.natural).showTextBox({large: true}) + .customButton("Randomize", () => slave.natural.artSeed = jsRandom(0, 10 ** 14), "") + .addComment(`The WebGL Art Renderer uses the art seed to set minor face and body parameters. You can change it if you don't like this slave's appearance.`); + } el.append(options.render()); return el; diff --git a/src/npc/startingGirls/startingGirlsPassage.js b/src/npc/startingGirls/startingGirlsPassage.js index 91e4def4d8c..dbdacc91f56 100644 --- a/src/npc/startingGirls/startingGirlsPassage.js +++ b/src/npc/startingGirls/startingGirlsPassage.js @@ -120,7 +120,8 @@ App.StartingGirls.passage = function() { V.activeSlave.face = 55; V.activeSlave.muscles = 20; V.activeSlave.weight = -20; - V.activeSlave.height = Height.forAge(190, V.activeSlave); + V.activeSlave.natural.height = 190; + V.activeSlave.height = Height.forAge(V.activeSlave.natural.height, V.activeSlave); }, [], "Starting Girls" diff --git a/src/npc/surgery/bodySwap/bodySwap.js b/src/npc/surgery/bodySwap/bodySwap.js index 5c6cdb2c71a..a14253a4510 100644 --- a/src/npc/surgery/bodySwap/bodySwap.js +++ b/src/npc/surgery/bodySwap/bodySwap.js @@ -7,6 +7,7 @@ globalThis.bodySwap = function(soul, body, fromGenepool) { WombInit(body); // Just to be sure. soul.genes = body.genes; + soul.natural = body.natural; soul.physicalAge = body.physicalAge; soul.visualAge = body.visualAge; soul.ageImplant = body.ageImplant; diff --git a/src/player/js/PlayerState.js b/src/player/js/PlayerState.js index 54e5149ca8e..2132c257f82 100644 --- a/src/player/js/PlayerState.js +++ b/src/player/js/PlayerState.js @@ -258,6 +258,8 @@ App.Entity.PlayerState = class PlayerState { this.refreshmentType = 0; /** @type {number} */ this.pronoun = App.Data.Pronouns.Kind.male; + /** player's natural genetic properties */ + this.natural = new App.Entity.GeneticState(); /** * * career prior to becoming owner * * (22+) (14+) (10+) -- GitLab