diff --git a/devTools/FC.d.ts b/devTools/FC.d.ts index 6ceb1585e3b68965398ba5e9ae83d98fa8363d13..186f3b3073f6da8503c8d3f87d1841b1e1f3ee84 100644 --- a/devTools/FC.d.ts +++ b/devTools/FC.d.ts @@ -1,184 +1,241 @@ - interface Window { +interface Window { - jsRandom(min: number, max: number): number; + jsRandom(min: number, max: number): number; - SlaveDataSchemeCleanup(slave: App.Entity.SlaveState): void; + SlaveDataSchemeCleanup(slave: App.Entity.SlaveState): void; - walkPasts(slave: App.Entity.SlaveState, seed: any): string; - WombInit(actor: any): void; - WombImpregnate(actor, fCount, fatherID, age, surrogate?): void; - WombSurrogate(actor, fCount, mother, fatherID, age): void; - WombSort(actor): void; + walkPasts(slave: App.Entity.SlaveState, seed: any): string; + WombInit(actor: any): void; + WombImpregnate(actor, fCount, fatherID, age, surrogate?): void; + WombSurrogate(actor, fCount, mother, fatherID, age): void; + WombSort(actor): void; - capFirstChar(s: string): string; + capFirstChar(s: string): string; - canWalk(slave: App.Entity.SlaveState): boolean; + canWalk(slave: App.Entity.SlaveState): boolean; - rulesAutosurgery: any; - ruleApplied: any; - clearSummaryCache: any; - SlaveSummary: any; - SlaveSummaryUncached: any; - } + rulesAutosurgery: any; + ruleApplied: any; + clearSummaryCache: any; + SlaveSummary: any; + SlaveSummaryUncached: any; +} - declare namespace App { - namespace RA { - class NumericTarget { - cond: string; - val: number; - } +declare namespace App { + namespace RA { + class NumericTarget { + cond: string; + val: number; + } - class RuleConditions { - function: boolean | string; - data: any; - specialSlaves: number; - assignment: string[]; - selectedSlaves: number[]; - excludedSlaves: number[]; - } + class RuleConditions { + function: boolean | string; + data: any; + specialSlaves: number; + assignment: string[]; + selectedSlaves: number[]; + excludedSlaves: number[]; + } - class RuleSurgerySettings { - eyes: number; - hears: number; - smells: number; - tastes: number; - lactation: number; - prostate: number; - cosmetic: number; - accent: number; - shoulders: number; - shouldersImplant: number; - boobs: NumericTarget; - hips: number; - hipsImplant: number; - butt: NumericTarget; - faceShape: string; - lips: NumericTarget; - holes: number; - hair: number; - bodyhair: number; - vasectomy: boolean; - bellyImplant: string; - tummy: number; - } + class RuleSurgerySettings { + eyes: number; + hears: number; + smells: number; + tastes: number; + lactation: number; + prostate: number; + cosmetic: number; + accent: number; + shoulders: number; + shouldersImplant: number; + boobs: NumericTarget; + hips: number; + hipsImplant: number; + butt: NumericTarget; + faceShape: string; + lips: NumericTarget; + holes: number; + hair: number; + bodyhair: number; + vasectomy: boolean; + bellyImplant: string; + tummy: number; + } - class RuleSetters { - releaseRules: string; - toyHole: string; - clitSetting: string; - clitSettingXY: number; - clitSettingXX: number; - clitSettingEnergy: number; - speechRules: string; - clothes: string; - collar: string; - shoes: string; - legAccessory: string; - chastityVagina: number; - chastityAnus: number; - chastityPenis: number; - virginAccessory: string; - aVirginAccessory: string; - vaginalAccessory: string; - aVirginDickAccessory: string; - dickAccessory: string; - bellyAccessory: string; - aVirginButtplug: string; - buttplug: string; - vaginalAttachment: string; - buttplugAttachment: string; - eyeColor: string; - makeup: string; - nails: string; - hColor: string; - hLength: number; - haircuts: number; - hStyle: string; - eyebrowHColor: string; - eyebrowHStyle: string; - eyebrowFullness: string; - markings: string; - pubicHColor: string; - pubicHStyle: string; - nipplesPiercing: number; - areolaePiercing: number; - clitPiercing: number; - vaginaLube: number; - vaginaPiercing: number; - dickPiercing: number; - anusPiercing: number; - lipsPiercing: number; - tonguePiercing: number; - earPiercing: number; - nosePiercing: number; - eyebrowPiercing: number; - navelPiercing: number; - corsetPiercing: number; - boobsTat: string | number; - buttTat: string | number; - vaginaTat: string | number; - dickTat: string | number; - lipsTat: string | number; - anusTat: string | number; - shouldersTat: string | number; - armsTat: string | number; - legsTat: string | number; - backTat: string | number; - stampTat: string | number; - curatives: number; - livingRules: string; - relationshipRules: string; - standardPunishment: string; - standardReward: string; - diet: string | number; - dietCum: number; - dietMilk: number; - onDiet: number; - muscles: NumericTarget; - XY: number; - XX: number; - gelding: number; - preg: boolean; - abortion: string; - growth: { - boobs: NumericTarget; - butt: NumericTarget; - lips: NumericTarget; - dick: NumericTarget; - balls: NumericTarget; - intensity: number; - } - hyper_drugs: number; - aphrodisiacs: number; - autoSurgery: number; - autoBrand: number; - pornFeed: number; - pornFameSpending: number; - dietGrowthSupport: number; - eyewear: string; - earwear: string; - setAssignment: string; - facilityRemove: boolean; - removalAssignment: string; - surgery: RuleSurgerySettings; - underArmHColor: string; - underArmHStyle: string; - drug: string; - eyes: string; - pregSpeed: string; - bellyImplantVol: number; - teeth: string; + class RuleGrowthSetters { + boobs: NumericTarget; + butt: NumericTarget; + lips: NumericTarget; + dick: NumericTarget; + balls: NumericTarget; + intensity: number; + } + + class RuleSetters { + releaseRules: string; + toyHole: string; + clitSetting: string; + clitSettingXY: number; + clitSettingXX: number; + clitSettingEnergy: number; + speechRules: string; + clothes: string; + collar: string; + shoes: string; + legAccessory: string; + chastityVagina: number; + chastityAnus: number; + chastityPenis: number; + virginAccessory: string; + aVirginAccessory: string; + vaginalAccessory: string; + aVirginDickAccessory: string; + dickAccessory: string; + bellyAccessory: string; + aVirginButtplug: string; + buttplug: string; + vaginalAttachment: string; + buttplugAttachment: string; + eyeColor: string; + makeup: string; + nails: string; + hColor: string; + hLength: number; + haircuts: number; + hStyle: string; + eyebrowHColor: string; + eyebrowHStyle: string; + eyebrowFullness: string; + markings: string; + pubicHColor: string; + pubicHStyle: string; + nipplesPiercing: number; + areolaePiercing: number; + clitPiercing: number; + vaginaLube: number; + vaginaPiercing: number; + dickPiercing: number; + anusPiercing: number; + lipsPiercing: number; + tonguePiercing: number; + earPiercing: number; + nosePiercing: number; + eyebrowPiercing: number; + navelPiercing: number; + corsetPiercing: number; + boobsTat: string | number; + buttTat: string | number; + vaginaTat: string | number; + dickTat: string | number; + lipsTat: string | number; + anusTat: string | number; + shouldersTat: string | number; + armsTat: string | number; + legsTat: string | number; + backTat: string | number; + stampTat: string | number; + curatives: number; + livingRules: string; + relationshipRules: string; + standardPunishment: string; + standardReward: string; + diet: string | number; + dietCum: number; + dietMilk: number; + onDiet: number; + muscles: NumericTarget; + XY: number; + XX: number; + gelding: number; + preg: boolean; + abortion: string; + growth: RuleGrowthSetters; + hyper_drugs: number; + aphrodisiacs: number; + autoSurgery: number; + autoBrand: number; + pornFeed: number; + pornFameSpending: number; + dietGrowthSupport: number; + eyewear: string; + earwear: string; + setAssignment: string; + facilityRemove: boolean; + removalAssignment: string; + surgery: RuleSurgerySettings; + underArmHColor: string; + underArmHStyle: string; + drug: string; + eyes: string; + pregSpeed: string; + bellyImplantVol: number; + teeth: string; + label: string; + removeLabel: string; + skinColor: string; + inflationType: string; + } + + class Rule { + ID: string; + name: string; + condition: RuleConditions; + set: RuleSetters; + } + } + + namespace Medicine { + namespace Surgery { + /** + * Describes surgical procedure + */ + class Procedure { + /** + * Type code that identifies this kind of procedure. + * Currently unused, but planned for future use by RA for prioritizing procedures + */ + typeId: string; + /** + * Short label for the procedure. Can be used as a link text. + */ label: string; - removeLabel: string; - skinColor: string; - inflationType: string; + /** + * If procedure is targeted at changing object characteristic, this is the net change (signed) + */ + targetEffect: number; + /** + * Description of the procedure, more or less detailed + */ + description: string; + /** + * Money costs (positive when you pay for it) + */ + costs: number; + /** + * Projected health loss (positive when health decreases) + */ + healthCosts: number; + /** + * Function to perform the procedure + * If action is undefined, the procedure can't be applied (and .description contains the reason) + */ + action: slaveOperation; + /** + * surgery type for passages like "Surgery Degradation" + */ + surgeryType: string; } - class Rule { - ID: string; - name: string; - condition: RuleConditions; - set: RuleSetters; - } + class SizingOptions { + /** include possible augmentation procedures */ + augmentation?: boolean; + /** include possible reduction procedures */ + reduction?: boolean; + /** include option to install string implants */ + strings?: boolean; + /** include implant change options */ + replace?: boolean; + }; } } +} diff --git a/src/002-config/fc-js-init.js b/src/002-config/fc-js-init.js index b1af84f565502168e513b75b68802f25687de0dc..f72c839f781d59d8ab0bd4132a07806d460af06b 100644 --- a/src/002-config/fc-js-init.js +++ b/src/002-config/fc-js-init.js @@ -33,5 +33,6 @@ App.Facilities = { Arcade: {}, HGSuite: {} }; +App.Medicine = {}; App.RA = {}; App.SF = {}; diff --git a/src/js/rulesAssistant.js b/src/js/rulesAssistant.js index 260edbf6bf01da0e5de5df84bc71cde51e181edd..5ff2a48f841b0c1eb33e814fdb207a11cc0ce7ef 100644 --- a/src/js/rulesAssistant.js +++ b/src/js/rulesAssistant.js @@ -232,24 +232,41 @@ window.ruleAppliesP = function ruleAppliesP(cond, slave) { return flag; }; -/** - * @returns {App.RA.Rule} - */ -window.emptyDefaultRule = function emptyDefaultRule() { - const id = generateNewID(); - const rule = { - ID: id, - name: `Rule ${id}`, - condition: { +App.RA.newRule = function() { + return { + rule: emptyRule, + conditions: emptyConditions, + setters: emptySetters, + growth: emptyGrowth, + surgery: emptySurgery + }; + + /** @returns {App.RA.Rule} */ + function emptyRule() { + const id = generateNewID(); + return { + ID: id, + name: `Rule ${id}`, + condition: emptyConditions(), + // TODO: rename properties in snake_case to camelCase? + set: emptySetters() + }; + } + + /** @returns {App.RA.RuleConditions} */ + function emptyConditions() { + return { function: false, data: {}, specialSlaves: -1, assignment: [], selectedSlaves: [], excludedSlaves: [], - }, - // TODO: rename properties in snake_case to camelCase? - set: { + }; + } + /** @returns {App.RA.RuleSetters} */ + function emptySetters() { + return { releaseRules: null, toyHole: null, clitSetting: null, @@ -327,14 +344,7 @@ window.emptyDefaultRule = function emptyDefaultRule() { gelding: null, preg: null, abortion: null, - growth: { - boobs: null, - butt: null, - lips: null, - dick: null, - balls: null, - intensity: 0 - }, + growth: emptyGrowth(), hyper_drugs: 0, aphrodisiacs: null, autoSurgery: 0, @@ -347,30 +357,7 @@ window.emptyDefaultRule = function emptyDefaultRule() { setAssignment: null, facilityRemove: false, removalAssignment: "rest", - surgery: { - eyes: null, - hears: null, - smells: null, - tastes: null, - lactation: null, - prostate: null, - cosmetic: null, - accent: null, - shoulders: null, - shouldersImplant: null, - boobs: null, - hips: null, - hipsImplant: null, - butt: null, - faceShape: null, - lips: null, - holes: null, - tummy: null, - hair: null, - bodyhair: null, - vasectomy: null, - bellyImplant: null - }, + surgery: emptySurgery(), underArmHColor: null, underArmHStyle: null, drug: null, @@ -382,10 +369,54 @@ window.emptyDefaultRule = function emptyDefaultRule() { removeLabel: null, skinColor: null, inflationType: null, - } - }; - return rule; -}; + }; + } + + /** @returns {App.RA.RuleGrowthSetters} */ + function emptyGrowth() { + return { + boobs: null, + butt: null, + lips: null, + dick: null, + balls: null, + intensity: 0 + }; + } + + /** @returns {App.RA.RuleSurgerySettings} */ + function emptySurgery() { + return { + eyes: null, + hears: null, + smells: null, + tastes: null, + lactation: null, + prostate: null, + cosmetic: null, + accent: null, + shoulders: null, + shouldersImplant: null, + boobs: null, + hips: null, + hipsImplant: null, + butt: null, + faceShape: null, + lips: null, + holes: null, + tummy: null, + hair: null, + bodyhair: null, + vasectomy: null, + bellyImplant: null + }; + } +}(); + +/** + * @returns {App.RA.Rule} + */ +window.emptyDefaultRule = App.RA.newRule.rule; /** * Saves the slave, silently fires the RA, saves the slave's after-RA state, and then reverts the slave. diff --git a/src/js/rulesAutosurgery.js b/src/js/rulesAutosurgery.js index aa2f9b9dbe61d0fab36ae092784c362f7363fe3d..d7413c56fbd0a66938d0b1b3be32947f76894496 100644 --- a/src/js/rulesAutosurgery.js +++ b/src/js/rulesAutosurgery.js @@ -29,7 +29,7 @@ window.rulesAutosurgery = (function() { * @returns {App.RA.RuleSurgerySettings} */ function autoSurgerySelector(slave, ruleset) { - const surgery = {}; + const surgery = App.RA.newRule.surgery(); ruleset.forEach(rule => { Object.keys(rule.surgery) .filter(key => rule.surgery[key] !== null) @@ -45,71 +45,63 @@ window.rulesAutosurgery = (function() { * @returns {App.RA.RuleSurgerySettings} */ function ProcessHGTastes(slave) { - let thisSurgery; + let thisSurgery = App.RA.newRule.surgery(); switch (V.HGTastes) { case 1: - thisSurgery = { - lactation: 0, - cosmetic: 1, - faceShape: "cute", - lips: App.RA.makeTarget('==', 10), - hips: 0, - hipsImplant: 0, - butt: App.RA.makeTarget('==', 0), - accent: 0, - shoulders: 0, - shouldersImplant: 0, - boobs: App.RA.makeTarget('==', 0), - holes: 0 - }; + thisSurgery.lactation = 0; + thisSurgery.cosmetic = 1; + thisSurgery.faceShape = "cute"; + thisSurgery.lips = App.RA.makeTarget('==', 10); + thisSurgery.hips = 0; + thisSurgery.hipsImplant = 0; + thisSurgery.butt = App.RA.makeTarget('==', 0); + thisSurgery.accent = 0; + thisSurgery.shoulders = 0; + thisSurgery.shouldersImplant = 0; + thisSurgery.boobs = App.RA.makeTarget('==', 0); + thisSurgery.holes = 0; break; case 2: - thisSurgery = { - lactation: 0, - cosmetic: 1, - faceShape: "cute", - lips: App.RA.makeTarget('==', 60), - hips: 0, - hipsImplant: 0, - butt: App.RA.makeTarget('==', 4), - accent: 0, - shoulders: 0, - shouldersImplant: 0, - boobs: App.RA.makeTarget('==', 1200), - holes: 0 - }; + thisSurgery.lactation = 0; + thisSurgery.cosmetic = 1; + thisSurgery.faceShape = "cute"; + thisSurgery.lips = App.RA.makeTarget('==', 60); + thisSurgery.hips = 0; + thisSurgery.hipsImplant = 0; + thisSurgery.butt = App.RA.makeTarget('==', 4); + thisSurgery.accent = 0; + thisSurgery.shoulders = 0; + thisSurgery.shouldersImplant = 0; + thisSurgery.boobs = App.RA.makeTarget('==', 1200); + thisSurgery.holes = 0; break; case 3: - thisSurgery = { - lactation: 0, - cosmetic: 1, - faceShape: "cute", - lips: App.RA.makeTarget('==', 95), - hips: 0, - hipsImplant: 0, - butt: App.RA.makeTarget('==', 8), - accent: 0, - shoulders: 0, - shouldersImplant: 0, - boobs: App.RA.makeTarget('==', 10000), - holes: 2 - }; + thisSurgery.lactation = 0; + thisSurgery.cosmetic = 1; + thisSurgery.faceShape = "cute"; + thisSurgery.lips = App.RA.makeTarget('==', 95); + thisSurgery.hips = 0; + thisSurgery.hipsImplant = 0; + thisSurgery.butt = App.RA.makeTarget('==', 8); + thisSurgery.accent = 0; + thisSurgery.shoulders = 0; + thisSurgery.shouldersImplant = 0; + thisSurgery.boobs = App.RA.makeTarget('==', 10000); + thisSurgery.holes = 2; break; case 4: - thisSurgery = { - lactation: 1, - cosmetic: 1, - faceShape: "cute", - lips: App.RA.makeTarget('==', 10), - hips: 3, - hipsImplant: 0, - butt: App.RA.makeTarget('==', 0), - accent: 0, - shoulders: 0, - shouldersImplant: 0, - boobs: App.RA.makeTarget('==', 0), - holes: 0 - }; + thisSurgery.lactation = 1; + thisSurgery.cosmetic = 1; + thisSurgery.faceShape = "cute"; + thisSurgery.lips = App.RA.makeTarget('==', 10); + thisSurgery.hips = 3; + thisSurgery.hipsImplant = 0; + thisSurgery.butt = App.RA.makeTarget('==', 0); + thisSurgery.accent = 0; + thisSurgery.shoulders = 0; + thisSurgery.shouldersImplant = 0; + thisSurgery.boobs = App.RA.makeTarget('==', 0); + thisSurgery.holes = 0; break; default: thisSurgery = autoSurgerySelector( @@ -162,22 +154,63 @@ window.rulesAutosurgery = (function() { slave.health -= (V.PC.medicine >= 100) ? Math.round(healthCost / 2) : healthCost; } + /** + * + * @param {string} bodyPart + * @param {!App.RA.NumericTarget} target + */ + function bodyPartSizing(bodyPart, target) { + const shallShrink = App.RA.shallShrink(slave[`${bodyPart}Implant`], target); + let shallGrow = false; + let options; + let sorter; + if (shallShrink) { + if (target.val === 0) { + commitProcedure(`surgery to remove ${slave.possessive} ${bodyPart} implants`, slave => { + slave[bodyPart] -= slave[`${bodyPart}Implant`]; + slave[`${bodyPart}Implant`] = 0; + slave[`${bodyPart}ImplantType`] = 0; + }); + return; + } + options = {reduction: true, replace: true}; + sorter = (left, right) => -right.targetEffect / right.costs + left.targetEffect / left.costs; + } else if (App.RA.shallGrow(slave[`${bodyPart}Implant`], target)) { + shallGrow = true; + options = {augmentation: true, replace: true}; + sorter = (left, right) => right.targetEffect / right.costs - left.targetEffect / left.costs; + } + if (!shallShrink && !shallGrow) { return; } + + const surgeryOptions = App.Medicine.Surgery.sizingProcedures.bodyPart(bodyPart, slave, options) + .filter(surgery => surgery.action !== undefined) + .sort(sorter); + for (const so of surgeryOptions) { + if ((shallShrink && App.RA.shallShrink(slave[`${bodyPart}Implant`], target, so.targetEffect)) || + (shallGrow && App.RA.shallGrow(slave[`${bodyPart}Implant`], target, so.targetEffect))) { + surgeries.push(`surgery to ${so.description}`); + App.Medicine.Surgery.commit(so, slave); + break; + } + } + } + // NOTE: App.RA.shallShrink() and App.RA.shallGrow() return 'false' when target is 'null' // Hence they have to be first conditions in the '&&' chains to avoid type errors // (reading properties of the 'null' object) if (slave.health > 20 && surgeries.length < 3) { if (slave.eyes === -1 && thisSurgery.eyes === 1) { - commitProcedure(`surgery to correct ${slave.possessive} vision`, s => { s.eyes = 1 }); + commitProcedure(`surgery to correct ${slave.possessive} vision`, s => { s.eyes = 1; }); } else if (slave.eyes === 1 && thisSurgery.eyes === -1) { - commitProcedure(`surgery to blur ${slave.possessive} vision`, s => { s.eyes = -1 }); + commitProcedure(`surgery to blur ${slave.possessive} vision`, s => { s.eyes = -1; }); } else if (slave.hears === -1 && thisSurgery.hears === 0) { - commitProcedure(`surgery to correct ${slave.possessive} hearing`, s => { s.hears = 0 }); + commitProcedure(`surgery to correct ${slave.possessive} hearing`, s => { s.hears = 0; }); } else if (slave.hears === 0 && thisSurgery.hears === -1) { - commitProcedure(`surgery to muffle ${slave.possessive} hearing`, s => { s.hears = -1 }); + commitProcedure(`surgery to muffle ${slave.possessive} hearing`, s => { s.hears = -1; }); } else if (slave.smells === -1 && thisSurgery.smells === 0) { - commitProcedure(`surgery to correct ${slave.possessive} sense of smell`, s => { s.smells = 0 }); + commitProcedure(`surgery to correct ${slave.possessive} sense of smell`, s => { s.smells = 0; }); } else if (slave.smells === 0 && thisSurgery.smells === -1) { - commitProcedure(`surgery to muffle ${slave.possessive} sense of smell`, s => { s.smells = -1 }); + commitProcedure(`surgery to muffle ${slave.possessive} sense of smell`, s => { s.smells = -1; }); } else if (slave.tastes === -1 && thisSurgery.tastes === 0) { commitProcedure(`surgery to correct ${slave.possessive} sense of taste`, s => { s.tastes = 0; }); } else if (slave.tastes === 0 && thisSurgery.tastes === -1) { @@ -199,57 +232,12 @@ window.rulesAutosurgery = (function() { slave.boobShape = "perky"; } }); - } else if (App.RA.shallShrink(slave.boobsImplant, thisSurgery.boobs) && thisSurgery.boobs.val === 0) { - commitProcedure(`surgery to remove ${slave.possessive} boob implants`, slave => { - slave.boobs -= slave.boobsImplant; - slave.boobsImplant = 0; - slave.boobsImplantType = 0; - }); - } else if (App.RA.shallGrow(slave.boobs, thisSurgery.boobs, 400) && slave.boobs <= 600 && slave.lactation < 2) { - commitProcedure("bigger boobs", slave => { - slave.boobsImplant += 400; - slave.boobs += 400; - }); - } else if (App.RA.shallGrow(slave.boobs, thisSurgery.boobs, 200) && slave.boobs <= 600 && slave.lactation < 2) { - commitProcedure("modestly bigger boobs", slave => { - slave.boobsImplant += 200; - slave.boobs += 200; - }); - } else if (App.RA.shallGrow(slave.boobs, thisSurgery.boobs, 400) && slave.boobs <= 2000 && slave.lactation < 2) { - commitProcedure("bigger boobs", slave => { - slave.boobsImplant += 400; - slave.boobs += 400; - }); - } else if (App.RA.shallGrow(slave.boobs, thisSurgery.boobs) && slave.boobs <= 9000 && slave.lactation < 2) { - commitProcedure("bigger boobs", slave => { - slave.boobsImplant += 200; - slave.boobs += 200; - }); + } else if (thisSurgery.boobs) { + bodyPartSizing("boobs", thisSurgery.boobs); } } if (thisSurgery.butt !== null && slave.health > 20 && surgeries.length < 3) { - if (App.RA.shallShrink(slave.buttImplant, thisSurgery.butt) && thisSurgery.butt.val === 0) { - commitProcedure(`surgery to remove ${slave.possessive} butt implants`, slave => { - slave.butt -= slave.buttImplant; - slave.buttImplant = 0; - slave.buttImplantType = 0; - }); - } else if (App.RA.shallGrow(slave.butt, thisSurgery.butt) && slave.butt <= 3) { - commitProcedure("a bigger butt", slave => { - slave.buttImplant = 1; // FIXME: +=1? - slave.butt += 1; - }); - } else if (App.RA.shallGrow(slave.butt, thisSurgery.butt) && slave.butt <= 5) { - commitProcedure("a bigger butt", slave => { - slave.buttImplant = 1; // FIXME: +=1? - slave.butt += 1; - }); - } else if (App.RA.shallGrow(slave.butt, thisSurgery.butt) && slave.butt <= 8) { - commitProcedure("a bigger butt", slave => { - slave.buttImplant = 1; // FIXME: +=1? - slave.butt += 1; - }); - } + bodyPartSizing("butt", thisSurgery.butt); } if (slave.health > 20 && surgeries.length < 3) { if (slave.anus > 3 && thisSurgery.cosmetic > 0) { diff --git a/src/js/surgery.js b/src/js/surgery.js new file mode 100644 index 0000000000000000000000000000000000000000..f8c6c2d3b62df1581205c70d0019315cf874647c --- /dev/null +++ b/src/js/surgery.js @@ -0,0 +1,453 @@ + +App.Medicine.Surgery = {}; +/** + * Composes the Procedure object from its parts + * + * This function has the only purpose to ensure the result object has all required properties + * @param {string} typeId + * @param {string} label + * @param {number} effect + * @param {string} desc + * @param {slaveOperation} [action] + * @param {number} [costs] money costs + * @param {number} [hCosts] health costs + * @param {string} [surgeryType] + * @returns {App.Medicine.Surgery.Procedure} + */ +App.Medicine.Surgery.makeOption = function(typeId, label, effect, desc, action, costs, hCosts, surgeryType) { + return { + typeId: typeId, + label: label, + targetEffect: effect, + description: desc, + costs: costs, + healthCosts: hCosts, + action: action, + surgeryType: surgeryType + }; +}; + +/** + * Composes the procedure option with empty .action, i.e. a procedure that can't be applied + * @param {string} typeId + * @param {string} label + * @param {string} desc + * @returns {App.Medicine.Surgery.Procedure} + */ +App.Medicine.Surgery.makeImpossibleOption = function(typeId, label, desc) { + return this.makeOption(typeId, label, 0, desc); +}; + +/** + * Various constants for procedures + */ +App.Medicine.Keys = { + Surgery: { + Target: { + /** + * Type id's for breast-related procedures + */ + breast: { + installImplant: "breast.implant.install", + removeImplant: "breast.implant.remove", + fillUp: "breast.implant.fill", + drain: "breast.implant.drain", + changeImplant: "breast.implant.replace", + reduction: "breast.tissue.reduce", + }, + /** + * Type id's for butt-related procedures + */ + butt: { + installImplant: "butt.implant.install", + removeImplant: "butt.implant.remove", + fillUp: "butt.implant.fill", + drain: "butt.implant.drain", + changeImplant: "but.implant.replace", + reduction: "butt.tissue.reduce", + } + } + } +}; + +/** + * Commit procedure, executing its action and subtracting its costs + * @param {App.Medicine.Surgery.Procedure} surgery + * @param {App.Entity.SlaveState} slave + */ +App.Medicine.Surgery.commit = function(surgery, slave) { + const V = State.variables; + V.surgeryType = surgery.surgeryType; + surgery.action(slave); + cashX(forceNeg(surgery.costs), "slaveSurgery", slave); + slave.health -= (V.PC.medicine >= 100) ? Math.round(surgery.healthCosts / 2) : surgery.healthCosts; +}; + +/** + * Returns markup for a link to execute the given procedure + * @param {string} passage Passage to go after the surgery + * @param {App.Medicine.Surgery.Procedure} surgery + * @param {App.Entity.SlaveState} slave + * @returns {string} + */ +App.Medicine.Surgery.makeLink = function(passage, surgery, slave) { + if (surgery.action === undefined) { + return App.UI.disabledLink(surgery.label, [surgery.description]); + } + + function healthCosts() { + const hc = (State.variables.PC.medicine >= 100) ? Math.round(surgery.healthCosts / 2) : surgery.healthCosts; + if (hc > 30) { + return 'substantial'; + } else if (hc > 20) { + return 'significant'; + } else if (hc > 10) { + return 'moderate'; + } else if (hc > 5) { + return 'light'; + } + return 'insignificant'; + } + + return App.UI.link(surgery.label, App.Medicine.Surgery.commit, [surgery, slave], passage, + `${capFirstChar(surgery.description)}.\nSurgery costs: ${cashFormat(surgery.costs)}.\nProjected health damage: ${healthCosts()}.`); +}; + +/** + * Helpers for composing procedure descriptions + */ +App.Medicine.Surgery.ListHelpers = class { + /** + * @param {App.Entity.SlaveState} slave + * @param {string} bodyPart + * @param {Object.<string, string>} keys + * @param {App.Utils.Pronouns} pronouns + * @param {boolean} showCCs + */ + constructor(slave, bodyPart, keys, pronouns, showCCs) { + /** @private */ + this._slave = slave; + /** @private */ + this._bodyPart = bodyPart; + /** @private */ + this._keys = keys; + /** @private */ + this._pronouns = pronouns; + /** @private */ + this._V = State.variables; + this._showCCs = showCCs; + } + /** + * @param {string} name + * @param {number} implantType + * @param {number} size + * @returns {App.Medicine.Surgery.Procedure} + */ + installImplants(name, implantType, size) { + return App.Medicine.Surgery.makeOption(this._keys.installImplant, `${capFirstChar(name)} implants`, size, + `place ${name}${this._showCCs ? ` ${size}cc` : ''} implants into ${this._pronouns.his} ${this._bodyPart}`, + slave => { + slave[`${this._bodyPart}Implant`] = size; + slave[`${this._bodyPart}ImplantType`] = implantType; + slave[this._bodyPart] += size; + }, this._V.surgeryCost, 10, this._bodyPart + ); + } + + removeImplants() { + return App.Medicine.Surgery.makeOption(this._keys.removeImplant, "Remove implants", + -this._slave[`${this._bodyPart}Implant`], + `remove ${this._pronouns.his} ${this._bodyPart} implants`, + slave => { + slave[`${this._bodyPart}`] -= slave[`${this._bodyPart}Implant`]; + slave[`${this._bodyPart}Implant`] = 0; + slave[`${this._bodyPart}ImplantType`] = 0; + }, this._V.surgeryCost, 5, `${this._bodyPart}Loss` + ); + } + + /** + * @param {string} name + * @param {number} implantType + * @param {number} size + * @returns {App.Medicine.Surgery.Procedure} + */ + replaceImplants(name, implantType, size) { + return App.Medicine.Surgery.makeOption(this._keys.changeImplant, `${capFirstChar(name)} implants`, + size - this._slave.boobsImplant, + `replace ${this._pronouns.his} ${this._bodyPart} implants with ${name}${this._showCCs ? ` (${size}cc)` : ''} ones`, + slave => { + slave[this._bodyPart] += size - slave[`${this._bodyPart}Implant`]; + slave[`${this._bodyPart}Implant`] = size; + slave[`${this._bodyPart}ImplantType`] = implantType; + }, this._V.surgeryCost, 10, this._bodyPart + ); + } + + /** + * @param {number} volume + * @returns {App.Medicine.Surgery.Procedure} + */ + fillUp(volume) { + return App.Medicine.Surgery.makeOption(this._keys.fillUp, "Add inert filler", volume, + `add${this._showCCs ? ` ${volume}cc of` : 'some'} inert filler to each of ${this._pronouns.his} ${this._bodyPart} implants`, + slave => { + slave[`${this._bodyPart}Implant`] += volume; + slave[this._bodyPart] += volume; + }, + this._V.surgeryCost, 10, this._bodyPart + ); + } + + /** + * @param {number} volume + * @returns {App.Medicine.Surgery.Procedure} + */ + drain(volume) { + return App.Medicine.Surgery.makeOption(this._keys.drain, `Drain ${volume}cc`, -volume, + `drain${this._showCCs ? ` ${volume}cc of` : 'some'} inert filler from ${this._pronouns.his} ${this._bodyPart} implants`, + slave => { + slave[`${this._bodyPart}Implant`] -= volume; + slave[this._bodyPart] -= volume; + }, this._V.surgeryCost, 5, `${this._bodyPart}Loss` + ); + } + + /** + * @param {string} procedureName + * @param {number} sizeChange + * @returns {App.Medicine.Surgery.Procedure} + */ + reduce(procedureName, sizeChange) { + return App.Medicine.Surgery.makeOption(this._keys.reduction, + `${capFirstChar(procedureName)} ${this._bodyPart}`, -200, + `${procedureName} ${this._pronouns.his} ${this._bodyPart}`, + slave => { + slave[this._bodyPart] -= sizeChange; + }, this._V.surgeryCost, 5, `${this._bodyPart}Loss` + ); + } +}; + +/** + * Returns options to accept all possible surgeries + * @returns {App.Medicine.Surgery.SizingOptions} + */ +App.Medicine.Surgery.allSizingOptions = function() { + return { + augmentation: true, + reduction: true, + strings: true, + replace: true + }; +}; + +App.Medicine.Surgery.sizingProcedures = function() { + return { + bodyPart: bodyPart, + boobs: boobSizingProcedures, + butt: buttSizingProcedures + }; + + /** + * Returns list of available surgeries targeted at changing size of the given body part + * @param {string} bodyPart + * @param {App.Entity.SlaveState} slave + * @param {App.Medicine.Surgery.SizingOptions} [options] + * @returns {App.Medicine.Surgery.Procedure[]} + */ + function bodyPart(bodyPart, slave, options) { + switch (bodyPart) { + case "boob": + case "boobs": + case "breast": + case "breasts": + return boobSizingProcedures(slave, options); + case "ass": + case "booty": + case "butt": + return buttSizingProcedures(slave, options); + default: + throw `No sizing procedures for ${bodyPart}`; + } + } + + /** + * @param {App.Entity.SlaveState} slave + * @param {App.Medicine.Surgery.SizingOptions} [options] + * @returns {App.Medicine.Surgery.Procedure[]} + */ + function boobSizingProcedures(slave, options = {}) { + const V = State.variables; + const thisArcology = V.arcologies[0]; + const largeImplantsAvailable = thisArcology.FSTransformationFetishistResearch === 1; + const advancedFillableImplantsAvailable = V.ImplantProductionUpgrade === 1; + const pronouns = getPronouns(slave); + const {he, His} = pronouns; + + const types = App.Medicine.Keys.Surgery.Target.breast; // shortcuts + const helper = new App.Medicine.Surgery.ListHelpers(slave, "boobs", types, pronouns, V.showBoobCCs); + + let r = []; + if (options.augmentation) { + if (slave.boobs > 50000) { + r.push(App.Medicine.Surgery.makeImpossibleOption(types.fillUp, "Increase boobs", `<em>${His} breasts are as large as ${he} can physically support</em>`)); + } else if (slave.boobsImplant > 10000 && !largeImplantsAvailable && slave.boobsImplantType !== 1) { + r.push(App.Medicine.Surgery.makeImpossibleOption(types.fillUp, "Increase boobs", `<em>${His} implants are filled to capacity</em>`)); + } else if (slave.indentureRestrictions >= 2) { + r.push(App.Medicine.Surgery.makeImpossibleOption(types.installImplant, "Change boob size", `<em>${His} indenture forbids elective surgery</em>`)); + } else if (slave.breastMesh === 1) { + r.push(App.Medicine.Surgery.makeImpossibleOption(types.installImplant, "Put implants", `<em>${His} supportive mesh implant blocks implantation</em>`)); + } else if (slave.boobsImplant === 0) { + if (options.strings) { + r.push(helper.installImplants("string", 1, 400)); + } + if (V.surgeryUpgrade === 1) { + r.push(helper.installImplants("large", 1, 600)); + } + r.push(helper.installImplants("standard", 1, 400)); + r.push(helper.installImplants("small", 1, 200)); + } else if (slave.boobsImplant > 10000 && slave.boobsImplantType !== 1 && advancedFillableImplantsAvailable) { + r.push(helper.fillUp(1000)); + } else if (slave.boobsImplant > 9800 && slave.boobsImplantType !== 1 && advancedFillableImplantsAvailable) { + r.push(helper.replaceImplants("hyper fillable", 0, 11000)); + } else if (slave.boobsImplant > 2000 && slave.boobsImplantType !== 1) { + r.push(helper.fillUp(400)); + } else if (slave.boobsImplant > 1800 && slave.boobsImplantType !== 1) { + r.push(App.Medicine.Surgery.makeImpossibleOption(types.fillUp, "Add inert filler", `<em>${His} implants are filled to capacity</em>`)); + + const advancedFillable = helper.replaceImplants("advanced fillable", 0, 2200); + if (!advancedFillableImplantsAvailable) { + advancedFillable.costs += 10000; + advancedFillable.label += " (special order)"; + advancedFillable.description += " (special order)"; + } + r.push(advancedFillable); + } else if (slave.boobsImplant > 600 && slave.boobsImplantType !== 1) { + r.push(helper.fillUp(200)); + } else if (slave.boobsImplant > 400 && slave.boobsImplantType !== 1) { + r.push(helper.replaceImplants("fillable", 0, 800)); + } else if (slave.boobsImplant > 200 && slave.boobsImplantType !== 1) { + r.push(helper.replaceImplants("large", 0, 600)); + } else if (slave.boobsImplant > 0 && slave.boobsImplantType !== 1) { + r.push(helper.replaceImplants("standard", 0, 400)); + r.push(helper.replaceImplants("large", 0, 600)); + } + } + + if (options.reduction && (slave.boobs > 300 || slave.boobsImplant > 0)) { + if (slave.boobsImplant > 0) { + if (slave.boobsImplantType === 1 && slave.boobsImplant > 400) { + if (slave.boobsImplant > 8000) { + r.push(helper.drain(1000)); + } else if (slave.boobsImplant > 5000) { + r.push(helper.drain(750)); + } else if (slave.boobsImplant > 2000) { + r.push(helper.drain(500)); + } else if (slave.boobsImplant > 1000) { + r.push(helper.drain(250)); + } else if (slave.boobsImplant > 500) { + r.push(helper.drain(100)); + } + } + r.push(helper.removeImplants()); + } + if ((slave.boobs > 300) && (slave.boobsImplant === 0) && slave.indentureRestrictions < 2) { + r.push(helper.reduce("reduce", 200)); + if (slave.boobs < 675) { + r.push(helper.reduce("slightly reduce", 25)); + } + } + if ((slave.boobsImplant === 0) && slave.indentureRestrictions < 2 && (slave.breedingMark !== 1 || V.propOutcome !== 1)) { + if (slave.boobs >= 7000) { + r.push(App.Medicine.Surgery.makeOption(types.reduction, "Mastectomy", 300 - slave.boobs, + "perform mastectomy", + slave => { + slave.boobs = 300; + }, + V.surgeryCost, 30, "mastectomy+" + )); + } else if (slave.boobs >= 2000) { + r.push(App.Medicine.Surgery.makeOption(types.reduction, "Mastectomy", 300 - slave.boobs, + "perform mastectomy", + slave => { + slave.boobs = 300; + }, + V.surgeryCost, 30, "mastectomy" + )); + } + } + } + return r; + } + + /** + * @param {App.Entity.SlaveState} slave + * @param {App.Medicine.Surgery.SizingOptions} [options] + * @returns {App.Medicine.Surgery.Procedure[]} + */ + function buttSizingProcedures(slave, options = {}) { + const V = State.variables; + const thisArcology = V.arcologies[0]; + const largeImplantsAvailable = thisArcology.FSTransformationFetishistResearch === 1; + const advancedFillableImplantsAvailable = V.ImplantProductionUpgrade === 1; + const pronouns = getPronouns(slave); + const {he, His} = pronouns; + + const types = App.Medicine.Keys.Surgery.Target.butt; // shortcuts + const helper = new App.Medicine.Surgery.ListHelpers(slave, "butt", types, pronouns, false); + + let r = []; + + if (options.augmentation) { + if (slave.indentureRestrictions >= 2) { + r.push(App.Medicine.Surgery.makeImpossibleOption(types.installImplant, "Change butt size", `<em>${His} indenture forbids elective surgery</em>`)); + } else if (slave.butt > 19) { + r.push(App.Medicine.Surgery.makeImpossibleOption(types.fillUp, "Increase butt", `<em>${His} butt is as large as it can possibly get</em>`)); + } else if (slave.butt > 7 && !largeImplantsAvailable && thisArcology.FSAssetExpansionist === "unset" && slave.buttImplantType !== 1) { + r.push(App.Medicine.Surgery.makeImpossibleOption(types.installImplant, "Increase butt", `<em>${His} butt is as large as $${he} can physically support</em>`)); + } else if (slave.buttImplant > 7 && !largeImplantsAvailable && slave.buttImplantType !== 1) { + r.push(App.Medicine.Surgery.makeImpossibleOption(types.installImplant, "Increase butt", `<em>${His} butt implants are filled to capacity</em>`)); + } else if (slave.buttImplant === 0) { + r.push(helper.installImplants("standard", 0, 1)); + if (options.strings) { + r.push(helper.installImplants("string", 1, 1)); + } + } else if (slave.buttImplant === 1 && slave.buttImplantType !== 1) { + r.push(helper.replaceImplants("bigger", 0, 2)); + } else if (slave.buttImplant === 2 && slave.buttImplantType !== 1) { + r.push(helper.replaceImplants("fillable", 0, 3)); + } else if (slave.buttImplant === 4 && slave.buttImplantType !== 1) { + r.push(App.Medicine.Surgery.makeImpossibleOption(types.fillUp, "Increase size", `<em>${His} implants are filled to capacity</em>`)); + const advancedFillable = helper.replaceImplants("advanced fillable", 0, 5); + if (!advancedFillableImplantsAvailable) { + advancedFillable.costs += 10000; + advancedFillable.label += " (special order)"; + advancedFillable.description += " (special order)"; + } + r.push(advancedFillable); + } else if (slave.buttImplant === 8 && slave.buttImplantType !== 1 && advancedFillableImplantsAvailable) { + r.push(helper.replaceImplants("hyper fillable", 0, 9)); + } else if (slave.buttImplant > 2 && slave.buttImplantType !== 1) { + r.push(helper.fillUp(1)); + } + } + + if (options.reduction) { + if (slave.buttImplant > 0) { + if (slave.indentureRestrictions < 2) { + if (slave.buttImplantType === 1 && slave.buttImplant > 1) { + r.push(helper.drain(1)); + } + r.push(helper.removeImplants()); + } + } + if ((slave.butt > 1) && (slave.buttImplant === 0)) { + if (slave.indentureRestrictions < 2) { + r.push(helper.reduce("reduce", 1)); + } + } + } + return r; + } +}(); diff --git a/src/js/utilJS.js b/src/js/utilJS.js index 5f66ee8b4a470c3bb8dbb79061fbdc777904dfa8..5962f8d7a24ea7cc9c35423bc77be8ff779d825f 100644 --- a/src/js/utilJS.js +++ b/src/js/utilJS.js @@ -2347,6 +2347,7 @@ App.UI.link = function() { // reset all handlers for each passage $(document).on(':passageinit', function() { State.temporary.linkHandlers = {}; + counter = 0; }); return makeLink; diff --git a/src/uncategorized/remoteSurgery.tw b/src/uncategorized/remoteSurgery.tw index 2a0d5d99598bcfbb2af36145a19f0b466752d175..c8da587b6fcc043ab45f5ef8f07026e1b1bdf99a 100644 --- a/src/uncategorized/remoteSurgery.tw +++ b/src/uncategorized/remoteSurgery.tw @@ -544,78 +544,10 @@ $He has <<else>> no implants. <</if>> -<<if $activeSlave.boobs > 50000>> - //$His breasts are as large as $he can physically support// -<<elseif $activeSlave.boobsImplant > 10000 && $arcologies[0].FSTransformationFetishistResearch != 1 && $activeSlave.boobsImplantType != 1>> - //$His implants are filled to capacity// -<<elseif $activeSlave.indentureRestrictions >= 2>> - //$His indenture forbids elective surgery// -<<elseif $activeSlave.breastMesh == 1>> - //$His supportive mesh implant blocks implantation// -<<elseif $activeSlave.boobsImplant == 0>> - [[String implants|Surgery Degradation][$activeSlave.boobsImplant = 400, $activeSlave.boobsImplantType = 1,$activeSlave.boobs += 400,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] | - <<if $surgeryUpgrade == 1>>[[Large implants|Surgery Degradation][$activeSlave.boobsImplant = 600,$activeSlave.boobs += 600,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] |<</if>> - [[Standard implants|Surgery Degradation][$activeSlave.boobsImplant = 400,$activeSlave.boobs += 400,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] | - [[Small implants|Surgery Degradation][$activeSlave.boobsImplant = 200,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] -<<elseif $activeSlave.boobsImplant > 10000 && $activeSlave.boobsImplantType != 1 && $ImplantProductionUpgrade == 1>> - [[Add inert filler|Surgery Degradation][$activeSlave.boobsImplant += 1000,$activeSlave.boobs += 1000,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] -<<elseif $activeSlave.boobsImplant > 9800 && $activeSlave.boobsImplantType != 1 && $ImplantProductionUpgrade == 1>> - [[Hyper fillable implants|Surgery Degradation][$activeSlave.boobsImplant = 11000,$activeSlave.boobs += 800,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] -<<elseif $activeSlave.boobsImplant > 2000 && $activeSlave.boobsImplantType != 1>> - [[Add inert filler|Surgery Degradation][$activeSlave.boobsImplant += 400,$activeSlave.boobs += 400,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] -<<elseif $activeSlave.boobsImplant > 1800 && $activeSlave.boobsImplantType != 1>> - $His implants are filled to capacity. - <<if $ImplantProductionUpgrade == 1>> - [[Advanced fillable implants|Surgery Degradation][$activeSlave.boobsImplant = 2200,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] - <<else>> - [[Special order advanced fillable implants|Surgery Degradation][$activeSlave.boobsImplant = 2200,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave)+10000, $activeSlave.health -= 10,$surgeryType = "boobs"]] //Will cost an additional <<= cashFormat(10000)>>// - <</if>> -<<elseif $activeSlave.boobsImplant > 600 && $activeSlave.boobsImplantType != 1>> - [[Add inert filler|Surgery Degradation][$activeSlave.boobsImplant += 200,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] -<<elseif $activeSlave.boobsImplant > 400 && $activeSlave.boobsImplantType != 1>> - [[Fillable implants|Surgery Degradation][$activeSlave.boobsImplant = 800,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] -<<elseif $activeSlave.boobsImplant > 200 && $activeSlave.boobsImplantType != 1>> - [[Large implants|Surgery Degradation][$activeSlave.boobsImplant = 600,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] -<<elseif $activeSlave.boobsImplant > 0 && $activeSlave.boobsImplantType != 1>> - [[Standard implants|Surgery Degradation][$activeSlave.boobsImplant = 400,$activeSlave.boobs += 200,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] | [[Large implants|Surgery Degradation][$activeSlave.boobsImplant = 600,$activeSlave.boobs += 400,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "boobs"]] -<</if>> -<<if $activeSlave.boobsImplant != 0>> - <<if $activeSlave.boobsImplantType == 1 && $activeSlave.boobsImplant > 400>> - <<if $activeSlave.boobsImplant > 8000>> - | [[Drain 1000cc|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-1000),$activeSlave.boobsImplant = ($activeSlave.boobsImplant-1000), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]] - <<elseif $activeSlave.boobsImplant > 5000>> - | [[Drain 750cc|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-750),$activeSlave.boobsImplant = ($activeSlave.boobsImplant-750), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]] - <<elseif $activeSlave.boobsImplant > 2000>> - | [[Drain 500cc|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-500),$activeSlave.boobsImplant = ($activeSlave.boobsImplant-500), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]] - <<elseif $activeSlave.boobsImplant > 1000>> - | [[Drain 250cc|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-250),$activeSlave.boobsImplant = ($activeSlave.boobsImplant-250), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]] - <<elseif $activeSlave.boobsImplant > 500>> - | [[Drain 100cc|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-100),$activeSlave.boobsImplant = ($activeSlave.boobsImplant-100), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]] - <</if>> - <</if>> - | [[Remove breast implants|Surgery Degradation][$activeSlave.boobs = ($activeSlave.boobs-$activeSlave.boobsImplant),$activeSlave.boobsImplant = 0,$activeSlave.boobsImplantType = 0, $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]] -<</if>> -<<if ($activeSlave.boobs > 300) && ($activeSlave.boobsImplant == 0)>> - <<if $activeSlave.indentureRestrictions >= 2>> - <<else>> - | [[Reduce breasts|Surgery Degradation][$activeSlave.boobs -= 200, $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]] - <<if $activeSlave.boobs < 675>> - | [[Slightly reduce breasts|Surgery Degradation][$activeSlave.boobs -= 25, $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "boobsLoss"]] - <</if>> - <</if>> -<</if>> -<<if ($activeSlave.boobs >= 7000) && ($activeSlave.boobsImplant == 0)>> - <<if $activeSlave.indentureRestrictions >= 2 || ($activeSlave.breedingMark == 1 && $propOutcome == 1)>> - <<else>> - | [[Mastectomy|Surgery Degradation][$activeSlave.boobs = 300, $activeSlave.breastMesh = 0, $activeSlave.health -= 30,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "mastectomy+"]] - <</if>> -<<elseif ($activeSlave.boobs >= 2000) && ($activeSlave.boobsImplant == 0)>> - <<if $activeSlave.indentureRestrictions >= 2 || ($activeSlave.breedingMark == 1 && $propOutcome == 1)>> - <<else>> - | [[Mastectomy|Surgery Degradation][$activeSlave.boobs = 300, $activeSlave.breastMesh = 0, $activeSlave.health -= 30,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "mastectomy"]] - <</if>> -<</if>> +<<set _surgeries = App.Medicine.Surgery.sizingProcedures.boobs($activeSlave, App.Medicine.Surgery.allSizingOptions())>> +<<set _surgeryLinks = _surgeries.map(s => App.Medicine.Surgery.makeLink("Surgery Degradation", s, $activeSlave))>> +<<= _surgeryLinks.join(' | ')>> <br> <<if $activeSlave.boobsImplant != 0>> @@ -959,46 +891,9 @@ $He's got a <</if>> <</if>> -<<if $activeSlave.indentureRestrictions >= 2>> - //$His indenture forbids elective surgery// -<<elseif $activeSlave.butt > 19>> - //$His butt is as large as it can possibly get// -<<elseif $activeSlave.butt > 7 && $arcologies[0].FSTransformationFetishistResearch != 1 && $arcologies[0].FSAssetExpansionist == "unset" && $activeSlave.buttImplantType != 1>> - //$His butt is as large as $he can physically support// -<<elseif $activeSlave.buttImplant > 7 && $arcologies[0].FSTransformationFetishistResearch != 1 && $activeSlave.buttImplantType != 1>> - //$His butt implants are filled to capacity// -<<elseif $activeSlave.buttImplant == 0>> - [[Implants|Surgery Degradation][$activeSlave.buttImplant = 1,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]] - | [[String implants|Surgery Degradation][$activeSlave.buttImplant = 1,$activeSlave.butt += 1,$activeSlave.buttImplantType = 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]] -<<elseif $activeSlave.buttImplant == 1 && $activeSlave.buttImplantType != 1>> - [[Bigger implants|Surgery Degradation][$activeSlave.buttImplant = 2,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]] -<<elseif $activeSlave.buttImplant == 2 && $activeSlave.buttImplantType != 1>> - [[Fillable implants|Surgery Degradation][$activeSlave.buttImplant = 3,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]] -<<elseif $activeSlave.buttImplant == 4 && $activeSlave.buttImplantType != 1>> - $His implants are filled to capacity. - <<if $ImplantProductionUpgrade == 1>> - [[Advanced fillable implants|Surgery Degradation][$activeSlave.buttImplant = 5,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]] - <<else>> - [[Special order advanced fillable implants|Surgery Degradation][$activeSlave.buttImplant = 5,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave)+10000, $activeSlave.health -= 10,$surgeryType = "butt"]] //Will cost an additional <<= cashFormat(10000)>>// - <</if>> -<<elseif $activeSlave.buttImplant == 8 && $activeSlave.buttImplantType != 1 && $ImplantProductionUpgrade == 1>> - [[Hyper fillable implants|Surgery Degradation][$activeSlave.buttImplant = 9,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]] -<<elseif $activeSlave.buttImplant > 2 && $activeSlave.buttImplantType != 1>> - [[Add inert filler|Surgery Degradation][$activeSlave.buttImplant += 1,$activeSlave.butt += 1,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $activeSlave.health -= 10,$surgeryType = "butt"]] -<</if>> -<<if $activeSlave.buttImplant != 0>> - <<if $activeSlave.indentureRestrictions < 2>> - <<if $activeSlave.buttImplantType == 1 && $activeSlave.buttImplant > 1>> - | [[Drain implants|Surgery Degradation][$activeSlave.butt = ($activeSlave.butt-1),$activeSlave.buttImplant = ($activeSlave.buttImplant-1), $activeSlave.health -= 5,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "buttLoss"]] - <</if>> - | [[Remove implants|Surgery Degradation][$activeSlave.butt = ($activeSlave.butt-$activeSlave.buttImplant),$activeSlave.buttImplant = 0, $activeSlave.health -= 10,$activeSlave.buttImplantType = 0,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "buttLoss"]] - <</if>> -<</if>> -<<if ($activeSlave.butt > 1) && ($activeSlave.buttImplant == 0)>> - <<if $activeSlave.indentureRestrictions < 2>> - | [[Reduce ass|Surgery Degradation][$activeSlave.butt -= 1, $activeSlave.health -= 10,cashX(forceNeg($surgeryCost), "slaveSurgery", $activeSlave), $surgeryType = "buttLoss"]] - <</if>> -<</if>> +<<set _surgeries = App.Medicine.Surgery.sizingProcedures.butt($activeSlave, App.Medicine.Surgery.allSizingOptions())>> +<<set _surgeryLinks = _surgeries.map(s => App.Medicine.Surgery.makeLink("Surgery Degradation", s, $activeSlave))>> +<<= _surgeryLinks.join(' | ')>> <br><br> Work on $his sex: