From 4ac1099f6d0fce18c42472a7bde0ad13e2ac5d62 Mon Sep 17 00:00:00 2001 From: Svornost <11434-svornost@users.noreply.gitgud.io> Date: Sat, 30 Apr 2022 20:00:18 -0400 Subject: [PATCH] Skintone fixes. 1. Fetuses generated with a particular non-mixed race selected will always have skintones within that race's natural genetic range. Mixed race fetuses remain unrestricted. 2. Catgirl fetuses will now get natural catgirl coloration instead of ordinary human skintones. 3. Catgirl natural skins are now in their own category so the `naturalSkins` guard on `skinToMelanin` works correctly. 4. Cheat mode will now offer natural skintones for catgirls from the catgirl list, and natural skintones from non-catgirls from the ordinary list. 5. The invalid "crinkled" hairstyle will no longer be set on some black slaves (instead, they'll have "afro"). --- js/003-data/slaveMods.js | 3 +- src/events/intro/pcAppearance.js | 4 +- src/facilities/salon/salonPassage.js | 3 +- src/facilities/surgery/analyzePregnancy.js | 2 +- src/js/utilsSlave.js | 2 +- src/npc/generate/generateGenetics.js | 67 +++++++++++++++++----- src/npc/generate/generateNewSlaveJS.js | 4 +- src/player/electiveSurgery.js | 2 +- 8 files changed, 63 insertions(+), 24 deletions(-) diff --git a/js/003-data/slaveMods.js b/js/003-data/slaveMods.js index 2f68317a67d..a07bac2d4e8 100644 --- a/js/003-data/slaveMods.js +++ b/js/003-data/slaveMods.js @@ -479,7 +479,8 @@ App.Medicine.Modification.eyeShape = [ {value: "wide-eyed"} ]; -App.Medicine.Modification.naturalSkins = ["pure white", "ivory", "white", "extremely pale", "very pale", "pale", "extremely fair", "very fair", "fair", "light", "light olive", "tan", "olive", "bronze", "dark olive", "dark", "light beige", "beige", "dark beige", "light brown", "brown", "dark brown", "black", "ebony", "pure black", "black and white striped", "red", "yellow"]; +App.Medicine.Modification.naturalSkins = ["pure white", "ivory", "white", "extremely pale", "very pale", "pale", "extremely fair", "very fair", "fair", "light", "light olive", "tan", "olive", "bronze", "dark olive", "dark", "light beige", "beige", "dark beige", "light brown", "brown", "dark brown", "black", "ebony", "pure black"]; +App.Medicine.Modification.catgirlNaturalSkins = ["white", "brown", "black", "red", "yellow", "black and white striped"]; App.Medicine.Modification.dyedSkins = ["camouflage patterned", "dyed blue", "dyed white", "dyed gray", "dyed black", "dyed green", "dyed pink", "dyed red", "tiger striped", "dyed purple", "clown"]; App.Medicine.Modification.naturalNippleColors = ["black", "brown", "dark brown", "ebony", "ivory", "light brown", "pale pink", "pink"]; App.Medicine.Modification.eyebrowStyles = new Set(["shaved", "straight", "rounded", "natural", "slanted inwards", "slanted outwards", "high-arched", "elongated", "shortened", "curved"]); diff --git a/src/events/intro/pcAppearance.js b/src/events/intro/pcAppearance.js index 07206f540ec..85d9523f96b 100644 --- a/src/events/intro/pcAppearance.js +++ b/src/events/intro/pcAppearance.js @@ -33,11 +33,11 @@ App.UI.Player.appearance = function(options, summary = false) { ); options.addOption("Your skin tone is", "skin", V.PC).showTextBox() - .addValueList(makeAList(App.Medicine.Modification.naturalSkins)); + .addValueList(makeAList(V.PC.race === "catgirl" ? App.Medicine.Modification.catgirlNaturalSkins : App.Medicine.Modification.naturalSkins)); if (V.cheatMode) { options.addOption("Your genetic skin tone is", "origSkin", V.PC).showTextBox() - .addValueList(makeAList(App.Medicine.Modification.naturalSkins)); + .addValueList(makeAList(V.PC.race === "catgirl" ? App.Medicine.Modification.catgirlNaturalSkins : App.Medicine.Modification.naturalSkins)); } if (V.cheatMode) { diff --git a/src/facilities/salon/salonPassage.js b/src/facilities/salon/salonPassage.js index ca637f7341e..70974df9f6d 100644 --- a/src/facilities/salon/salonPassage.js +++ b/src/facilities/salon/salonPassage.js @@ -407,7 +407,8 @@ App.UI.salon = function(slave, cheat = false, startingGirls = false) { if (cheat) { option = options.addOption(`${His} natural skin color is`, "origSkin", slave).showTextBox().pulldown(); - for (const skin of App.Medicine.Modification.naturalSkins) { + const naturalSkins = slave.race === "catgirl" ? App.Medicine.Modification.catgirlNaturalSkins : App.Medicine.Modification.naturalSkins; + for (const skin of naturalSkins) { option.addValue(capFirstChar(skin), skin, () => slave.skin = slave.origSkin); } } diff --git a/src/facilities/surgery/analyzePregnancy.js b/src/facilities/surgery/analyzePregnancy.js index 0279720d92c..26d217cb4ec 100644 --- a/src/facilities/surgery/analyzePregnancy.js +++ b/src/facilities/surgery/analyzePregnancy.js @@ -52,7 +52,7 @@ globalThis.analyzePregnancies = function(mother, cheat) { } option = options.addOption(`Skin tone: ${capFirstChar(genes.skin)}`, "skin", genes); if (cheat) { - option.showTextBox().pulldown().addValueList(App.Medicine.Modification.naturalSkins); + option.showTextBox().pulldown().addValueList(genes.race === "catgirl" ? App.Medicine.Modification.catgirlNaturalSkins : App.Medicine.Modification.naturalSkins); } option = options.addOption(`Intelligence index: ${genes.intelligence} out of 100`, "intelligence", genes); if (cheat) { diff --git a/src/js/utilsSlave.js b/src/js/utilsSlave.js index 86e0deb8154..69e896443e9 100644 --- a/src/js/utilsSlave.js +++ b/src/js/utilsSlave.js @@ -1619,7 +1619,7 @@ globalThis.randomRaceSkin = function(raceName) { skin = jsEither(["fair", "light", "pale"]); break; case "catgirl": - skin = jsEither(["black", "white", "brown", "red", "black and white striped", "yellow"]); + skin = jsEither(App.Medicine.Modification.catgirlNaturalSkins); break; default: skin = jsEither(["dark", "light", "pale"]); diff --git a/src/npc/generate/generateGenetics.js b/src/npc/generate/generateGenetics.js index 3d0ec6b553f..1b5ffaeeaff 100644 --- a/src/npc/generate/generateGenetics.js +++ b/src/npc/generate/generateGenetics.js @@ -104,8 +104,8 @@ globalThis.generateGenetics = (function() { genes.inbreedingCoeff = ibc.kinship(mother, father); genes.nationality = setNationality(father, mother); genes.geneticQuirks = setGeneticQuirks(activeFather, activeMother, genes.gender); - genes.skin = setSkin(father, mother); genes.race = setRace(father, mother); + genes.skin = setSkin(father, mother, genes.race); genes.intelligence = setIntelligence(father, mother, activeMother, actor2, genes.inbreedingCoeff); genes.face = setFace(father, mother, activeMother, actor2, genes.geneticQuirks, genes.inbreedingCoeff); genes.faceShape = setFaceShape(father, mother, genes.geneticQuirks); @@ -284,8 +284,12 @@ globalThis.generateGenetics = (function() { return race; } - // skin - function setSkin(father, mother) { + /** + * @param {FC.Zeroable<FC.HumanState>} father + * @param {FC.HumanState} mother + * @param {FC.Race} race + */ + function setSkin(father, mother, race) { /** @type {FC.Zeroable<string>} */ let fatherSkin = 0; let dadSkinIndex; @@ -316,21 +320,54 @@ globalThis.generateGenetics = (function() { "ivory": 2, "pure white": 1 }; - const momSkinIndex = mother ? (skinToMelanin[mother.origSkin] || 13) : 8; - if (father !== 0) { - fatherSkin = father.origSkin; - } else if (fatherRace !== 0) { - fatherSkin = randomRaceSkin(fatherRace); - } - dadSkinIndex = fatherSkin !== 0 ? (skinToMelanin[fatherSkin] || 13) : 8; - const skinIndex = Math.round(Math.random() * (dadSkinIndex - momSkinIndex) + momSkinIndex); + const racialSkinToneBounds = { + "black": [21, 25], + "white": [4, 12], + "latina": [10, 22], + "indo-aryan": [9, 24], + "malay": [9, 24], + "pacific islander": [11, 24], + "amerindian": [11, 22], + "asian": [4, 15], + "middle eastern": [10, 21], + "semitic": [10, 21], + "southern european": [9, 15] + }; let prop = ""; - for (prop in skinToMelanin) { - if (!skinToMelanin.hasOwnProperty(prop)) { continue; } - if (skinIndex >= skinToMelanin[prop]) { return prop; } + if (race === "catgirl") { + // pick a random catgirl color, slightly preferring the parents' coloration if applicable + const catgirlColors = [...App.Medicine.Modification.catgirlNaturalSkins]; + if (mother.origSkin in catgirlColors) { + catgirlColors.push(mother.origSkin, mother.origSkin); + } + if (father && father.origSkin in catgirlColors) { + catgirlColors.push(father.origSkin, father.origSkin); + } + return catgirlColors.random(); + } else { + // blend the father's and mother's skintones + const momSkinIndex = mother ? (skinToMelanin[mother.origSkin] || 13) : 8; + if (father !== 0) { + fatherSkin = father.origSkin; + } else if (fatherRace !== 0) { + fatherSkin = randomRaceSkin(fatherRace); + } + dadSkinIndex = fatherSkin !== 0 ? (skinToMelanin[fatherSkin] || 13) : 8; + + let skinIndex = Math.round(Math.random() * (dadSkinIndex - momSkinIndex) + momSkinIndex); + if (race in racialSkinToneBounds) { + // don't exceed the skintone bounds of the already-selected race (note that "mixed race" does not have bounds) + skinIndex = Math.clamp(skinIndex, racialSkinToneBounds[race][0], racialSkinToneBounds[race][1]); + } + + // find the skin name associated with the blended skintone + for (prop in skinToMelanin) { + if (!skinToMelanin.hasOwnProperty(prop)) { continue; } + if (skinIndex >= skinToMelanin[prop]) { return prop; } + } + return prop; } - return prop; // skinIndex can be zero - now false? } /** Make sure a given eye color is a valid genetic eye color and not the result of some modification. diff --git a/src/npc/generate/generateNewSlaveJS.js b/src/npc/generate/generateNewSlaveJS.js index 7ce7bc3833a..691e0b754e7 100644 --- a/src/npc/generate/generateNewSlaveJS.js +++ b/src/npc/generate/generateNewSlaveJS.js @@ -1484,7 +1484,7 @@ globalThis.GenerateNewSlave = (function() { slave.lips = jsRandom(5, 30); slave.origSkin = jsEither(["pure black", "ebony", "black", "dark brown", "brown"]); slave.origHColor = jsEither(["jet black", "black", "black", "black", "dark brown"]); - slave.hStyle = jsEither(["crinkled", "neat"]); + slave.hStyle = jsEither(["afro", "neat"]); eyeColor(["brown"], true); break; case "white": @@ -1553,7 +1553,7 @@ globalThis.GenerateNewSlave = (function() { break; case "catgirl": slave.lips = jsRandom(5, 25); - slave.origSkin = jsEither(["white", "brown", "black", "red", "yellow", "black and white striped"]); + slave.origSkin = jsEither(App.Medicine.Modification.catgirlNaturalSkins); slave.origHColor = jsEither(["black", "white", "golden", "red", "brown"]); slave.hStyle = jsEither(["undercut", "neat"]); slave.faceShape = "feline"; diff --git a/src/player/electiveSurgery.js b/src/player/electiveSurgery.js index 55fd1e625c7..0332fe21eca 100644 --- a/src/player/electiveSurgery.js +++ b/src/player/electiveSurgery.js @@ -168,7 +168,7 @@ App.UI.electiveSurgery = function() { if (V.PC.skin !== V.PC.origSkin) { choices.push({key: V.PC.origSkin, name: capFirstChar(`Restore natural ${V.PC.origSkin}`)}); } - for (const skin of App.Medicine.Modification.naturalSkins) { + for (const skin of [...App.Medicine.Modification.naturalSkins, ...App.Medicine.Modification.dyedSkins]) { choices.push({key: skin, name: capFirstChar(skin)}); } -- GitLab