diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js index 45bf1590287bfb643e7f394011cf4953e99332bc..663e7a5580ca33931207ba861195d863492ac799 100644 --- a/js/003-data/gameVariableData.js +++ b/js/003-data/gameVariableData.js @@ -1247,7 +1247,8 @@ App.Data.resetOnNGPlus = { animalOvaries: 0, dinnerParty: 0, reportMissingClothing: 0, - raGrowthExpr: 0 + raGrowthExpr: 0, + sexOverhaul: 0, }, NaNArray: [], diff --git a/src/002-config/fc-version.js b/src/002-config/fc-version.js index a828794ca51c7b0d36c79a75294271f8347c7c4d..83c909c9ff99161768a05ed8c2bee3b46c546ba0 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.8", commitHash: null, - release: 1135 // When getting close to 2000, please remove the check located within the onLoad() function defined at line five of src/js/eventHandlers.js. + release: 1136 // 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/data/backwardsCompatibility/backwardsCompatibility.js b/src/data/backwardsCompatibility/backwardsCompatibility.js index 2656ee346d81b4379813914a0587ac62db25ff5d..6c33dc2bad1a0f1b4388e0dba9409b4b087bb80e 100644 --- a/src/data/backwardsCompatibility/backwardsCompatibility.js +++ b/src/data/backwardsCompatibility/backwardsCompatibility.js @@ -1258,6 +1258,7 @@ App.Update.globalVariables = function(node) { V.experimental.raGrowthExpr = V.experimental.raGrowthExpr || 0; V.experimental.reportMissingClothing = V.experimental.reportMissingClothing || 0; + V.experimental.sexOverhaul = V.experimental.sexOverhaul || 0; // Budget V.showAllEntries.costsBudget = V.showAllEntries.costsBudget || 0; diff --git a/src/gui/options/options.js b/src/gui/options/options.js index b22f7a2f99ed286f0e4596f3b71efe813df9b946..92f3a9677caed2dcf23668f715f5aade90e63ac0 100644 --- a/src/gui/options/options.js +++ b/src/gui/options/options.js @@ -775,6 +775,10 @@ App.UI.optionsPassage = function() { options.addOption("New event", "tempEventToggle") .addValue("Enabled", 1).on().addValue("Disabled", 0).off(); + options.addOption("Sex overhaul", "sexOverhaul", V.experimental) + .addValue("Enabled", 1).on().addValue("Disabled", 0).off() + .addComment("This will enable a new way to interact with slaves. Currently working but missing flavor text."); + el.append(options.render()); return el; } @@ -1123,7 +1127,7 @@ App.UI.artOptions = function() { options.addOption("Clothing erection bulges are", "showClothingErection") .addValue("Enabled", true).on().addValue("Disabled", false).off(); } else if (V.imageChoice === 4) { - options.addComment(`<a href='https://mega.nz/folder/Sgp0lQbY#L1iG-jMQUeztUFuFqj-ryw' target='_blank'> Download the WebGL art assets</a> and place the 'webgl' folder into the resources/ folder where this HTML file is. + options.addComment(`<a href='https://mega.nz/folder/Sgp0lQbY#L1iG-jMQUeztUFuFqj-ryw' target='_blank'> Download the WebGL art assets</a> and place the 'webgl' folder into the resources/ folder where this HTML file is. Then <b>refresh</b> the page. Create the resources folder if it does not exist. <span class="warning">(Android/MacOS not supported)</span>`); diff --git a/src/interaction/siWork.js b/src/interaction/siWork.js index a46c141d3310b34ef262059c4c51f40823fc0bab..ebe6d096fde62e8269f57f18da8bb8087dc91923 100644 --- a/src/interaction/siWork.js +++ b/src/interaction/siWork.js @@ -737,6 +737,11 @@ App.UI.SlaveInteract.work = function(slave, refresh) { } el.append(`Use ${him}: `); el.appendChild(generateRows(sexOptions)); + + if (V.experimental.sexOverhaul) { + el.appendChild(App.UI.SlaveInteract.useSlave(slave)); + } + if (!jQuery.isEmptyObject(fillFaceOptions)) { let fill = document.createElement('div'); fill.appendChild(document.createTextNode(` Fill ${his} mouth with: `)); diff --git a/src/interaction/useSlave/useSlave.css b/src/interaction/useSlave/useSlave.css new file mode 100644 index 0000000000000000000000000000000000000000..4094355ce4097b12e958592472870c98f5f1248e --- /dev/null +++ b/src/interaction/useSlave/useSlave.css @@ -0,0 +1,5 @@ +#use-slave-container { + overflow: scroll; + max-height: 16em; + margin: 1em 0; +} diff --git a/src/interaction/useSlave/useSlave.js b/src/interaction/useSlave/useSlave.js new file mode 100644 index 0000000000000000000000000000000000000000..bca63469cabbbcd2e0a4e7110ce0c0002e2c0a60 --- /dev/null +++ b/src/interaction/useSlave/useSlave.js @@ -0,0 +1,734 @@ +/** + * @typedef {Object} UseSlave.Option + * + * @property {string} link The link text. + * @property {string} desc The text that appears when the option is selected. + * @property {string} tooltip The link tooltip. + * @property {() => boolean} prereq Any prerequisites required for the option to appear. + * @property {() => void} effect Any effects the option has. + */ + +/** + * Creates a new sex scene. + * @param {App.Entity.SlaveState} slave + * @returns {HTMLDivElement} + */ +App.UI.SlaveInteract.useSlave = function(slave) { + /** A class containing the different temporary variables and states for each participant. */ + class CharacterState { + constructor() { + /** @type {number} The character's lust. Orgasm occurs at 100. */ + this.lust = 0; + /** @type {Position} Whether the character is standing, kneeling, or laying down. */ + this.position = null; + /** @type {boolean} Whether the character is pressed up close to the other actor. */ + this.close = false; + /** Properties relating to the character's clothing. */ + this.clothing = { + /** Properties relating to the character's clothing top. */ + top: { + /** @type {boolean} Whether the top is pulled up. */ + pulledUp: false, + /** @type {boolean} Whether the top is off. */ + isOff: false, + }, + /** Properties relating to the character's clothing bottom. */ + bottom: { + /** + * @type {boolean} + * Whether the bottom is pulled down. + * + * If the clothing is a dress, whether the bottom is pulled up over the character's waist. */ + pulledDown: false, + /** @type {boolean} Whether the bottom is off. */ + isOff: false, + }, + /** @type {boolean} Whether the character is wearing a bra. */ + bra: true, + /** @type {boolean} Whether the character is wearing underwear. */ + underwear: true, + /** @type {boolean} Whether the character is wearing a strapon. */ + strapon: false, + }; + } + + /** @param {Clone} actor The actor to assign the state to. */ + assign(actor) { + actor.state = this; + + return this; + } + + /** @type {boolean} Whether the character is standing up. */ + get isStanding() { + return this.position === Position.STANDING; + } + + /** @type {boolean} Whether the character is kneeling. */ + get isKneeling() { + return this.position === Position.KNEELING; + } + + /** @type {boolean} Whether the character is laying down. */ + get isLaying() { + return this.position === Position.LAYING; + } + + /** @type {boolean} Whether the character is completely naked. */ + get isNaked() { + return this.clothing.top.isOff + && this.clothing.bottom.isOff + && !this.clothing.bra + && !this.clothing.underwear; + } + + /** @type {boolean} Whether the character's chest is accessible. */ + get topFree() { + return this.clothing.top.isOff || this.clothing.top.pulledUp; + } + + /** @type {boolean} Whether the character's crotch is accessible. */ + get bottomFree() { + return this.clothing.bottom.isOff || this.clothing.bottom.pulledDown; + } + } + + /** + * A class for creating a temporary clone of the slave. + * Not to be confused with SlaveState's `.clone` property. + */ + class Clone extends App.Entity.SlaveState { + /** @param {App.Entity.SlaveState} slave The slave to clone. */ + constructor(slave) { + super(); + + this.slave = _.cloneDeep(slave); + /** @type {CharacterState} */ + this.state = null; + } + + /** @param {CharacterState} state The state to assign to the clone. */ + assign(state) { + this.state = state; + + return this; + } + + /** @returns {App.Entity.SlaveState} */ + getSlave() { + return this.slave; + } + } + + // Declarations + + const playerState = new CharacterState(); + const slaveState = new CharacterState(); + + const PC = V.PC; + const tempSlave = new Clone(slave) + .assign(slaveState) + .getSlave(); + + const refreshArt = () => App.Events.refreshEventArt(tempSlave); + + const {He, he, him, his, hers} = getPronouns(tempSlave); + + /** @enum {string} */ + const Fetish = { + NONE: "none", + MINDBROKEN: "mindbroken", + SUBMISSIVE: "submissive", + CUMSLUT: "cumslut", + HUMILIATION: "humiliation", + BUTTSLUT: "buttslut", + BOOBS: "boobs", + SADIST: "sadist", + MASOCHIST: "masochist", + DOM: "dom", + PREGNANCY: "pregnancy", + }; + /** @enum {boolean} */ + const Position = { + STANDING: true, + KNEELING: false, + LAYING: false, + }; + /** @enum {string} */ + const none = "none"; + + let clothes = tempSlave.clothes; + let introShown = false; + + const div = document.createElement("div"); + + const face = App.UI.SlaveInteract.useSlave.faceText; + const faceOptions = [ + { + link: `Kiss ${him}`, + desc: face.regularKiss(tempSlave), + tooltip: `Press your lips to ${hers} and kiss ${him}.`, + prereq: () => tempSlave.mouthAccessory === none, + effect: () => { + playerState.lust++; + slaveState.lust++; + } + }, + { + link: `Kiss ${him} passionately`, + desc: face.passionateKiss(tempSlave), + tooltip: `Press ${his} body to yours and kiss ${him}.`, + prereq: () => tempSlave.mouthAccessory === none, + effect: () => { + playerState.lust++; + slaveState.lust++; + } + }, + { + link: `Kiss ${him} intimately`, + desc: face.intimateKiss(tempSlave), + tooltip: `Share a romantic kiss.`, + prereq: () => tempSlave.mouthAccessory === none, + effect: () => { + playerState.lust++; + slaveState.lust++; + } + }, + { + link: `Have ${him} go down on you`, + desc: face.slaveGivesOral(tempSlave), + tooltip: `Have ${him} give you oral.`, + prereq: () => (tempSlave.mouthAccessory === none || tempSlave.mouthAccessory === "ring gag") + && !playerState.isKneeling + && !slaveState.isKneeling, + effect: () => { + playerState.lust++; + slaveState.lust++; + slaveState.position = Position.KNEELING; + } + }, + { + link: `Go down on ${him}`, + desc: face.playerGivesOral(tempSlave), + tooltip: `Give ${him} oral.`, + prereq: () => clothes === "no clothing" && !playerState.isKneeling && !slaveState.isKneeling, + effect: () => { + playerState.lust++; + slaveState.lust++; + playerState.position = Position.KNEELING; + } + }, + ]; + + const chest = App.UI.SlaveInteract.useSlave.chestText; + const chestOptions = [ + { + link: `Grope ${his} chest`, + desc: chest.grope(tempSlave), + tooltip: tempSlave.boobs >= 300 ? `Play with ${his} tits a bit.` : `Stroke ${his} chest a bit.`, + prereq: () => true, + effect: () => { + playerState.lust += 2; + slaveState.lust += tempSlave.fetish === Fetish.BOOBS ? 7 : 4; + } + }, + ]; + + const crotch = App.UI.SlaveInteract.useSlave.crotchText; + const crotchOptions = [ + { + link: `Grope ${his} pussy`, + desc: crotch.gropePussy(tempSlave), + tooltip: `Fondle and play with ${his} crotch a bit.`, + prereq: () => tempSlave.vagina > -1, + effect: () => { + playerState.lust++; + slaveState.lust++; + } + }, + { + link: `Grope ${his} ass`, + desc: crotch.gropeAss(tempSlave), + tooltip: `Grab ${his} ass and give it a good fondle.`, + prereq: () => true, + effect: () => { + playerState.lust++; + slaveState.lust++; + } + }, + { + link: `Finger ${his} pussy`, + desc: crotch.fingerPussy(tempSlave), + tooltip: `Play with ${his} clit a little, maybe slide a finger in there. Go on, you know you want to.`, + prereq: () => tempSlave.vagina > -1 && (slaveState.bottomFree || clothes.includes("dress")) && !tempSlave.chastityVagina, + effect: () => { + playerState.lust += 2; + slaveState.lust += 5; + } + }, + { + link: `Finger ${his} asshole`, + desc: crotch.fingerAnus(tempSlave), + tooltip: `Play with ${his} backdoor a little. Go on, you know you want to.`, + prereq: () => slaveState.bottomFree || clothes.includes("dress") && !tempSlave.chastityAnus, + effect: () => { + playerState.lust += 2; + slaveState.lust += tempSlave.fetish === Fetish.BUTTSLUT ? 7 : 4; + } + }, + { + link: `Fuck ${his} pussy`, + desc: crotch.fuckPussy(tempSlave), + tooltip: `Push your ${PC.dick ? `dick` : `strapon`} into ${his} pussy.`, + prereq: () => tempSlave.vagina > -1 + && slaveState.bottomFree + && !slaveState.clothing.underwear + && !tempSlave.chastityVagina + && playerState.lust > 5, + effect: () => { + playerState.lust += 8; + slaveState.lust += 8; + } + }, + { + link: `Fuck ${his} asshole`, + desc: crotch.fuckAnus(tempSlave), + tooltip: `Push your ${PC.dick ? `dick` : `strapon`} into ${his} asshole.`, + prereq: () => slaveState.bottomFree + && !slaveState.clothing.underwear + && !tempSlave.chastityAnus + && playerState.lust > 5, + effect: () => { + playerState.lust += 8; + slaveState.lust += tempSlave.fetish === Fetish.BUTTSLUT ? 8 : 5; + } + }, + { + link: `Start a sixty-nine`, + desc: crotch.sixtyNine(tempSlave), + tooltip: `Show each other some mutual affection.`, + prereq: () => slaveState.bottomFree && playerState.bottomFree, + effect: () => { + playerState.lust += 10; + slaveState.lust += 10; + } + } + ]; + + const general = App.UI.SlaveInteract.useSlave.generalText; + const generalOptions = [ + { + link: `Have ${him} dance for you`, + desc: general.dance(tempSlave), + tooltip: `Make ${him} give you a sensual dance.`, + prereq: () => !slaveState.isKneeling && !slaveState.isLaying, + effect: () => { + playerState.lust += 4; + slaveState.lust += 3; + } + }, + { + link: `Have ${him} perform a striptease for you`, + desc: general.striptease(tempSlave), + tooltip: `Make ${him} strip for you.`, + prereq: () => !slaveState.isKneeling && !slaveState.isLaying && clothes !== "no clothing", + effect: () => { + clothes = "no clothing"; + playerState.lust += 5; + slaveState.lust += 6; + } + }, + { + link: `Push ${him} down`, + desc: general.pushDown(tempSlave), + tooltip: `Have ${him} go down on you.`, + prereq: () => !slaveState.isKneeling, + effect: () => { + slaveState.position = Position.KNEELING; + } + }, + { + link: `Pull ${him} up`, + desc: general.pullUp(tempSlave), + tooltip: `Have ${him} stop going down on you.`, + prereq: () => slaveState.isKneeling, + effect: () => { + slaveState.position = Position.STANDING; + } + }, + { + link: `Pull ${him} in close`, + desc: general.pullClose(tempSlave), + tooltip: `Pull ${his} body in close to yours.`, + prereq: () => !slaveState.close, + effect: () => { + slaveState.close = true; + } + }, + { + link: `Push ${him} away`, + desc: general.pushAway(tempSlave), + tooltip: `Put some distance between you two.`, + prereq: () => slaveState.close, + effect: () => { + slaveState.close = false; + } + }, + { + link: `Take ${him} to bed`, + desc: general.goToBed(tempSlave), + tooltip: `Take ${him} somewhere a bit more comfortable.`, + prereq: () => !playerState.isLaying && !slaveState.isLaying, + effect: () => { + playerState.position = Position.LAYING; + slaveState.position = Position.LAYING; + } + }, + { + link: `Get out of bed`, + desc: general.getOutOfBed(tempSlave), + tooltip: `In case you need a little more maneuverability.`, + prereq: () => playerState.isLaying && slaveState.isLaying, + effect: () => { + playerState.position = Position.STANDING; + slaveState.position = Position.STANDING; + } + }, + { + link: `Bring in another slave`, + desc: general.bringInSlave(tempSlave), + tooltip: `Have another slave join the two of you.`, + prereq: () => V.slaves.length > 1, + effect: () => { + return; // temporarily disabled + } + }, + ]; + + if (V.active.canine) { + generalOptions.push({ + link: `Bring in ${V.active.canine.articleAn} ${V.active.canine.name}`, + desc: general.bringInCanine(tempSlave), + tooltip: `Spice things up with ${V.active.canine.species === 'dog' ? `man's best friend` : `a four-legged friend`}.`, + prereq: () => V.active.canine !== null, + effect: () => { + return; // temporarily disabled + } + }); + } + + if (V.active.hooved) { + generalOptions.push({ + link: `Bring in ${V.active.hooved.articleAn} ${V.active.hooved.name}`, + desc: general.bringInHooved(tempSlave), + tooltip: `Make things more interesting with something a bit larger.`, + prereq: () => V.active.hooved !== null, + effect: () => { + return; // temporarily disabled + } + }); + } + + if (V.active.feline) { + generalOptions.push({ + link: `Bring in ${V.active.feline.articleAn} ${V.active.feline.name}`, + desc: general.bringInFeline(tempSlave), + tooltip: `Have some fun with a furry ${V.active.feline.species === 'cat' ? `little` : ``} friend.`, + prereq: () => V.active.feline !== null, + effect: () => { + return; // temporarily disabled + } + }); + } + + const clothing = App.UI.SlaveInteract.useSlave.clothingText; + const clothingOptions = [ + { + link: `Pull up ${his} dress`, + desc: clothing.pullUpDress(tempSlave), + tooltip: `For easier access.`, + prereq: () => clothes.includes("dress") && !slaveState.clothing.bottom.pulledDown, + effect: () => { + slaveState.clothing.bottom.pulledDown = true; + playerState.lust++; + slaveState.lust++; + + refreshArt(); + } + }, + { + link: `Take off ${his} clothing`, + desc: clothing.removeClothing(tempSlave), + tooltip: `Have ${him} get completely naked.`, + prereq: () => clothes !== "no clothing" && !slaveState.clothing.top.isOff && !slaveState.clothing.bottom.isOff, + effect: () => { + tempSlave.clothes = "no clothing"; + slaveState.clothing.top.isOff = true; + slaveState.clothing.bottom.isOff = true; + + playerState.lust++; + slaveState.lust += 2; + + refreshArt(); + } + }, + { + link: `Take off ${his} top`, + desc: clothing.removeTop(tempSlave), + tooltip: `For easier access to ${his} ${tempSlave.boobs >= 300 ? `tits` : `chest`}.`, + prereq: () => !clothes.includes("dress") && !slaveState.clothing.top.isOff, + effect: () => { + slaveState.clothing.top.isOff = true; + playerState.lust++; + slaveState.lust++; + + refreshArt(); + } + }, + { + link: `Take off ${his} bottoms`, + desc: clothing.removeBottom(tempSlave), + tooltip: `For easier access to ${his} crotch.`, + prereq: () => !clothes.includes("dress") && !slaveState.clothing.bottom.isOff, + effect: () => { + slaveState.clothing.bottom.isOff = true; + playerState.lust++; + slaveState.lust++; + + refreshArt(); + } + }, + { + link: `Take off ${his} bra`, + desc: clothing.removeBra(tempSlave), + tooltip: `Get ${his} bra out of the way.`, + prereq: () => slaveState.topFree && slaveState.clothing.bra, + effect: () => { + slaveState.clothing.bra = false; + playerState.lust++; + slaveState.lust++; + + refreshArt(); + } + }, + { + link: `Take off ${his} underwear`, + desc: clothing.removeUnderwear(tempSlave), + tooltip: `Get ${his} ${tempSlave.vagina > -1 ? `panties` : `underwear`} out of the way.`, + prereq: () => slaveState.bottomFree && slaveState.clothing.underwear, + effect: () => { + slaveState.clothing.underwear = false; + playerState.lust++; + slaveState.lust++; + + refreshArt(); + } + }, + { + link: `Pull aside ${his} underwear`, + desc: clothing.pullAsideUnderwear(tempSlave), + tooltip: `Move ${his} ${tempSlave.vagina > -1 ? `panties` : `underwear`} out of the way for easier access to what's underneath.`, + prereq: () => slaveState.bottomFree && slaveState.clothing.underwear, + effect: () => { + playerState.lust++; + slaveState.lust++; + } + }, + { + link: `Give ${him} a ball gag`, + desc: clothing.addMouthAccessory(tempSlave), + tooltip: `In case ${he}'s being too mouthy – or just for fun.`, + prereq: () => tempSlave.mouthAccessory === none, + effect: () => { + tempSlave.mouthAccessory = "ball gag"; + + refreshArt(); + } + }, + { + link: `Give ${him} a ring gag`, + desc: clothing.addMouthAccessory(tempSlave), + tooltip: `In case ${he}'s being too mouthy, but you still want access to ${his} throat.`, + prereq: () => tempSlave.mouthAccessory === none, + effect: () => { + tempSlave.mouthAccessory = "ring gag"; + + refreshArt(); + } + }, + { + link: `Take ${tempSlave.mouthAccessory.includes("dildo") ? `out` : `off`} ${his} ${tempSlave.mouthAccessory}`, + desc: clothing.removeMouthAccessory(tempSlave), + tooltip: `Give ${him} some respite.`, + prereq: () => tempSlave.mouthAccessory !== none, + effect: () => { + tempSlave.mouthAccessory = none; + + refreshArt(); + } + }, + { + link: `Take off ${his} vaginal chastity device`, + desc: clothing.removeChastityVaginal(tempSlave), + tooltip: `${He} won't be needing it.`, + prereq: () => (clothes === "no clothing" || clothes.includes("dress")) + && tempSlave.chastityVagina === 1, + effect: () => { + tempSlave.chastityVagina = 0; + + refreshArt(); + } + }, + { + link: `Take off ${his} anal chastity device`, + desc: clothing.removeChastityAnal(tempSlave), + tooltip: `${He} won't be needing it.`, + prereq: () => (clothes === "no clothing" || clothes.includes("dress")) + && tempSlave.chastityVagina === 1, + effect: () => { + tempSlave.chastityVagina = 0; + + refreshArt(); + } + }, + { + link: `Take the chastity device off of ${his} dick`, + desc: clothing.removeChastityPenis(tempSlave), + tooltip: `${He} won't be needing it.`, + prereq: () => (clothes === "no clothing" || clothes.includes("dress")) + && tempSlave.chastityPenis === 1, + effect: () => { + tempSlave.chastityPenis = 0; + + refreshArt(); + } + }, + ]; + + div.id = 'use-slave-container'; + div.append(main()); + + return div; + + // Main Loop + + function main() { + const div = document.createElement("div"); + + if (playerState.lust < 100) { + if (introShown) { + div.appendChild(options()); + } else { + div.appendChild(intro()); + } + } else { + if (introShown) { + div.append(`You are out of stamina.`); + } else { + App.UI.DOM.appendNewElement("span", div, `You have recently had sex with ${him}`, "note"); + } + } + + return div; + } + + // Text Functions + + function intro() { + introShown = true; + + const mainSpan = App.UI.DOM.makeElement("span", `Use ${him} and take control: `); + + if (tempSlave.devotion > 50) { + const intro = App.UI.DOM.makeElement("div", `You pull ${tempSlave.slaveName} in close and tell ${him} that you want to make love. With ${tempSlave.mouthAccessory === none + ? `a ${Beauty(tempSlave) > 150 && tempSlave.face > 10 ? `pretty` : `quick`} smile` + : `as much of a smile as ${his} ${tempSlave.mouthAccessory} will allow` + }, ${he} makes it clear that your advances are not unwanted.`); + + intro.appendChild(options()); + mainSpan.appendChild(App.UI.DOM.linkReplace( + `Have sex with ${him}`, + intro + )); + + return mainSpan; + } else if (tempSlave.devotion > 20) { + const intro = App.UI.DOM.makeElement("div", `You tell ${tempSlave.slaveName} that you want to fuck ${him}. Though ${he} seems hesitant, your tone and the stern look in your eye make it clear that ${he} has no choice, and ${he} reluctantly agrees.`); + + intro.appendChild(options()); + mainSpan.appendChild(App.UI.DOM.linkReplace( + `Fuck ${him}`, + intro + )); + + return mainSpan; + } else { + const intro = App.UI.DOM.makeElement("div", `You tell ${tempSlave.slaveName} that you're going to fuck ${him}, whether ${he} likes it or not. The daggers ${he} glares at you feel almost physically tangible, but ${he} knows that ${he} ultimately has no choice.`); + + intro.appendChild(options()); + mainSpan.appendChild(App.UI.DOM.linkReplace( + `Rape ${him}`, + intro + )); + + return mainSpan; + } + } + + // Generator Functions + + function options() { + const optionsDiv = document.createElement("div"); + + const face = generateOptions(faceOptions, optionsDiv); + const chest = generateOptions(chestOptions, optionsDiv); + const crotch = generateOptions(crotchOptions, optionsDiv); + const general = generateOptions(generalOptions, optionsDiv); + const clothing = generateOptions(clothingOptions, optionsDiv); + + optionsDiv.append(face, chest, crotch, general, clothing); + + return optionsDiv; + } + + /** + * @param {Array<UseSlave.Option>} arr + * @param {HTMLDivElement} div + * @returns {HTMLDivElement} + */ + function generateOptions(arr, div) { + const mainDiv = document.createElement("div"); + + const availableOptions = arr.filter(option => option.prereq()); + + mainDiv.appendChild(generateLinks(availableOptions, div)); + + return mainDiv; + } + + /** + * @param {Array<UseSlave.Option>} available + * @param {HTMLDivElement} div + */ + function generateLinks(available, div) { + const links = []; + + available.forEach((e) => links.push(App.UI.DOM.link(e.link, () => { + div.innerHTML = e.desc; + e.effect(); + + if (V.debugMode) { + console.log( + playerState, + slaveState, + ); + } + + div.appendChild(main()); + + div.scrollTop = div.scrollHeight - div.clientHeight; + }, null, '', e.tooltip))); + + return App.UI.DOM.generateLinksStrip(links); + } +}; diff --git a/src/interaction/useSlave/useSlaveText.js b/src/interaction/useSlave/useSlaveText.js new file mode 100644 index 0000000000000000000000000000000000000000..25bddc7d967712aff2ae97d8bb0018da9f7e6785 --- /dev/null +++ b/src/interaction/useSlave/useSlaveText.js @@ -0,0 +1,610 @@ +App.UI.SlaveInteract.useSlave.faceText = { + /** @param {App.Entity.SlaveState} slave */ + regularKiss(slave) { + const {him} = getPronouns(slave); + + if (slave.devotion > 50) { + return `You pull ${him} in close and kiss ${him}.`; + } else if (slave.devotion > 20) { + return `Face test regular 2`; + } else if (slave.devotion > -20) { + return `Face test regular 3`; + } else { + return `Face test regular 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + passionateKiss(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Face test passionate 1`; + } else if (slave.devotion > 20) { + return `Face test passionate 2`; + } else if (slave.devotion > -20) { + return `Face test passionate 3`; + } else { + return `Face test passionate 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + intimateKiss(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Face test intimate 1`; + } else if (slave.devotion > 20) { + return `Face test intimate 2`; + } else if (slave.devotion > -20) { + return `Face test intimate 3`; + } else { + return `Face test intimate 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + slaveGivesOral(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Face test slave oral 1`; + } else if (slave.devotion > 20) { + return `Face test slave oral 2`; + } else if (slave.devotion > -20) { + return `Face test slave oral 3`; + } else { + return `Face test slave oral 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + playerGivesOral(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Face test player oral 1`; + } else if (slave.devotion > 20) { + return `Face test player oral 2`; + } else if (slave.devotion > -20) { + return `Face test player oral 3`; + } else { + return `Face test player oral 4`; + } + }, +}; + +App.UI.SlaveInteract.useSlave.chestText = { + /** @param {App.Entity.SlaveState} slave */ + grope(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Chest test grope 1`; + } else if (slave.devotion > 20) { + return `Chest test grope 2`; + } else if (slave.devotion > -20) { + return `Chest test grope 3`; + } else { + return `Chest test grope 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + lick(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Chest test lick 1`; + } else if (slave.devotion > 20) { + return `Chest test lick 2`; + } else if (slave.devotion > -20) { + return `Chest test lick 3`; + } else { + return `Chest test lick 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + suck(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Chest test suck 1`; + } else if (slave.devotion > 20) { + return `Chest test suck 2`; + } else if (slave.devotion > -20) { + return `Chest test suck 3`; + } else { + return `Chest test suck 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + bite(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Chest test bite 1`; + } else if (slave.devotion > 20) { + return `Chest test bite 2`; + } else if (slave.devotion > -20) { + return `Chest test bite 3`; + } else { + return `Chest test bite 4`; + } + }, +}; + +App.UI.SlaveInteract.useSlave.crotchText = { + /** @param {App.Entity.SlaveState} slave */ + gropePussy(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Groping pussy test 1`; + } else if (slave.devotion > 20) { + return `Groping pussy test 2`; + } else if (slave.devotion > -20) { + return `Groping pussy test 3`; + } else { + return `Groping pussy test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + gropeAss(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Groping ass test 1`; + } else if (slave.devotion > 20) { + return `Groping ass test 2`; + } else if (slave.devotion > -20) { + return `Groping ass test 3`; + } else { + return `Groping ass test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + fingerPussy(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Fingering pussy test 1`; + } else if (slave.devotion > 20) { + return `Fingering pussy test 2`; + } else if (slave.devotion > -20) { + return `Fingering pussy test 3`; + } else { + return `Fingering pussy test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + fingerAnus(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Fingering anus test 1`; + } else if (slave.devotion > 20) { + return `Fingering anus test 2`; + } else if (slave.devotion > -20) { + return `Fingering anus test 3`; + } else { + return `Fingering anus test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + fuckPussy(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Fuck pussy test 1`; + } else if (slave.devotion > 20) { + return `Fuck pussy test 2`; + } else if (slave.devotion > -20) { + return `Fuck pussy test 3`; + } else { + return `Fuck pussy test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + fuckAnus(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Fuck asshole test 1`; + } else if (slave.devotion > 20) { + return `Fuck asshole test 2`; + } else if (slave.devotion > -20) { + return `Fuck asshole test 3`; + } else { + return `Fuck asshole test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + sixtyNine(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `69 test 1`; + } else if (slave.devotion > 20) { + return `69 test 2`; + } else if (slave.devotion > -20) { + return `69 test 3`; + } else { + return `69 test 4`; + } + } +}; + +App.UI.SlaveInteract.useSlave.generalText = { + /** @param {App.Entity.SlaveState} slave */ + dance(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Dance test 1`; + } else if (slave.devotion > 20) { + return `Dance test 2`; + } else if (slave.devotion > -20) { + return `Dance test 3`; + } else { + return `Dance test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + striptease(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Striptease test 1`; + } else if (slave.devotion > 20) { + return `Striptease test 2`; + } else if (slave.devotion > -20) { + return `Striptease test 3`; + } else { + return `Striptease test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + pushDown(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Push down test 1`; + } else if (slave.devotion > 20) { + return `Push down test 2`; + } else if (slave.devotion > -20) { + return `Push down test 3`; + } else { + return `Push down test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + pullUp(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Pull up test 1`; + } else if (slave.devotion > 20) { + return `Pull up test 2`; + } else if (slave.devotion > -20) { + return `Pull up test 3`; + } else { + return `Pull up test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + pushAway(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Push away test 1`; + } else if (slave.devotion > 20) { + return `Push away test 2`; + } else if (slave.devotion > -20) { + return `Push away test 3`; + } else { + return `Push away test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + pullClose(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Pull in test 1`; + } else if (slave.devotion > 20) { + return `Pull in test 2`; + } else if (slave.devotion > -20) { + return `Pull in test 3`; + } else { + return `Pull in test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + goToBed(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Go to bed test 1`; + } else if (slave.devotion > 20) { + return `Go to bed test 2`; + } else if (slave.devotion > -20) { + return `Go to bed test 3`; + } else { + return `Go to bed test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + getOutOfBed(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Get out of bed test 1`; + } else if (slave.devotion > 20) { + return `Get out of bed test 2`; + } else if (slave.devotion > -20) { + return `Get out of bed test 3`; + } else { + return `Get out of bed test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + bringInSlave(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Second slave test 1`; + } else if (slave.devotion > 20) { + return `Second slave test 2`; + } else if (slave.devotion > -20) { + return `Second slave test 3`; + } else { + return `Second slave test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + bringInCanine(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Canine test 1`; + } else if (slave.devotion > 20) { + return `Canine test 2`; + } else if (slave.devotion > -20) { + return `Canine test 3`; + } else { + return `Canine test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + bringInHooved(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Hooved test 1`; + } else if (slave.devotion > 20) { + return `Hooved test 2`; + } else if (slave.devotion > -20) { + return `Hooved test 3`; + } else { + return `Hooved test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + bringInFeline(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Feline test 1`; + } else if (slave.devotion > 20) { + return `Feline test 2`; + } else if (slave.devotion > -20) { + return `Feline test 3`; + } else { + return `Feline test 4`; + } + }, +}; + +App.UI.SlaveInteract.useSlave.clothingText = { + /** @param {App.Entity.SlaveState} slave */ + pullUpDress(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Pull up dress test 1`; + } else if (slave.devotion > 20) { + return `Pull up dress test 2`; + } else if (slave.devotion > -20) { + return `Pull up dress test 3`; + } else { + return `Pull up dress test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + removeClothing(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Remove clothing test 1`; + } else if (slave.devotion > 20) { + return `Remove clothing test 2`; + } else if (slave.devotion > -20) { + return `Remove clothing test 3`; + } else { + return `Remove clothing test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + removeTop(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Remove top test 1`; + } else if (slave.devotion > 20) { + return `Remove top test 2`; + } else if (slave.devotion > -20) { + return `Remove top test 3`; + } else { + return `Remove top test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + removeBottom(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Remove bottom test 1`; + } else if (slave.devotion > 20) { + return `Remove bottom test 2`; + } else if (slave.devotion > -20) { + return `Remove bottom test 3`; + } else { + return `Remove bottom test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + removeBra(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Remove bra test 1`; + } else if (slave.devotion > 20) { + return `Remove bra test 2`; + } else if (slave.devotion > -20) { + return `Remove bra test 3`; + } else { + return `Remove bra test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + removeUnderwear(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Remove underwear test 1`; + } else if (slave.devotion > 20) { + return `Remove underwear test 2`; + } else if (slave.devotion > -20) { + return `Remove underwear test 3`; + } else { + return `Remove underwear test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + pullAsideUnderwear(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Pull aside underwear test 1`; + } else if (slave.devotion > 20) { + return `Pull aside underwear test 2`; + } else if (slave.devotion > -20) { + return `Pull aside underwear test 3`; + } else { + return `Pull aside underwear test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + addMouthAccessory(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Add mouth accessory test 1`; + } else if (slave.devotion > 20) { + return `Add mouth accessory test 2`; + } else if (slave.devotion > -20) { + return `Add mouth accessory test 3`; + } else { + return `Add mouth accessory test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + removeMouthAccessory(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Remove mouth accessory test 1`; + } else if (slave.devotion > 20) { + return `Remove mouth accessory test 2`; + } else if (slave.devotion > -20) { + return `Remove mouth accessory test 3`; + } else { + return `Remove mouth accessory test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + removeChastityVaginal(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Remove chastity vaginal test 1`; + } else if (slave.devotion > 20) { + return `Remove chastity vaginal test 2`; + } else if (slave.devotion > -20) { + return `Remove chastity vaginal test 3`; + } else { + return `Remove chastity vaginal test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + removeChastityAnal(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Remove chastity anal test 1`; + } else if (slave.devotion > 20) { + return `Remove chastity anal test 2`; + } else if (slave.devotion > -20) { + return `Remove chastity anal test 3`; + } else { + return `Remove chastity anal test 4`; + } + }, + + /** @param {App.Entity.SlaveState} slave */ + removeChastityPenis(slave) { + // const {him, his} = getPronouns(slave); + + if (slave.devotion > 50) { + return `Remove chastity penis test 1`; + } else if (slave.devotion > 20) { + return `Remove chastity penis test 2`; + } else if (slave.devotion > -20) { + return `Remove chastity penis test 3`; + } else { + return `Remove chastity penis test 4`; + } + }, + +};