diff --git a/devTools/types/FC/RA.d.ts b/devTools/types/FC/RA.d.ts index 17c7e6cf48ed8b4698cff3d982dec85682ed5e15..ac03fb5f0165565edecc3cd6cf52ac6aa28193c7 100644 --- a/devTools/types/FC/RA.d.ts +++ b/devTools/types/FC/RA.d.ts @@ -93,6 +93,7 @@ declare namespace FC { dick: ExpressiveNumericTarget; balls: ExpressiveNumericTarget; clit: ExpressiveNumericTarget; + nipples: NippleShape[]; intensity: number; } diff --git a/devTools/types/FC/human.d.ts b/devTools/types/FC/human.d.ts index 91bb4871c77d064b0f14cf8281bebdcf596c95e2..81593fb6dd0072d1f2e9ea48fa181b04220a9d80 100644 --- a/devTools/types/FC/human.d.ts +++ b/devTools/types/FC/human.d.ts @@ -497,7 +497,7 @@ declare global { type Markings = WithNone<"beauty mark" | "birthmark" | "freckles" | "heavily freckled">; type TailShape = WithNone<"cat" | "leopard" | "tiger" | "jaguar" | "lion" | "dog" | "wolf" | "jackal" | "fox" | "kitsune" | "tanuki" | "raccoon" | "rabbit" | "squirrel" | "horse" | "bird" | "phoenix" | "peacock" | "raven" | "swan" | "sheep" | "cow" | "gazelle" | "deer" | "succubus" | "dragon" >; type WingsShape = WithNone<"angel" | "seraph" | "demon"| "dragon" | "phoenix" | "bird"| "fairy" | "butterfly" | "moth" | "insect" | "evil" >; - + type ToyHole = "all her holes" | "mouth" | "boobs" | "pussy" | "ass" | "dick"; interface ToyHoleFreeze extends Record<string, ToyHole> { ALL: "all her holes"; @@ -518,14 +518,14 @@ declare global { type NippleShape = "huge" | "puffy" | "inverted" | "tiny" | "cute" | "partially inverted" | "fuckable" | "flat"; interface NippleShapeFreeze extends Record<string, NippleShape> { - HUGE: "huge"; - PUFFY: "puffy"; INVERTED: "inverted"; + PARTIAL: "partially inverted"; + FLAT: "flat"; TINY: "tiny"; CUTE: "cute"; - PARTIAL: "partially inverted"; + PUFFY: "puffy"; + HUGE: "huge"; FUCKABLE: "fuckable"; - FLAT: "flat"; } type LactationType = 0 | 1 | 2; diff --git a/js/003-data/constants.js b/js/003-data/constants.js index da40d9daac3ff5209169981b49ef04199ba88a6c..c3cace50ab82a7f3aed4f6ab30facaa8a312e5ea 100644 --- a/js/003-data/constants.js +++ b/js/003-data/constants.js @@ -391,14 +391,14 @@ globalThis.OvaryImplantType = Object.freeze({ * @enum {string} */ globalThis.NippleShape = Object.freeze({ - HUGE: "huge", - PUFFY: "puffy", INVERTED: "inverted", + PARTIAL: "partially inverted", + FLAT: "flat", TINY: "tiny", CUTE: "cute", - PARTIAL: "partially inverted", + PUFFY: "puffy", + HUGE: "huge", FUCKABLE: "fuckable", - FLAT: "flat", }); /** diff --git a/src/002-config/fc-version.js b/src/002-config/fc-version.js index 5ef16aebe97a460ecf404d24c82e1a1dd0c23c0f..14f201392c599c9f437ebd243c8a45d0f9ef6f7d 100644 --- a/src/002-config/fc-version.js +++ b/src/002-config/fc-version.js @@ -2,5 +2,5 @@ App.Version = { base: "0.10.7.1", // The vanilla version the mod is based off of, this should never be changed. pmod: "4.0.0-alpha.31", commitHash: null, - release: 1249, // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js. + release: 1250, // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js. }; diff --git a/src/js/DefaultRules.js b/src/js/DefaultRules.js index ebce434bf6a4dcc3f24de854eb8b489969aba0ca..5e44c3c4a73bb891939d80a1e0c119660042b465 100644 --- a/src/js/DefaultRules.js +++ b/src/js/DefaultRules.js @@ -1216,61 +1216,62 @@ globalThis.DefaultRules = function(slave, options) { ProcessOtherDrugs(slave, rule); return; } else if ( - [ + ([ rule.growth.boobs, rule.growth.butt, rule.growth.lips, rule.growth.dick, rule.growth.clit, rule.growth.balls - ].every(r => r === null) // Check if all objects in list equal null + ].every(r => r === null) && !rule.growth.nipples.length) // Check if all objects in list equal null ) { ProcessOtherDrugs(slave, rule); return; } // Asset growth/shrink - const sizingDrugs = new Set(["breast injections", "breast redistributors", "butt injections", "butt redistributors", "hyper breast injections", "hyper butt injections", "hyper penis enhancement", "hyper testicle enhancement", "intensive breast injections", "intensive butt injections", "intensive penis enhancement", "intensive testicle enhancement", "lip atrophiers", "lip injections", "penis atrophiers", "penis enhancement", "testicle atrophiers", "testicle enhancement", "clitoris enhancement", "intensive clitoris enhancement"]); + /** @type {Set<FC.Drug>} */ + const sizingDrugs = new Set([Drug.GROWBREAST, Drug.REDISTBREAST, Drug.HYPERBREAST, Drug.GROWBUTT, Drug.REDISTBUTT, Drug.HYPERBUTT, Drug.HYPERPENIS, Drug.HYPERTESTICLE, Drug.INTENSIVEBREAST, Drug.INTENSIVEBUTT, Drug.INTENSIVEPENIS, Drug.INTENSIVETESTICLE, Drug.ATROPHYLIP, Drug.GROWLIP, Drug.ATROPHYPENIS, Drug.GROWPENIS, Drug.ATROPHYTESTICLE, Drug.GROWTESTICLE, Drug.GROWCLIT, Drug.INTENSIVECLIT, Drug.GROWNIPPLE, Drug.ATROPHYNIPPLE]); // NOTE: property names in growDrugs, and shrinkDrugs must be identical and this fact is used by the drugs() below /** @type {Record<FC.SizableBodyPart, FC.Drug>} */ const growDrugs = { - lips: "lip injections", - boobs: "breast injections", - butt: "butt injections", + lips: Drug.GROWLIP, + boobs: Drug.GROWBREAST, + butt: Drug.GROWBUTT, clit: null, dick: null, balls: null }; if (slave.dick > 0) { - growDrugs.dick = "penis enhancement"; + growDrugs.dick = Drug.GROWPENIS; } else if (slave.vagina >= 0) { - growDrugs.clit = "clitoris enhancement"; + growDrugs.clit = Drug.GROWCLIT; } if (slave.balls > 0) { - growDrugs.balls = "testicle enhancement"; + growDrugs.balls = Drug.GROWTESTICLE; } if (V.arcologies[0].FSAssetExpansionistResearch === 1 && rule.hyper_drugs === 1) { - growDrugs.boobs = "hyper breast injections"; - growDrugs.butt = "hyper butt injections"; + growDrugs.boobs = Drug.HYPERBREAST; + growDrugs.butt = Drug.HYPERBUTT; if (slave.dick > 0) { - growDrugs.dick = "hyper penis enhancement"; + growDrugs.dick = Drug.HYPERPENIS; } if (slave.balls > 0) { - growDrugs.balls = "hyper testicle enhancement"; + growDrugs.balls = Drug.HYPERTESTICLE; } } else if (rule.growth.intensity && slave.indentureRestrictions < 2 && slave.health.condition > 0) { - growDrugs.boobs = "intensive breast injections"; - growDrugs.butt = "intensive butt injections"; + growDrugs.boobs = Drug.INTENSIVEBREAST; + growDrugs.butt = Drug.INTENSIVEBUTT; if (slave.dick > 0) { - growDrugs.dick = "intensive penis enhancement"; + growDrugs.dick = Drug.INTENSIVEPENIS; } else if (slave.vagina >= 0) { - growDrugs.clit = "intensive clitoris enhancement"; + growDrugs.clit = Drug.INTENSIVECLIT; } if (slave.balls > 0) { - growDrugs.balls = "intensive testicle enhancement"; + growDrugs.balls = Drug.INTENSIVETESTICLE; } } @@ -1285,18 +1286,18 @@ globalThis.DefaultRules = function(slave, options) { }; if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { - shrinkDrugs.lips = "lip atrophiers"; + shrinkDrugs.lips = Drug.ATROPHYLIP; if (slave.dick > 0) { - shrinkDrugs.dick = "penis atrophiers"; + shrinkDrugs.dick = Drug.ATROPHYPENIS; } else if (slave.vagina >= 0) { - shrinkDrugs.clit = "clitoris atrophiers"; + shrinkDrugs.clit = Drug.ATROPHYCLIT; } if (slave.balls > 0) { - shrinkDrugs.balls = "testicle atrophiers"; + shrinkDrugs.balls = Drug.ATROPHYTESTICLE; } if (slave.weight < 100) { - shrinkDrugs.boobs = "breast redistributors"; - shrinkDrugs.butt = "butt redistributors"; + shrinkDrugs.boobs = Drug.REDISTBREAST; + shrinkDrugs.butt = Drug.REDISTBUTT; } } @@ -1346,6 +1347,46 @@ globalThis.DefaultRules = function(slave, options) { } } + /** + * @param {FC.SlaveState} slave + * @param {FC.NippleShape[]} target + * @param {{drug: FC.Drug, weight: number, source:string}[]} priorities + * @param {object} source + */ + function nippleDrugs(slave, target, priorities, source) { + if (!target.length || target.includes(slave.nipples)) { return; } + + /** Assign sizes artificially + * @type {Record<FC.NippleShape, number>} */ + const sizes = { + flat: 0, + tiny: 1, + cute: 2, + puffy: 3, + huge: 4, + // the next ones are not directly reachable by drugs + "partially inverted": NaN, + inverted: NaN, + fuckable: NaN, + }; + + if (Number.isNaN(sizes[slave.nipples])) { return; } + // target is sorted according to the sizes above, and target does not include slave.nipples + + const curSize = sizes[slave.nipples]; + for (const tgt of target) { + const tgtSize = sizes[tgt]; + if (curSize < tgtSize) { + priorities.push({drug: Drug.GROWNIPPLE, weight: 1.0 - (curSize / tgtSize) , source}); + return; + } + if (sizes[slave.nipples] > sizes[tgt]) { + priorities.push({drug: Drug.ATROPHYNIPPLE, weight: curSize / tgtSize - 1.0, source}); + return; + } + } + } + /** @type {{drug: FC.Drug, weight: number, source:string}[]} */ let priorities = []; drugs(slave, "boobs", rule.growth.boobs, priorities, 200, sourceRecord.growth.boobs); @@ -1354,6 +1395,7 @@ globalThis.DefaultRules = function(slave, options) { drugs(slave, "dick", rule.growth.dick, priorities, 1, sourceRecord.growth.dick); drugs(slave, "clit", rule.growth.clit, priorities, 1, sourceRecord.growth.clit); drugs(slave, "balls", rule.growth.balls, priorities, 1, sourceRecord.growth.balls); + nippleDrugs(slave, rule.growth.nipples, priorities, sourceRecord.growth.nipples); if (priorities.length > 0) { const action = priorities.reduce((acc, cur) => (acc.weight > cur.weight) ? acc : cur); diff --git a/src/js/rulesAssistant.js b/src/js/rulesAssistant.js index 457cf2214b716d038b4531473227d5f466ba8eff..073a5de0ac646c306cfe85a305cef9507aded9a7 100644 --- a/src/js/rulesAssistant.js +++ b/src/js/rulesAssistant.js @@ -333,6 +333,7 @@ App.RA.newRule = function() { dick: null, balls: null, clit: null, + nipples: [], intensity: 0 }; } diff --git a/src/js/rulesAssistantOptions.js b/src/js/rulesAssistantOptions.js index 49c972d65defa002461147718bc9b138cec97aea..836238debaa03c01fb4f8cb8b6fe524c431ead9c 100644 --- a/src/js/rulesAssistantOptions.js +++ b/src/js/rulesAssistantOptions.js @@ -2101,7 +2101,7 @@ App.RA.options = (function() { this.lips = new ExprLipGrowthList(); this.clits = new ExprClitGrowthList(); } - this.sublists.push(this.breasts, this.butts, this.lips, this.clits); + this.sublists.push(new NippleGrowthList(), this.breasts, this.butts, this.lips, this.clits); if (V.seeDicks > 0 || V.makeDicks > 0) { if (!V.experimental.raGrowthExpr) { @@ -2261,6 +2261,21 @@ App.RA.options = (function() { } } + class NippleGrowthList extends MultiListSelector { + constructor(label, target) { + /** @type {Array<[string, FC.NippleShape]>} */ + const items = [ + ["Tiny", NippleShape.TINY], + ["Cute", NippleShape.CUTE], + ["Puffy", NippleShape.PUFFY], + ["Huge", NippleShape.HUGE] + ]; + super("Nipple shape", items); + this.setValue(current_rule.set.growth.nipples); + this.onchange = (value) => current_rule.set.growth.nipples = value; + } + } + class ExprBreastGrowthList extends ExpressiveNumericTargetEditor { constructor() { const pairs = [