diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js index 2a18ab6fb7d50560c8323dab5a39b3b4b3967f2e..6f43fef0bab3d0307e622d98fcfe9b0594be0e3b 100644 --- a/js/003-data/gameVariableData.js +++ b/js/003-data/gameVariableData.js @@ -81,6 +81,7 @@ App.Data.defaultGameStateVariables = { extremeUnderage: 0, formatNumbers: 1, fucktoyInteractionsPosition: 1, + slaveInteractLongForm: false, headGirlSoftensFlaws: 1, headGirlTrainsFlaws: 1, headGirlTrainsHealth: 1, diff --git a/src/Mods/SecExp/js/Unit.js b/src/Mods/SecExp/js/Unit.js index 77260493c86d8d4bc08eb93578944056ee953fb0..35fac5031ab627d3de6aa952931b21781ba3407a 100644 --- a/src/Mods/SecExp/js/Unit.js +++ b/src/Mods/SecExp/js/Unit.js @@ -3,7 +3,6 @@ */ App.SecExp.bulkUpgradeUnit = function(unit) { unit = Array.isArray(unit) ? unit : [unit]; - // console.log(unit); return; let el = document.createElement("a"); function upgradeUnit(x) { @@ -37,16 +36,14 @@ App.SecExp.bulkUpgradeUnit = function(unit) { return Math.ceil(cost *= 1.1); } - if (unit.length > 0) { - const price = unit.map(getCost).reduce((acc, cur) => acc + cur); - if (price > 0) { - el.append(App.UI.DOM.link(`Bulk upgrade for ${cashFormat(price)}`, () => { - unit.map(upgradeUnit).reduce((acc, cur) => acc + cur); - cashX(-price, "securityExpansion"); - }, - [], passage() - )); - } + const price = unit.map(getCost).reduce((acc, cur) => acc + cur); + if (price > 0) { + el.append(App.UI.DOM.link(`Bulk upgrade for ${cashFormat(price)}`, () => { + unit.map(upgradeUnit).reduce((acc, cur) => acc + cur); + cashX(-price, "securityExpansion"); + }, + [], passage() + )); } return el; }; diff --git a/src/Mods/SecExp/js/buildingsJS.js b/src/Mods/SecExp/js/buildingsJS.js index f12f8329c26d862345dfb15fbadb41e6f1022425..f0ac128806045d97620b2e2d746c86042e4d8f3f 100644 --- a/src/Mods/SecExp/js/buildingsJS.js +++ b/src/Mods/SecExp/js/buildingsJS.js @@ -198,10 +198,11 @@ App.SecExp.propHub = (function() { } if (V.SecExp.buildings.propHub && Object.entries(V.SecExp.buildings.propHub).length === 0) { delete V.SecExp.buildings.propHub; - } else if (V.propHub || (V.SecExp.buildings.propHub && Object.entries(V.SecExp.buildings.propHub).length > 0)){ + } else if (V.propHub || (V.SecExp.buildings.propHub && Object.entries(V.SecExp.buildings.propHub).length > 0)) { V.SecExp.buildings.propHub = V.SecExp.buildings.propHub || {}; V.SecExp.buildings.propHub.upgrades = V.SecExp.buildings.propHub.upgrades || {}; - V.SecExp.buildings.propHub.recruiterOffice = V.SecExp.buildings.propHub.recruiterOffice || V.recuriterOffice || V.RecuriterOffice || 0; + V.SecExp.buildings.propHub.recruiterOffice = V.SecExp.buildings.propHub.recruiterOffice || V.SecExp.buildings.propHub.recuriterOffice || V.recuriterOffice || V.RecuriterOffice || 0; + delete V.SecExp.buildings.propHub.recuriterOffice; V.SecExp.buildings.propHub.upgrades.campaign = V.SecExp.buildings.propHub.upgrades.campaign || V.SecExp.buildings.propHub.campaign || V.propCampaign || 0; delete V.SecExp.buildings.propHub.campaign; @@ -216,17 +217,18 @@ App.SecExp.propHub = (function() { if (V.propFocus && V.propFocus !== "none") { V.SecExp.buildings.propHub.focus = V.propFocus; } - - const vars = ['fakeNews', 'controlLeaks', 'marketInfiltration', 'blackOps']; - for(let i = 0; i < vars.length; i++) { - if (jsDef(V[vars[i]]) && V[vars[i]] > 0) { - V.SecExp.buildings.propHub[vars[i]] = V[vars[i]]; - delete V[vars[i]]; - } else { - V.SecExp.buildings.propHub.upgrades[vars[i]] = V.SecExp.buildings.propHub.upgrades[vars[i]] || V.SecExp.buildings.propHub[vars[i]] || 0; - delete V.SecExp.buildings.propHub[vars[i]]; - } - } + + V.SecExp.buildings.propHub.upgrades.fakeNews = V.SecExp.buildings.propHub.upgrades.fakeNews || V.SecExp.buildings.propHub.fakeNews || V.fakeNews || 0; + delete V.SecExp.buildings.propHub.fakeNews; + + V.SecExp.buildings.propHub.upgrades.controlLeaks = V.SecExp.buildings.propHub.upgrades.controlLeaks || V.SecExp.buildings.propHub.controlLeaks || V.controlLeaks || 0; + delete V.SecExp.buildings.propHub.controlLeaks; + + V.SecExp.buildings.propHub.upgrades.marketInfiltration = V.SecExp.buildings.propHub.upgrades.marketInfiltration || V.SecExp.buildings.propHub.marketInfiltration || V.marketInfiltration || 0; + delete V.SecExp.buildings.propHub.marketInfiltration; + + V.SecExp.buildings.propHub.upgrades.blackOps = V.SecExp.buildings.propHub.upgrades.blackOps || V.SecExp.buildings.propHub.blackOps || V.blackOps || 0; + delete V.SecExp.buildings.propHub.blackOps; } } })(); @@ -252,13 +254,19 @@ App.SecExp.barracks = (function() { } if (V.SecExp.buildings.barracks && Object.entries(V.SecExp.buildings.barracks === 0).length) { delete V.SecExp.buildings.barracks; - } else if (V.secBarracks || (V.SecExp.buildings.barracks && Object.entries(V.SecExp.buildings.barracks).length > 0)){ - V.SecExp.buildings.barracks = V.SecExp.buildings.barracks || V.SecExp.buildings.barracks.upgrades || V.secBarracksUpgrades || {}; + } else if (V.secBarracks || (V.SecExp.buildings.barracks && Object.entries(V.SecExp.buildings.barracks).length > 0)) { + V.SecExp.buildings.barracks = V.SecExp.buildings.barracks || V.secBarracksUpgrades || {}; V.SecExp.buildings.barracks.size = V.SecExp.buildings.barracks.size || 0; V.SecExp.buildings.barracks.luxury = V.SecExp.buildings.barracks.luxury || 0; V.SecExp.buildings.barracks.training = V.SecExp.buildings.barracks.training || 0; V.SecExp.buildings.barracks.loyaltyMod = V.SecExp.buildings.barracks.loyaltyMod || 0; - delete V.SecExp.buildings.barracks.upgrades; + if (V.SecExp.buildings.barracks.upgrades) { + V.SecExp.buildings.barracks.size = V.SecExp.buildings.barracks.upgrades.size; + V.SecExp.buildings.barracks.luxury = V.SecExp.buildings.barracks.upgrades.luxury; + V.SecExp.buildings.barracks.training = V.SecExp.buildings.barracks.upgrades.training; + V.SecExp.buildings.barracks.loyaltyMod = V.SecExp.buildings.barracks.upgrades.loyaltyMod; + delete V.SecExp.buildings.barracks.upgrades; + } } } })(); @@ -306,13 +314,18 @@ App.SecExp.secHub = (function() { V.SecExp.buildings.secHub = V.SecExp.buildings.secHub || {}; V.SecExp.buildings.secHub.menials = V.SecExp.buildings.secHub.menials || V.secMenials || V.secHelots || 0; V.SecExp.buildings.secHub.coldstorage = V.SecExp.buildings.secHub.coldstorage || 0; + + V.SecExp.buildings.secHub.upgrades = V.SecExp.buildings.secHub.upgrades || {}; + V.SecExp.buildings.secHub.upgrades.security = V.SecExp.buildings.secHub.upgrades.security || {}; if (V.secUpgrades) { V.SecExp.buildings.secHub.coldstorage = V.secUpgrades.coldstorage; - delete V.secUpgrades.coldstorage; + V.SecExp.buildings.secHub.upgrades.security = { + nanoCams: V.secUpgrades.nanoCams, + cyberBots: V.secUpgrades.cyberBots, + eyeScan: V.secUpgrades.eyeScan, + cryptoAnalyzer: V.secUpgrades.cryptoAnalyzer, + }; } - - V.SecExp.buildings.secHub.upgrades = V.SecExp.buildings.secHub.upgrades || {}; - V.SecExp.buildings.secHub.upgrades.security = V.SecExp.buildings.secHub.upgrades.security || V.secUpgrades || {}; V.SecExp.buildings.secHub.upgrades.crime = V.SecExp.buildings.secHub.upgrades.crime || V.crimeUpgrades || {}; V.SecExp.buildings.secHub.upgrades.intel = V.SecExp.buildings.secHub.upgrades.intel || V.intelUpgrades || {}; V.SecExp.buildings.secHub.upgrades.readiness = V.SecExp.buildings.secHub.upgrades.readiness || V.readinessUpgrades || {}; diff --git a/src/endWeek/saPregnancy.js b/src/endWeek/saPregnancy.js index 0f215860f66c0a88769cb17c80e57c829be14841..1a4ef2dad884a5bdbe3d2b236a1165b0118a2d50 100644 --- a/src/endWeek/saPregnancy.js +++ b/src/endWeek/saPregnancy.js @@ -888,7 +888,7 @@ App.SlaveAssignment.pregnancy = (function() { if (slave.fetishKnown === 1 && slave.fetishStrength <= 95) { r.push(`Such total satisfaction of ${his} pregnancy fantasies <span class="fetish inc">strengthens ${his} fetish.</span>`); slave.fetishStrength += 4; - } else { + } else if (slave.fetishKnown === 0) { r.push(`You are now well aware of ${his} <span class="fetish gain">latent pregnancy fetish.</span>`); slave.fetishKnown = 1; } diff --git a/src/endWeek/saRecruitGirls.js b/src/endWeek/saRecruitGirls.js index e855a0d2d600cb2ba186e1ab9bbf0ef64922342f..2780ac1f5b4062466dcd5aa34449c03f1da3ad8a 100644 --- a/src/endWeek/saRecruitGirls.js +++ b/src/endWeek/saRecruitGirls.js @@ -1654,8 +1654,42 @@ App.SlaveAssignment.recruitGirls = (function() { } else { pushFS(`${He} never considers promoting your household's Revivalist protocols, since you don't value your Head Girl enough to accord ${him} a separate apartment inside your walls.`); } + } else if (arcology.FSAztecRevivalist !== "unset") { + if (arcology.FSPaternalist !== "unset") { + if (slave.health.condition >= 80 && slave.bellyPreg < 1500 && slave.trust + slave.devotion >= 175) { + pushFS(`${He} allows willing members of the public to <span class="health dec">spill ${his} blood</span> in tribute to the gods.`); + healthDamage(slave, 2); + FSmatch++; + seed += 5; + arcology.FSAztecRevivalist += 0.02 * V.FSSingleSlaveRep; + } else if (slave.trust + slave.devotion < 175) { + pushFS(`${He} is willing to take part in bloodletting, but the public doesn't find that believable.`); + } else if (slave.bellyPreg >= 1500) { + pushFS(`${He} is willing to take part in bloodletting, but the public absolutely refuses to do such a thing to a pregnant $girl.`); + } else { + pushFS(`${He} is willing to take part in bloodletting, but the public finds it wrong to impose on someone not in the absolute best of health.`); + } + } else { + if (slave.health.condition >= -20 && slave.trust + slave.devotion >= 175) { + pushFS(`${He} practices public displays of <span class="health dec">bloodletting,</span> both on ${himself} and those willing, impressing onlookers with ${his} devotion to the gods.`); + healthDamage(slave, 2); + FSmatch++; + seed += 5; + arcology.FSAztecRevivalist += 0.02 * V.FSSingleSlaveRep; + } else if (slave.trust + slave.devotion < 175) { + pushFS(`${He} is willing to take part in bloodletting, but you have no reason to trust ${him} with the tools required.`); + } else { + pushFS(`${He} is willing to take part in bloodletting, but you can't allow ${him} to do so in ${his} poor health.`); + } + } + if (slaveInt > 15) { + pushFS(`${He} puts ${his} mind to work as ${he} joins citizens in their prayers to each diety.`); + FSdefend++; + seed += 1; + } else { + pushFS(`${His} poor attempts to espouse the benefits of true faith leave the crowd wondering if ${he} is next in line for sacrifice.`); + } } - /* TODO: and then there's Aztec revivalist, completely forgotten */ repX(Math.trunc(seed * 5), "futureSocieties", slave); diff --git a/src/gui/options/options.tw b/src/gui/options/options.tw index 6077eb0299d2bcb0170b78166a57897b41d91ad7..1ab2f1a3fe5c74e4bbb620138e7dd4a2d05b0dd9 100644 --- a/src/gui/options/options.tw +++ b/src/gui/options/options.tw @@ -151,6 +151,9 @@ <<run _options.addOption("Interactions with your fucktoys are", "fucktoyInteractionsPosition") .addValueList([["next to them", 1], ["at page bottom", 0]])>> + <<run _options.addOption("Hide tabs in Slave Interact", "slaveInteractLongForm") + .addValue("Enabled", true).on().addValue("Disabled", false).off()>> + <<run _options.addOption("Line separations are", "lineSeparations") .addValue("Shown", 1).on().addValue("Hidden", 0).off()>> diff --git a/src/interaction/siCustom.js b/src/interaction/siCustom.js new file mode 100644 index 0000000000000000000000000000000000000000..fe81a8a2ccf381ea7503fc1768650a0bfda92b6d --- /dev/null +++ b/src/interaction/siCustom.js @@ -0,0 +1,858 @@ +App.UI.SlaveInteract.custom = (function() { + let el; + let label; + let result; + let textbox; + return custom; + + function custom(slave) { + let title; + el = document.createElement('div'); + + el.appendChild(intro(slave)); + + title = document.createElement('h3'); + title.textContent = `Art`; + el.appendChild(title); + el.appendChild(customSlaveImage(slave)); + el.appendChild(customHairImage(slave)); + + title = document.createElement('h3'); + title.textContent = `Names`; + el.appendChild(title); + el.appendChild(playerTitle(slave)); + el.appendChild(slaveFullName(slave)); + + title = document.createElement('h3'); + title.textContent = `Description`; + el.appendChild(title); + el.appendChild(hair(slave)); + el.appendChild(eyeColor(slave)); + el.appendChild(customTattoo(slave)); + el.appendChild(customOriginStory(slave)); + el.appendChild(customDescription(slave)); + el.appendChild(customLabel(slave)); + + return el; + } + + function intro(slave) { + const frag = new DocumentFragment(); + let p; + p = document.createElement('p'); + p.id = "rename"; + frag.append(p); + + p = document.createElement('p'); + p.className = "scene-p"; + p.append(`You may enter custom descriptors for your slave's hair color, hair style, tattoos, or anything else here. After typing, press `); + p.appendChild(App.UI.DOM.makeElement("kbd", "enter")); + p.append(` to commit your change. These custom descriptors will appear in descriptions of your slave, but will have no gameplay effect. Changing them is free.`); + frag.append(p); + return frag; + } + + function playerTitle(slave) { + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + hers, + himself, + boy, + He, + His + } = getPronouns(slave); + let playerTitle = document.createElement('p'); + label = document.createElement('div'); + if (slave.devotion >= -50) { + if (slave.custom.title !== "") { + label.textContent = `You have instructed ${him} to always refer to you as ${slave.custom.title}, which, should ${he} lisp, comes out as ${slave.custom.titleLisp}.`; + } else { + label.textContent = `You expect ${him} to refer to you as all your other slaves do.`; + } + result = document.createElement('div'); + result.id = "result"; + result.className = "choices"; + + let hiddenTextBox = document.createElement('span'); + let shownTextBox = document.createElement('span'); + if (slave.custom.title === "") { + hiddenTextBox.appendChild( + App.UI.DOM.link( + `Set a custom title for ${him} to address you as`, + () => { + jQuery('#result').empty().append(shownTextBox); + } + ) + ); + result.appendChild(hiddenTextBox); + shownTextBox.textContent = `Custom title: `; + textbox = App.UI.DOM.makeTextBox( + "", + v => { + slave.custom.title = v; + jQuery('#result').empty().append( + document.createTextNode(`${He}'ll try ${his} best to call you ${slave.custom.title}.`) + ); + slave.custom.titleLisp = lispReplace(slave.custom.title); + }); + shownTextBox.appendChild(textbox); + } else { + result.append(`${He}'s trying ${his} best to call you `); + textbox = App.UI.DOM.makeTextBox( + slave.custom.title, + v => { + slave.custom.title = v; + jQuery('#result').empty().append( + document.createTextNode(`${He}'ll try ${his} best to call you ${slave.custom.title}.`) + ); + slave.custom.titleLisp = lispReplace(slave.custom.title); + }); + result.appendChild(textbox); + result.appendChild( + App.UI.DOM.link( + ` Stop using a custom title`, + () => { + jQuery('#result').empty().append( + document.createTextNode(`${He} will no longer refer to you with a special title.`) + ); + slave.custom.title = ""; + slave.custom.titleLisp = ""; + } + ) + ); + } + label.appendChild(result); + } else { + label.textContent = `You must break ${his} will further before ${he} will refer to you by a new title. `; + if (SlaveStatsChecker.checkForLisp(slave)) { + if (slave.custom.titleLisp && slave.custom.titleLisp !== "") { + label.textContent += `For now, ${he} intends to keep calling you "${slave.custom.titleLisp}."`; + } + } else { + if (slave.custom.title && slave.custom.title !== "") { + label.textContent += `For now, ${he} intends to keep calling you "${slave.custom.title}."`; + } + } + } + playerTitle.appendChild(label); + return playerTitle; + } + + function slaveFullName(slave) { + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + hers, + himself, + boy, + He, + His + } = getPronouns(slave); + let slaveFullNameNode = document.createElement('span'); + if ( + ((slave.devotion >= -50 || slave.trust < -20) && (slave.birthName !== slave.slaveName)) || + (slave.devotion > 20 || slave.trust < -20) + ) { + slaveFullNameNode.appendChild(slaveName()); + slaveFullNameNode.appendChild(slaveSurname()); + } else { + slaveFullNameNode.textContent = `You must break ${his} will further before you can successfully force a new name on ${him}.`; + slaveFullNameNode.className = "note"; + } + + return slaveFullNameNode; + + function slaveName() { + const oldName = slave.slaveName; + const oldSurname = slave.slaveSurname; + // Slave Name + let slaveNameNode = document.createElement('p'); + label = document.createElement('div'); + result = document.createElement('div'); + result.id = "result"; + result.className = "choices"; + const linkArray = []; + + label.append(`Change ${his} given name`); + if (slave.birthName !== slave.slaveName) { + label.append(` (${his} birth name was ${slave.birthName})`); + } + label.append(`: `); + + textbox = App.UI.DOM.makeTextBox( + slave.slaveName, + v => { + slave.slaveName = v; + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + ); + label.appendChild(textbox); + + slaveNameNode.appendChild(label); + + if (slave.slaveName === slave.birthName) { + linkArray.push(App.UI.DOM.disabledLink(`${He} has ${his} birth name`, [`Nothing to reset`])); + } else { + linkArray.push(App.UI.DOM.link( + `Restore ${his} birth name`, + () => { + slave.slaveName = slave.birthName; + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + )); + } + + if (V.arcologies[0].FSPastoralist !== "unset") { + if (slave.lactation > 0) { + linkArray.push(chooseThreeNames(`Choose a random cow name for ${him}`, setup.cowSlaveNames, "cow-names")); + } + } + if (V.arcologies[0].FSIntellectualDependency !== "unset") { + if (slave.intelligence + slave.intelligenceImplant < -10) { + linkArray.push(chooseThreeNames(`Give ${him} a random stripper given name`, setup.bimboSlaveNames, "bimbo-names")); + } + } + if (V.arcologies[0].FSChattelReligionist !== "unset") { + linkArray.push(chooseThreeNames(`Give ${him} a random devotional given name`, setup.chattelReligionistSlaveNames, "devotional-names")); + } + result.append(App.UI.DOM.generateLinksStrip(linkArray)); + slaveNameNode.appendChild(result); + return slaveNameNode; + + function chooseThreeNames(title, array, id) { + const el = document.createElement("span"); + el.id = id; + el.append( + App.UI.DOM.link( + title, + () => { + linkGuts(); + } + ) + ); + return el; + function linkGuts() { + // Randomize the array + const shuffled = array.sort(() => 0.5 - Math.random()); + + // Get the first three new names + const names = []; + for (let i = 0; names.length < 3; i++) { + if (i > shuffled.length) { + break; + } + if (shuffled[i] !== slave.slaveName) { + names.push(shuffled[i]); + } + } + + // return the three names as links + const nameLinks = []; + for (const name of names) { + nameLinks.push( + App.UI.DOM.link( + name, + () => { + slave.slaveName = name; + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + } + ) + ); + } + nameLinks.push( + App.UI.DOM.link( + "...", + () => { + linkGuts(); + } + ) + ); + jQuery(`#${id}`).empty().append(App.UI.DOM.generateLinksStrip(nameLinks)); + } + } + } + + function slaveSurname() { + // Slave Surname + const oldName = slave.slaveName; + const oldSurname = slave.slaveSurname; + let slaveSurnameNode = document.createElement('p'); + label = document.createElement('div'); + result = document.createElement('div'); + result.id = "result"; + result.className = "choices"; + + label.append(`Change ${his} surname`); + if (slave.birthSurname !== slave.slaveSurname) { + label.append(` (${his} birth surname was ${slave.birthSurname})`); + } + label.append(`: `); + + textbox = App.UI.DOM.makeTextBox( + slave.slaveSurname, + v => { + slave.slaveSurname = textbox.value; + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + ); + label.appendChild(textbox); + + slaveSurnameNode.appendChild(label); + + if (slave.slaveSurname === slave.birthSurname) { + result.append(` ${He} has ${his} birth surname`); + } else { + result.appendChild(App.UI.DOM.link( + ` Restore ${his} birth surname`, + () => { + slave.slaveSurname = slave.birthSurname; + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + )); + } + + if (slave.slaveSurname) { + result.append(` | `); + result.appendChild(App.UI.DOM.link( + `Take ${his} surname away`, + () => { + slave.slaveSurname = 0; + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + )); + } + if (slave.relationship >= 5) { + const spouse = getSlave(slave.relationshipTarget); + if (spouse.slaveSurname && slave.slaveSurname !== spouse.slaveSurname) { + result.append(` | `); + const wifePronouns = getPronouns(spouse); + result.appendChild(App.UI.DOM.link( + `Give ${him} ${his} ${wifePronouns.wife}'s surname`, + () => { + slave.slaveSurname = spouse.slaveSurname; + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + )); + } + } + if (slave.relationship === -3) { + if (V.PC.slaveSurname && slave.slaveSurname !== V.PC.slaveSurname) { + result.append(` | `); + result.appendChild(App.UI.DOM.link( + `Give ${him} your surname`, + () => { + slave.slaveSurname = V.PC.slaveSurname; + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + )); + } + } + if (V.arcologies[0].FSRomanRevivalist !== "unset") { + result.append(` | `); + result.appendChild(App.UI.DOM.link( + `Give ${him} a random full Roman name`, + () => { + slave.slaveName = setup.romanSlaveNames.random(); + slave.slaveSurname = setup.romanSlaveSurnames.random(); + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + )); + } else if (V.arcologies[0].FSAztecRevivalist !== "unset") { + result.append(` | `); + result.appendChild(App.UI.DOM.link( + `Give ${him} a random full Aztec name`, + () => { + slave.slaveName = setup.aztecSlaveNames.random(); + slave.slaveSurname = 0; + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + )); + } else if (V.arcologies[0].FSEgyptianRevivalist !== "unset") { + result.append(` | `); + result.appendChild(App.UI.DOM.link( + `Give ${him} a random full ancient Egyptian name`, + () => { + slave.slaveName = setup.ancientEgyptianSlaveNames.random(); + slave.slaveSurname = 0; + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + )); + } else if (V.arcologies[0].FSEdoRevivalist !== "unset") { + result.append(` | `); + result.appendChild(App.UI.DOM.link( + `Give ${him} a random full feudal Japanese name`, + () => { + slave.slaveName = setup.edoSlaveNames.random(); + slave.slaveSurname = setup.edoSlaveSurnames.random(); + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + )); + } + if (V.arcologies[0].FSDegradationist > -1) { + result.append(` | `); + result.appendChild(App.UI.DOM.link( + `Give ${him} a degrading full name`, + () => { + DegradingName(slave); + updateName(slave, {oldName: oldName, oldSurname: oldSurname}); + }, + false, + )); + } + slaveSurnameNode.appendChild(result); + return slaveSurnameNode; + } + function updateName(slave, {oldName: oldName, oldSurname: oldSurname}) { + App.UI.SlaveInteract.custom(slave); + App.UI.SlaveInteract.rename(slave, {oldName: oldName, oldSurname: oldSurname}); + } + } + + /** + * @param {App.Entity.SlaveState} slave + */ + function hair(slave) { + let hairNode = new DocumentFragment(); + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + hers, + himself, + boy, + He, + His + } = getPronouns(slave); + + hairNode.appendChild(hairStyle()); + hairNode.appendChild(hairColor()); + return hairNode; + + function hairStyle() { + let hairStyleNode = document.createElement('p'); + let label = document.createElement('div'); + label.append(`Custom hair description: `); + + let textbox = App.UI.DOM.makeTextBox( + slave.hStyle, + v => { + slave.hStyle = v; + App.UI.SlaveInteract.custom(slave); + }); + label.appendChild(textbox); + + switch (slave.hStyle) { + case "tails": + case "dreadlocks": + case "cornrows": + label.append(` "${His} hair is in ${slave.hStyle}."`); + break; + case "ponytail": + label.append(` "${His} hair is in a ${slave.hStyle}."`); + break; + default: + label.append(` "${His} hair is ${slave.hStyle}."`); + break; + } + hairStyleNode.appendChild(label); + + let choices = document.createElement('div'); + choices.className = "choices"; + choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, use a short, uncapitalized and unpunctuated description; for example: 'back in a ponytail'`, 'note')); + hairStyleNode.appendChild(choices); + return hairStyleNode; + } + + function hairColor() { + let hairStyleNode = document.createElement('p'); + let label = document.createElement('div'); + label.append(`Custom hair color: `); + + let textbox = App.UI.DOM.makeTextBox( + slave.hColor, + v => { + slave.hColor = v; + App.UI.SlaveInteract.custom(slave); + }); + label.appendChild(textbox); + label.append(` "${His} hair is ${slave.hColor}."`); + hairStyleNode.appendChild(label); + + let choices = document.createElement('div'); + choices.className = "choices"; + choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, use a short, uncapitalized and unpunctuated description; for example: 'black with purple highlights'`, 'note')); + hairStyleNode.appendChild(choices); + return hairStyleNode; + } + } + + /** + * @param {App.Entity.SlaveState} slave + */ + function eyeColor(slave) { + let eyeColorNode = document.createElement('p'); + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + hers, + himself, + boy, + He, + His + } = getPronouns(slave); + let label = document.createElement('div'); + if (getLenseCount(slave) > 0) { + label.textContent = `${He} is wearing ${App.Desc.eyesColor(slave, "", "lense", "lenses")}.`; + } else { + label.textContent = `${He} has ${App.Desc.eyesColor(slave)}.`; + } + eyeColorNode.appendChild(label); + + let choices = document.createElement('div'); + choices.className = "choices"; + + let eye; + let textbox; + + if (hasLeftEye(slave)) { + eye = document.createElement('div'); + eye.append(`Custom left eye color: `); + textbox = App.UI.DOM.makeTextBox( + slave.eye.left.iris, + v => { + slave.eye.left.iris = v; + App.UI.SlaveInteract.custom(slave); + }); + eye.appendChild(textbox); + choices.appendChild(eye); + } + if (hasRightEye(slave)) { + eye = document.createElement('div'); + eye.append(`Custom right eye color: `); + textbox = App.UI.DOM.makeTextBox( + slave.eye.right.iris, + v => { + slave.eye.right.iris = v; + App.UI.SlaveInteract.custom(slave); + }); + eye.appendChild(textbox); + choices.appendChild(eye); + } + choices.appendChild(App.UI.DOM.makeElement('span', `For best results, use a short, uncapitalized and unpunctuated description; for example: 'blue'`, 'note')); + eyeColorNode.appendChild(choices); + return eyeColorNode; + } + + /** + * @param {App.Entity.SlaveState} slave + */ + function customTattoo(slave) { + let el = document.createElement('p'); + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + hers, + himself, + boy, + He, + His + } = getPronouns(slave); + el.append(`Change ${his} custom tattoo: `); + el.appendChild(App.UI.DOM.makeTextBox( + slave.custom.tattoo, + v => { + slave.custom.tattoo = v; + App.UI.SlaveInteract.custom(slave); + })); + + let choices = document.createElement('div'); + choices.className = "choices"; + choices.appendChild(App.UI.DOM.makeElement('span', `For best results, use complete sentences; for example: '${He} has blue stars tattooed along ${his} cheekbones.'`, 'note')); + el.appendChild(choices); + + return el; + } + + function customOriginStory(slave) { + let el = document.createElement('p'); + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + hers, + himself, + boy, + He, + His + } = getPronouns(slave); + + el.append(`Change ${his} origin story: `); + el.appendChild(App.UI.DOM.makeTextBox( + slave.origin, + v => { + slave.origin = v; + App.UI.SlaveInteract.custom(slave); + })); + + let choices = document.createElement('div'); + choices.className = "choices"; + choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, use complete, capitalized and punctuated sentences; for example: '${He} followed you home from the pet store.'`, 'note')); + el.appendChild(choices); + + return el; + } + + function customDescription(slave) { + let el = document.createElement('p'); + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + hers, + himself, + boy, + He, + His + } = getPronouns(slave); + + el.append(`Change ${his} custom description: `); + el.appendChild(App.UI.DOM.makeTextBox( + pronounsForSlaveProp(slave, slave.custom.desc), + v => { + slave.custom.desc = v; + App.UI.SlaveInteract.custom(slave); + })); + + let choices = document.createElement('div'); + choices.className = "choices"; + choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, use complete, capitalized and punctuated sentences; for example: '${He} has a beauty mark above ${his} left nipple.'`, 'note')); + el.appendChild(choices); + + return el; + } + + function customLabel(slave) { + let el = document.createElement('p'); + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + hers, + himself, + boy, + He, + His + } = getPronouns(slave); + + el.append(`Change ${his} custom label: `); + el.appendChild(App.UI.DOM.makeTextBox( + slave.custom.label, + v => { + slave.custom.label = v; + App.UI.SlaveInteract.custom(slave); + })); + + let choices = document.createElement('div'); + choices.className = "choices"; + choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, use a short phrase; for example: 'Breeder.'`, 'note')); + el.appendChild(choices); + + return el; + } + + + function customSlaveImage(slave) { + let el = document.createElement('p'); + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + hers, + himself, + boy, + He, + His + } = getPronouns(slave); + el.append(`Assign ${him} a custom image: `); + + let textbox = document.createElement("INPUT"); + textbox.id = "customImageValue"; + el.appendChild(textbox); + + + let kbd = document.createElement('kbd'); + let select = document.createElement('SELECT'); + select.id = "customImageFormatSelector"; + select.style.border = "none"; + + let filetypes = [ + "png", + "jpg", + "gif", + "webm", + "webp", + "mp4" + ]; + + filetypes.forEach((fileType) => { + let el = document.createElement('OPTION'); + el.value = fileType; + el.text = fileType.toUpperCase(); + select.add(el); + }); + kbd.append(`.`); + kbd.appendChild(select); + el.appendChild(kbd); + + el.appendChild( + App.UI.DOM.link( + ` Reset`, + () => { + slave.custom.image = null; + App.UI.SlaveInteract.custom(slave); + App.Art.refreshSlaveArt(slave, 3, "art-frame"); + }, + ) + ); + + let choices = document.createElement('div'); + choices.className = "choices"; + let note = document.createElement('span'); + note.className = "note"; + note.append(`Place file in the `); + + kbd = document.createElement('kbd'); + kbd.append(`resources`); + note.appendChild(kbd); + + note.append(` folder. Choose the extension from the menu first, then enter the filename in the space and press enter. For example, for a file with the path `); + + kbd = document.createElement('kbd'); + kbd.textContent = `\\bin\\resources\\headgirl.`; + let filetypeDesc = document.createElement('span'); + filetypeDesc.id = "customImageFormatValue"; + filetypeDesc.textContent = "png"; + kbd.appendChild(filetypeDesc); + note.appendChild(kbd); + + note.append(`, choose `); + + kbd = document.createElement('kbd'); + kbd.textContent = `PNG`; + note.appendChild(kbd); + + note.append(` then enter `); + + kbd = document.createElement('kbd'); + kbd.textContent = `headgirl`; + note.appendChild(kbd); + + note.append(`.`); + choices.appendChild(note); + el.appendChild(choices); + + jQuery(function() { + function activeSlave() { + return slave; + } + + jQuery("#customImageFormatValue").text(activeSlave().custom.image === null ? "png" : activeSlave().custom.image.format); + jQuery("#customImageValue") + .val(activeSlave().custom.image === null ? + "" : activeSlave().custom.image.filename) + .on("change", function(e) { + const c = activeSlave().custom; + if (this.value.length === 0) { + c.image = null; + } else { + if (c.image === null) { + c.image = { + filename: this.value, + format: jQuery("#customImageFormatSelector").val() + }; + App.Art.refreshSlaveArt(slave, 3, "art-frame"); + } else { + c.image.filename = this.value; + App.Art.refreshSlaveArt(slave, 3, "art-frame"); + } + } + }); + jQuery("#customImageFormatSelector") + .val(activeSlave().custom.image ? activeSlave().custom.image.format : "png") + .on("change", function(e) { + if (activeSlave().custom.image !== null) { + activeSlave().custom.image.format = this.value; + } + jQuery("#customImageFormatValue").text(this.value); + }); + }); + return el; + } + + function customHairImage(slave) { + let el = document.createElement('p'); + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + hers, + himself, + boy, + He, + His + } = getPronouns(slave); + + if (V.seeImages === 1 && V.imageChoice === 1) { + if (!slave.custom.hairVector) { + slave.custom.hairVector = 0; + } + el.append(`Assign ${him} a custom hair SVG image: `); + + el.appendChild(App.UI.DOM.makeTextBox( + slave.custom.hairVector, + v => { + slave.custom.hairVector = v; + App.UI.SlaveInteract.custom(slave); + })); + + el.appendChild( + App.UI.DOM.link( + ` Reset`, + () => { + slave.custom.hairVector = 0; + App.UI.SlaveInteract.custom(slave); + App.Art.refreshSlaveArt(slave, 3, "art-frame"); + }, + ) + ); + } + + return el; + } +})(); diff --git a/src/interaction/siDescription.js b/src/interaction/siDescription.js new file mode 100644 index 0000000000000000000000000000000000000000..50e62da56199304467ca45e263a5966d28c7cd75 --- /dev/null +++ b/src/interaction/siDescription.js @@ -0,0 +1,61 @@ +App.UI.SlaveInteract.description = function(slave) { + const el = document.createElement("p"); + el.id = "si-description"; + el.append(description()); + return el; + + function description() { + const el = new DocumentFragment(); + const descriptionLink = document.createElement("div"); + descriptionLink.style.fontStyle = "italic"; + descriptionLink.id = "description-link"; + if (V.seeDetails === 1) { + descriptionLink.append(showOptions()); + el.append(descriptionLink); + + const descriptionOptions = document.createElement("div"); + descriptionOptions.id = "description-options"; + el.append(descriptionOptions); + + el.append(App.Desc.longSlave(getSlave(V.AS), {noArt: true})); + } else { + descriptionLink.append( + App.UI.DOM.link( + "Show descriptions", + () => { + V.seeDetails = 1; + }, + [], + "Slave Interact" + ) + ); + el.append(descriptionLink); + } + + + return el; + + function showOptions() { + return App.UI.DOM.link( + "Description Options", + () => { + jQuery("#description-link").empty().append(hideOptions()); + jQuery("#description-options").empty().append(App.UI.DOM.renderPassage("Description Options")); + } + ); + } + + function hideOptions() { + return App.UI.DOM.link( + "Description Options", + () => { + jQuery("#description-link").empty().append(showOptions()); + jQuery("#description-options").empty().append(); + } + ); + } + } + function refresh() { + jQuery("#si-description").empty().append(description()); + } +}; diff --git a/src/interaction/siFamily.js b/src/interaction/siFamily.js new file mode 100644 index 0000000000000000000000000000000000000000..da003bb94def359a83b82d877523987eeba05c97 --- /dev/null +++ b/src/interaction/siFamily.js @@ -0,0 +1,18 @@ +/** + * @returns {HTMLParagraphElement} + */ +App.UI.SlaveInteract.family = function() { + let element; + const p = document.createElement("p"); + p.id= "family"; + + element = document.createElement("div"); + element.id = "family-tree"; + p.append(element); + + element = document.createElement("span"); + element.id = "family-tree-link"; + p.append(element); + + return p; +}; diff --git a/src/interaction/siFinancial.js b/src/interaction/siFinancial.js new file mode 100644 index 0000000000000000000000000000000000000000..8a278a7ea6fdc2cd83381d3b5ddb9e9d757c714c --- /dev/null +++ b/src/interaction/siFinancial.js @@ -0,0 +1,251 @@ +App.UI.SlaveInteract.financial = function(slave) { + const el = document.createElement("div"); + el.id = "si-financial"; + el.append(financialContent()); + return el; + + function financialContent() { + const el = new DocumentFragment(); + let r = []; + let linkArray; + const { + He, His, + his, him + } = getPronouns(slave); + if (V.studio === 1) { + App.UI.DOM.appendNewElement("h3", el, "Media"); + slave.porn.spending = Math.clamp(Math.ceil(slave.porn.spending / 1000) * 1000, 0, 5000); + if (slave.porn.prestige === 3) { + r.push( + App.UI.DOM.makeElement("div", `${He} is so prestigious in the realm of ${slave.porn.fameType} porn that ${his} fame is self-sustaining.`, "note") + ); + } else if (slave.porn.feed === 0) { + r.push(`The media hub is not releasing highlights of ${his} sex life.`); + r.push( + App.UI.DOM.link( + "Release", + () => { + slave.porn.feed = 1; + refresh(); + } + ) + ); + } else { + r.push(`The media hub is releasing highlights of ${his} sex life`); + if (slave.porn.spending < 500) { + r.push(`to those who can find it.`); + } else if (slave.porn.spending < 2500) { + r.push(`on several websites.`); + } else if (slave.porn.spending > 5000) { + r.push(`through your old distributor.`); + } else { + r.push(`on many websites.`); + } + if (slave.porn.spending === 0) { + linkArray = []; + linkArray.push( + App.UI.DOM.link( + "Halt", + () => { + slave.porn.feed = 0; + slave.porn.focus = "none"; + refresh(); + } + ) + ); + linkArray.push( + App.UI.DOM.link( + "Publicize", + () => { + slave.porn.spending += 1000; + refresh(); + }, + [], + "", + `Will cost ${cashFormat(1000)} weekly.` + ) + ); + r.push(App.UI.DOM.generateLinksStrip(linkArray)); + } else { + r.push( + App.UI.DOM.makeTextBox( + slave.porn.spending, + v => { + slave.porn.spending = v; + }, + true + ) + ); + r.push(`weekly is spent to publicize them.`); + + linkArray = []; + linkArray.push( + App.UI.DOM.link( + "Halt", + () => { + slave.porn.spending = 0; + slave.porn.feed = 0; + slave.porn.focus = "none"; + V.PCSlutContacts = 1; + refresh(); + } + ) + ); + if (slave.porn.spending <= 4000) { + linkArray.push( + App.UI.DOM.link( + "Increase", + () => { + slave.porn.spending += 1000; + refresh(); + }, + [], + "", + `Spending more than ${cashFormat(5000)} weekly will have no effect.` + ) + ); + } + linkArray.push( + App.UI.DOM.link( + "Decrease", + () => { + slave.porn.spending -= 1000; + refresh(); + }, + [], + "", + `Will cost ${cashFormat(1000)} weekly.` + ) + ); + r.push(App.UI.DOM.generateLinksStrip(linkArray)); + App.Events.addNode(el, r, "div"); + + if (V.PC.career === "escort") { + App.Events.addNode(el, r, "div"); + r = []; + r.push(`You retain some contacts from your past life in the industry that may be willing to cut you some discounts should you return to it.`); + if (V.PCSlutContacts !== 2) { + r.push(`You are not baring your body for all to see.`); + r.push( + App.UI.DOM.link( + `Star in porn for a discount`, + () => { + V.PCSlutContacts = 2; + refresh(); + } + ) + ); + } else { + r.push(`You are starring in hardcore porn once more.`); + r.push( + App.UI.DOM.link( + `Stop doing porn for a discount`, + () => { + V.PCSlutContacts = 1; + refresh(); + } + ) + ); + } + } + } + if (V.studioFeed === 1) { + App.Events.addNode(el, r, "div"); + r = []; + if (slave.porn.viewerCount < 100) { + r.push(`${He} lacks the fame in porn needed to discern what ${his} feed is getting tagged as.`); + } else { + if (slave.porn.prestige > 0) { + r.push(`${He} is known for ${slave.porn.fameType}${(slave.porn.prestige > 1) ? ` and viewers have grown to expect it from ${him}` : ``}.`); + } + if (slave.porn.focus === "none") { + r.push(`You are allowing ${his} viewers to guide the direction of ${his} content.`); + } else { + r.push(`You are focusing attention on the ${slave.porn.focus} aspect of ${his} content.`); + } + r.push(App.Porn.genreChoiceLinks("Slave Interact", slave)); + } + } + } + App.Events.addNode(el, r, "div"); + } + App.UI.DOM.appendNewElement("h3", el, "Financial"); + App.UI.DOM.appendNewElement("p", el, slaveExpenses(slave)); + + r = []; + linkArray = []; + if (V.slaveCostFactor > 1) { + r.push(App.UI.DOM.makeElement("span", `The slave market is bullish; the price of slaves is high.`, "yellow")); + } else if ((V.slaveCostFactor < 1)) { + r.push(App.UI.DOM.makeElement("span", `The slave market is bearish; the price of slaves is low.`, "yellow")); + } + + if (V.slaves.length < 2) { + r.push("You cannot sell your last save"); + } else if (slave.origin === "You bought ${him} from a body dump, completely broken." && (V.week - slave.weekAcquired <= 8)) { + r.push(`A discarded slave must be kept for at least two months to ensure health before being sold.`); + } else if (slave.accent > 3) { + r.push(`${His} lack of language and basic life skills is a red sign to most slave appraisers. ${He} must not act like a child to be sold without raising suspicion.`); + } else { + linkArray.push( + App.UI.DOM.link( + `Sell ${him}`, + () => { + cashX(-500, "personalBusiness", slave); + }, + [], + "Sell Slave", + `Listing ${him} for sale will cost ${cashFormat(500)}` + ) + ); + if ((V.seeAge !== 0) && (slave.indenture < 1)) { + linkArray.push( + App.UI.DOM.link( + `Retire ${him}`, + () => { + V.retiree = slave.ID; + V.retired = 1; + }, + [], + "SE retirement", + ) + ); + } + linkArray.push( + App.UI.DOM.passageLink( + `Discard ${him}`, + "Discard Confirm", + ) + ); + if (V.seeExtreme === 1 && V.arcologies[0].FSPaternalist === "unset") { + linkArray.push( + App.UI.DOM.passageLink( + `Threaten ${his} life`, + "KillSlave", + ) + ); + } + } + linkArray.push( + App.UI.DOM.passageLink( + `Export this slave`, + "Export this slave", + ) + ); + if (V.cheatMode) { + linkArray.push( + App.UI.DOM.passageLink( + `Import a slave`, + "Import Slave", + ) + ); + } + r.push(App.UI.DOM.generateLinksStrip(linkArray)); + App.Events.addNode(el, r, "p"); + return el; + } + + function refresh() { + jQuery("#si-financial").empty().append(financialContent()); + } +}; diff --git a/src/interaction/siModify.js b/src/interaction/siModify.js new file mode 100644 index 0000000000000000000000000000000000000000..11f52477e4c8a234ff52ad57aa030ba2f5984a52 --- /dev/null +++ b/src/interaction/siModify.js @@ -0,0 +1,59 @@ +/** + * @param {App.Entity.SlaveState} slave + * @returns {Node} + */ +App.UI.SlaveInteract.modify = function(slave) { + const {he, his} = getPronouns(slave); + let el = new DocumentFragment(); + + const isAgent = [Job.AGENT, Job.AGENTPARTNER].includes(slave.assignment); + + App.UI.DOM.appendNewElement('p', el, isAgent ? "Recall your agent to modify them." : "Take slave to another room.", "scene-intro"); + + if (isAgent) { + return el; + } + + /** + * Create a link with a note to send a slave to a specific room + * @param {Node} c + * @param {string} caption + * @param {string} passage + * @param {string} note + * @param {function ():void} [handler] + */ + function makeRoomLink(c, caption, passage, note, handler = () => {}) { + const res = document.createElement('div'); + c.appendChild(res); + res.appendChild(App.UI.DOM.link(caption, handler, [], passage)); + App.UI.DOM.appendNewElement('span', res, note, "note"); + return res; + } + + makeRoomLink(el, "Auto salon", "Salon", ' Modify hair (color, length, style), nails, and even skin color.'); + + makeRoomLink(el, "Body mod studio", "Body Modification", ' Mark your slave with piercings, tattoos, brands or even scars.', + () => { + V.degradation = 0; + V.tattooChoice = undefined; + }, + ); + + makeRoomLink(el, "Remote surgery", "Remote Surgery", ` Surgically modify your slave with state of the art plastic surgery and more. Alter ${his} senses, skeletal structure, organs, and even more.`); + + // Prosthetics + if (V.prostheticsUpgrade > 0) { + makeRoomLink(el, "Configure cybernetics", "Prosthetics Configuration", ` Configure prosthetics, if ${he} has been surgically implanted with interfaces that support it.`, + () => { + V.prostheticsConfig = "main"; + } + ); + } + + // Analyze Pregnancy + if (V.pregnancyMonitoringUpgrade > 0) { + makeRoomLink(el, "Internal scan", "Analyze Pregnancy", ` Full scan of abdomen and reproductive organs.`); + } + + return el; +}; \ No newline at end of file diff --git a/src/interaction/siNavigation.js b/src/interaction/siNavigation.js new file mode 100644 index 0000000000000000000000000000000000000000..c7bfe5e5b0aece2af05aeff67fd3c50636a847f9 --- /dev/null +++ b/src/interaction/siNavigation.js @@ -0,0 +1,63 @@ + + +/** + * @param {App.Entity.SlaveState} slave + * @returns {HTMLParagraphElement} + */ +App.UI.SlaveInteract.navigation = function(slave) { + const p = document.createElement("p"); + p.classList.add("center"); + + if (V.cheatMode) { + const div = document.createElement("div"); + div.classList.add("note"); + div.append(App.UI.DOM.passageLink("Cheat Edit Slave", "MOD_Edit Slave Cheat", () => { V.cheater = 1; }), + " | ", + App.UI.DOM.passageLink("Cheat Edit Slave Alternative", "MOD_Edit Slave Cheat New", () => { V.cheater = 1; })); + p.append(div); + } + + App.UI.DOM.appendNewElement("span", p, App.UI.Hotkeys.hotkeys("prev-slave"), "hotkey"); + const prevSpan = App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Prev", "Slave Interact", + () => { V.AS = App.UI.SlaveInteract.placeInLine(slave)[0]; }), "adjacent-slave"); + prevSpan.id = "prev-slave"; + p.append(" ", prevSpan); + + const centerSpan = document.createElement("span"); + centerSpan.classList.add("interact-name"); + + App.UI.DOM.appendNewElement("span", centerSpan, slave.slaveName, "slave-name"); + + const favSpan = document.createElement("span"); + favSpan.id = "fav-span"; + favSpan.append(favLink()); + + centerSpan.append(" ", favSpan); + p.append(centerSpan); + + const nextSpan = App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Next", "Slave Interact", + () => { V.AS = App.UI.SlaveInteract.placeInLine(slave)[1]; }), "adjacent-slave"); + nextSpan.id = "next-slave"; + p.append(nextSpan, " "); + App.UI.DOM.appendNewElement("span", p, App.UI.Hotkeys.hotkeys("next-slave"), "hotkey"); + + return p; + + function favLink() { + if (V.favorites.includes(slave.ID)) { + const link = App.UI.DOM.link(String.fromCharCode(0xe800), () => { + V.favorites.delete(slave.ID); + App.UI.DOM.replace("#fav-span", favLink()); + }); + link.classList.add("icons", "favorite"); + return link; + } else { + const link = App.UI.DOM.link(String.fromCharCode(0xe801), () => { + V.favorites.push(slave.ID); + App.UI.DOM.replace("#fav-span", favLink()); + }); + link.classList.add("icons", "not-favorite"); + return link; + } + } +}; diff --git a/src/interaction/siPhysicalRegimen.js b/src/interaction/siPhysicalRegimen.js new file mode 100644 index 0000000000000000000000000000000000000000..e7086dbd03e0c6cec08e797edc4af755100bf315 --- /dev/null +++ b/src/interaction/siPhysicalRegimen.js @@ -0,0 +1,1052 @@ +App.UI.SlaveInteract.physicalRegimen = function(slave) { + const el = document.createElement("p"); + el.id = "si-physical-regimen"; + el.append(physicalRegimenContent()); + return el; + + function physicalRegimenContent() { + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + himself, + He, + His + } = getPronouns(slave); + const el = new DocumentFragment(); + el.append(drugs()); + el.append(curatives()); + el.append(aphrodisiacs()); + el.append(fertility()); + el.append(incubator()); + el.append(nursery()); + el.append(breederEligibility()); + el.append(bloating()); + el.append(hormones()); + el.append(diet()); + el.append(dietBase()); + el.append(snacks()); + return el; + + function drugs() { + let el = document.createElement('div'); + + const drugLevelOptions = []; + const lips = []; + const breasts = []; + const nipples = []; + const butt = []; + const dick = []; + const balls = []; + const fertility = []; + const hormones = []; + const psych = []; + const misc = []; + + if (slave.drugs !== "no drugs") { + drugLevelOptions.push({text: `None`, updateSlave: {drugs: `no drugs`}}); + } + if (slave.indentureRestrictions < 2) { + // Psych + if (slave.intelligence > -100 && slave.indentureRestrictions < 1) { + psych.push({text: `Psychosuppressants`, updateSlave: {drugs: `psychosuppressants`}}); + } else if (slave.intelligence > -100) { + psych.push({text: `Psychosuppressants`, disabled: `Cannot suppress indentured slave`}); + } else if (slave.indentureRestrictions < 1) { + psych.push({text: `Psychosuppressants`, disabled: `Too stupid to suppress`}); + } else { + psych.push({text: `Psychosuppressants`, disabled: `Too stupid and indentured to suppress`}); + } + if (V.arcologies[0].FSSlaveProfessionalismResearch === 1) { + if (canImproveIntelligence(slave)) { + psych.push({text: `Psychostimulants`, updateSlave: {drugs: `psychostimulants`}}); + } else { + psych.push({text: `Psychostimulants`, disabled: `Cannot improve intelligence`}); + } + } + + // Breasts + if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { + if ((slave.boobs - slave.boobsImplant - slave.boobsMilk) > 100) { + breasts.push({text: `Reducers`, updateSlave: {drugs: `breast redistributors`}}); + } else { + breasts.push({text: `Reducers`, disabled: `Boobs are too small`}); + } + } + if (slave.boobs < 50000) { + breasts.push({text: `Enhancement`, updateSlave: {drugs: `breast injections`}}); + breasts.push({text: `Intensive enhancement`, updateSlave: {drugs: `intensive breast injections`}}); + } else { + breasts.push({text: `Enhancement`, disabled: `Boobs are too large`}); + } + if (V.arcologies[0].FSAssetExpansionistResearch === 1) { + if (slave.boobs < 50000) { + breasts.push({text: `Hyper enhancement`, updateSlave: {drugs: `hyper breast injections`}}); + } else { + breasts.push({text: `Hyper enhancement`, disabled: `Boobs are too large`}); + } + } + + // Nipples + if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { + if (slave.nipples === "huge" || slave.nipples === "puffy" || slave.nipples === "cute") { + nipples.push({text: `Reducers`, updateSlave: {drugs: `nipple atrophiers`}}); + } else { + nipples.push({text: `Reducers`, disabled: `Nipples are ${slave.nipples}`}); + } + } + if (V.dispensary) { + if (["inverted", "partially inverted", "cute", "tiny", "puffy"].includes(slave.nipples)) { + nipples.push({text: `Enhancement`, updateSlave: {drugs: `nipple enhancers`}}); + } else if (slave.nipples === "huge") { + nipples.push({text: `Enhancement`, disabled: `Nipples are already huge`}); + } else { + nipples.push({text: `Enhancement`, disabled: `Has no effect on ${slave.nipples} nipples`}); + } + } + + // Butt + if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { + if (slave.butt - slave.buttImplant > 0) { + butt.push({text: `Reducers`, updateSlave: {drugs: `butt redistributors`}}); + } else { + butt.push({text: `Reducers`, disabled: `Butt is too small`}); + } + } + if (slave.butt < 9) { + butt.push({text: `Enhancement`, updateSlave: {drugs: `butt injections`}}); + butt.push({text: `Intensive enhancement`, updateSlave: {drugs: `intensive butt injections`}}); + } else { + butt.push({text: `Enhancement`, disabled: `Butt is too large`}); + } + if (V.arcologies[0].FSAssetExpansionistResearch === 1) { + if (slave.butt < 20) { + butt.push({text: `Hyper enhancement`, updateSlave: {drugs: `hyper butt injections`}}); + } else { + butt.push({text: `Hyper enhancement`, disabled: `Butt is too large`}); + } + } + + // Lips + if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { + if (slave.lips - slave.lipsImplant > 0) { + lips.push({text: `Reducers`, updateSlave: {drugs: `lip atrophiers`}}); + } else { + lips.push({text: `Reducers`, disabled: `Lips are too small`}); + } + } + if (slave.lips <= 95 || (slave.lips <= 85 && V.seeExtreme !== 1)) { + lips.push({text: `Enhancement`, updateSlave: {drugs: `lip injections`}}); + } else { + lips.push({text: `Enhancement`, disabled: `Lips are too large`}); + } + + // Fertility + fertility.push({text: `Fertility`, updateSlave: {drugs: `fertility drugs`}}); + if (V.seeHyperPreg === 1 && slave.indentureRestrictions < 1 && V.superFertilityDrugs === 1 && (slave.breedingMark !== 1 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) { + fertility.push({text: `Fertility+`, updateSlave: {drugs: `super fertility drugs`}}); + } + + // Dick/clit + if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { + if (slave.dick > 1) { + dick.push({text: `Reducers`, updateSlave: {drugs: `penis atrophiers`}}); + } else if (slave.dick === 1) { + dick.push({text: `Reducers`, disabled: `Dick is already at minimum size`}); + } + if (slave.clit > 0) { + dick.push({text: `Reducers`, updateSlave: {drugs: `clitoris atrophiers`}}); + } + } + if (slave.dick > 0) { + if (slave.dick < 10) { + dick.push({text: `Enhancement`, updateSlave: {drugs: `penis enhancement`}}); + dick.push({text: `Intensive enhancement`, updateSlave: {drugs: `intensive penis enhancement`}}); + } else { + dick.push({text: `Enhancement`, disabled: `Dick is too large`}); + } + } else { + if (slave.clit < 5) { + dick.push({text: `Enhancement`, updateSlave: {drugs: `penis enhancement`}}); + dick.push({text: `Intensive enhancement`, updateSlave: {drugs: `intensive penis enhancement`}}); + } else { + dick.push({text: `Enhancement`, disabled: `Clit is too large`}); + } + } + if (V.arcologies[0].FSAssetExpansionistResearch === 1) { + if (slave.dick > 0) { + if (slave.dick < 31) { + dick.push({text: `Hyper enhancement`, updateSlave: {drugs: `hyper penis enhancement`}}); + } else { + dick.push({text: `Hyper enhancement`, disabled: `Dick is too large`}); + } + } else { + if (slave.clit < 5) { + dick.push({text: `Hyper enhancement`, updateSlave: {drugs: `penis enhancement`}}); + } else { + dick.push({text: `Hyper enhancement`, disabled: `Clit is too large`}); + } + } + } + if (slave.dick > 0 && slave.dick < 11 && !canAchieveErection(slave) && slave.chastityPenis !== 1) { + dick.push({text: `Erectile dysfunction circumvention`, updateSlave: {drugs: `priapism agents`}}); + } + + // Balls + if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { + if (slave.balls > 1) { + balls.push({text: `Reducers`, updateSlave: {drugs: `testicle atrophiers`}}); + } else if (slave.balls === 1) { + balls.push({text: `Reducers`, disabled: `Balls are already at minimum size`}); + } + } + if (slave.balls > 0) { + balls.push({text: `Enhancement`, updateSlave: {drugs: `testicle enhancement`}}); + balls.push({text: `Intensive enhancement`, updateSlave: {drugs: `intensive testicle enhancement`}}); + if (V.arcologies[0].FSAssetExpansionistResearch === 1) { + balls.push({text: `Hyper enhancement`, updateSlave: {drugs: `hyper testicle enhancement`}}); + } + } + + // Hormones + if (V.precociousPuberty === 1 && V.pubertyHormones === 1 && (slave.breedingMark !== 1 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) { + if ((slave.ovaries === 1 || slave.mpreg === 1) && slave.pubertyXX === 0) { + hormones.push({text: `Female injections`, updateSlave: {drugs: `female hormone injections`}}); + } + if (slave.balls > 0 && slave.pubertyXY === 0) { + hormones.push({text: `Male injections`, updateSlave: {drugs: `male hormone injections`}}); + } + } + hormones.push({text: `Blockers`, updateSlave: {drugs: `hormone blockers`}}); + hormones.push({text: `Enhancement`, updateSlave: {drugs: `hormone enhancers`}}); + + // Misc + if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { + if (slave.labia > 0) { + misc.push({text: `Labia reducers`, updateSlave: {drugs: `labia atrophiers`}}); + } + } + if (V.growthStim === 1) { + if (canImproveHeight(slave)) { + misc.push({text: `Growth Stimulants`, updateSlave: {drugs: `growth stimulants`}}); + } else { + misc.push({text: `Growth Stimulants`, disabled: `Cannot increase height further`}); + } + } + if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { + if (slave.weight > -95) { + misc.push({text: `Weight loss pills`, updateSlave: {drugs: `appetite suppressors`}}); + } else { + misc.push({text: `Weight loss pills`, disabled: `Slave is already at low weight`}); + } + } + misc.push({text: `Steroids`, updateSlave: {drugs: `steroids`}}); + if (slave.boobs > 250 && slave.boobShape !== "saggy" && V.purchasedSagBGone === 1) { + misc.push({text: `Sag-B-Gone breast lifting cream`, updateSlave: {drugs: `sag-B-gone`}}); + } + if (V.arcologies[0].FSYouthPreferentialistResearch === 1) { + if (slave.visualAge > 18) { + misc.push({text: `Anti-aging cream`, updateSlave: {drugs: `anti-aging cream`}}); + } else { + misc.push({text: `Anti-aging cream`, disabled: `Slave already looks young enough`}); + } + } + } + + let title = document.createElement('div'); + title.textContent = `Drugs: `; + let chosenDrug = document.createElement('span'); + chosenDrug.textContent = `${capFirstChar(slave.drugs)}. `; + chosenDrug.style.fontWeight = "bold"; + title.append(chosenDrug); + title.appendChild(App.UI.SlaveInteract.generateRows(drugLevelOptions, slave, "", false, refresh)); + el.append(title); + + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Lips", lips, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Breasts", breasts, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Nipples", nipples, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Butt", butt, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, slave.dick > 0 ? "Dick" : "Clit", dick, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Balls", balls, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Fertility", fertility, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Hormones", hormones, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Psych", psych, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Misc", misc, slave, refresh); + + return el; + } + + function curatives() { + const curativeOptions = []; + + curativeOptions.push({text: `None`, updateSlave: {curatives: 0}}); + curativeOptions.push({text: `Preventatives`, updateSlave: {curatives: 1}}); + curativeOptions.push({text: `Curatives`, updateSlave: {curatives: 2}}); + + let el = document.createElement('div'); + let title = document.createElement('div'); + title.append(`Health: `); + let chosenOption = document.createElement('span'); + chosenOption.style.fontWeight = "bold"; + if (slave.curatives > 1) { + chosenOption.textContent = `curatives`; + } else if (slave.curatives > 0) { + chosenOption.textContent = `preventatives`; + } else { + chosenOption.textContent = `none`; + } + title.appendChild(chosenOption); + title.append(`.`); + let link = document.createElement('div'); + link.className = "choices"; + link.appendChild(App.UI.SlaveInteract.generateRows(curativeOptions, slave, "", false, refresh)); + el.append(title); + el.append(link); + return el; + } + + function aphrodisiacs() { + const aphrodisiacOptions = []; + + aphrodisiacOptions.push({text: `None`, updateSlave: {aphrodisiacs: 0}}); + aphrodisiacOptions.push({text: `Aphrodisiacs`, updateSlave: {aphrodisiacs: 1}}); + aphrodisiacOptions.push({text: `Extreme aphrodisiacs`, updateSlave: {aphrodisiacs: 2}}); + aphrodisiacOptions.push({text: `Anaphrodisiacs`, updateSlave: {aphrodisiacs: -1}, note: `Suppresses libido`}); + + + let el = document.createElement('div'); + let title = document.createElement('div'); + title.append(`Aphrodisiacs: `); + let chosenOption = document.createElement('span'); + chosenOption.style.fontWeight = "bold"; + if (slave.aphrodisiacs > 1) { + chosenOption.textContent = `extreme`; + } else if (slave.aphrodisiacs > 0) { + chosenOption.textContent = `applied`; + } else if (slave.aphrodisiacs === -1) { + chosenOption.textContent = `anaphrodisiacs`; + } else { + chosenOption.textContent = `none`; + } + title.appendChild(chosenOption); + title.append(`.`); + let link = document.createElement('div'); + link.className = "choices"; + link.appendChild(App.UI.SlaveInteract.generateRows(aphrodisiacOptions, slave, "", false, refresh)); + el.append(title); + el.append(link); + return el; + } + + function fertility() { + let fertilityBlock = document.createElement('span'); + let linkArray = []; + if (slave.ovaries === 1 || slave.mpreg === 1 || slave.preg > 0) { + let note = ""; + if (slave.preg < -1) { + note += `${He} is sterile`; + } else if (slave.pubertyXX === 0 && slave.preg < 1) { + note += `${He} is not yet fertile`; + } else if (slave.ovaryAge >= 47 && slave.preg < 1) { + note += `${He} is too old to become pregnant`; + if (slave.preg === -1) { + slave.preg = 0; + SetBellySize(slave); + } + } else if (slave.broodmotherOnHold === 1) { + note += `${His} pregnancy implant is turned off`; + if (slave.broodmotherCountDown > 0) { + note += `${he} is expected to be completely emptied of ${his} remaining brood in ${slave.broodmotherCountDown} week`; + if (slave.broodmotherCountDown > 1) { + note += `s`; + } + note += `.`; + linkArray.push(App.UI.DOM.link( + `Turn on implant`, + () => { + slave.broodmotherOnHold = 0; + slave.broodmotherCountDown = 0; + refresh(); + }, + )); + } + } else if (slave.preg >= -1) { + fertilityBlock.append("Contraception and fertility: "); + let fertility = ""; + // fertility.id = "fertility"; + if (slave.preg === -1) { + fertility = "using contraceptives"; + } else if (slave.pregWeek < 0) { + fertility = "postpartum"; + } else if (slave.preg === 0) { + fertility = "fertile"; + } else if (slave.preg < 4 && (slave.broodmother === 0 || slave.broodmotherOnHold === 1)) { + fertility = "may be pregnant"; + } else if (slave.preg < 2) { + fertility = "1 week pregnant"; + } else { + fertility = `${Math.trunc(slave.preg * 1000) / 1000} weeks pregnant`; // * and / needed to avoid seeing something like 20.1000000008 in some cases. + if (slave.broodmother > 0) { + fertility += " broodmother"; + } + } + fertility += ". "; + App.UI.DOM.appendNewElement("span", fertilityBlock, fertility, "bold"); + + if (slave.preg === 0) { + linkArray.push(App.UI.DOM.link( + `Use contraceptives`, + () => { + slave.preg = -1; + refresh(); + }, + )); + } else if (slave.preg === -1) { + linkArray.push(App.UI.DOM.link( + `Let ${him} get pregnant`, + () => { + slave.preg = 0; + refresh(); + }, + )); + } else if (isInduced(slave)) { + note += `Hormones are being slipped into ${his} food; ${he} will give birth suddenly and rapidly this week`; + } else if ( + slave.preg > slave.pregData.normalBirth - 2 && + slave.preg > slave.pregData.minLiveBirth && + slave.broodmother === 0 && + !isInLabor(slave) + ) { + linkArray.push(App.UI.DOM.link( + `Induce labor`, + () => { + induce(slave); + refresh(); + }, + )); + linkArray.push(App.UI.DOM.passageLink(`Give ${him} a cesarean section`, "csec")); + } else if (slave.broodmother > 0) { + if (slave.broodmotherOnHold !== 1) { + linkArray.push(App.UI.DOM.link( + `Turn off implant`, + () => { + slave.broodmotherOnHold = 1; + slave.broodmotherCountDown = 38 - WombMinPreg(slave); + refresh(); + }, + )); + } + if (slave.preg > 37) { + linkArray.push(App.UI.DOM.passageLink(`Induce mass childbirth`, "BirthStorm")); + } + } else if (slave.preg > slave.pregData.minLiveBirth) { + linkArray.push(App.UI.DOM.link( + `Give ${him} a cesarean section`, + () => { + slave.broodmotherOnHold = 0; + slave.broodmotherCountDown = 0; + }, + [], + "csec" + )); + } else if (slave.preg > 0 && slave.breedingMark === 1 && V.propOutcome === 1 && V.arcologies[0].FSRestart !== "unset" && V.eugenicsFullControl !== 1 && (slave.pregSource === -1 || slave.pregSource === -6)) { + note += "You are forbidden from aborting an Elite child"; + } else if (slave.preg > 0) { + linkArray.push(App.UI.DOM.link( + `Abort ${his} pregnancy`, + () => { + slave.broodmotherOnHold = 0; + slave.broodmotherCountDown = 0; + }, + [], + "Abort" + )); + } + } + App.UI.DOM.appendNewElement("span", fertilityBlock, note, "note"); + App.UI.DOM.appendNewElement("div", fertilityBlock, App.UI.DOM.generateLinksStrip(linkArray), "choices"); + } + if ( + (slave.pregKnown === 1) && + (V.pregSpeedControl === 1) && + ( + slave.breedingMark !== 1 || + V.propOutcome === 0 || + V.eugenicsFullControl === 1 || + V.arcologies[0].FSRestart === "unset" + ) && + (slave.indentureRestrictions < 1) && + (slave.broodmother === 0) && + V.seePreg !== 0 + ) { + let title = document.createElement('div'); + let underline = document.createElement('span'); + underline.style.textDecoration = "underline"; + underline.textContent = "Pregnancy control"; + title.appendChild(underline); + title.append(": "); + + if (slave.pregControl === "labor suppressors") { + title.append("Labor is suppressed. "); + } else if (slave.pregControl === "slow gestation") { + title.append("Slowed gestation speed. "); + } else if (slave.pregControl === "speed up") { + title.append("Faster gestation speed, staffed clinic recommended. "); + } else { + title.append("Normal gestation and birth. "); + } + fertilityBlock.appendChild(title); + + linkArray = []; + if (slave.pregControl !== "none") { + linkArray.push(App.UI.DOM.link( + `Normal ${slave.preg < slave.pregData.normalBirth ? "Gestation" : "Birth"}`, + () => { + slave.pregControl = "none"; + refresh(); + }, + )); + } + if (slave.preg < slave.pregData.normalBirth) { + if (slave.pregControl !== "slow gestation") { + linkArray.push(App.UI.DOM.link( + `Slow Gestation`, + () => { + slave.pregControl = "slow gestation"; + refresh(); + }, + )); + } + if (slave.pregControl !== "speed up") { + linkArray.push(App.UI.DOM.link( + `Fast Gestation`, + () => { + slave.pregControl = "speed up"; + refresh(); + }, + )); + } + } + if (slave.preg >= slave.pregData.minLiveBirth) { + if (slave.pregControl !== "labor suppressors") { + linkArray.push(App.UI.DOM.link( + `Suppress Labor`, + () => { + slave.pregControl = "labor suppressors"; + refresh(); + }, + )); + } + } + App.UI.DOM.appendNewElement("div", fertilityBlock, App.UI.DOM.generateLinksStrip(linkArray), "choices"); + } + return fertilityBlock; + } + + function incubator() { + V.reservedChildren = FetusGlobalReserveCount("incubator"); + let _reservedIncubator = WombReserveCount(slave, "incubator"); + let _reservedNursery = WombReserveCount(slave, "nursery"); + let _WL = slave.womb.length; + let el = document.createElement('div'); + + if (V.incubator > 0) { + if (slave.preg > 0 && slave.broodmother === 0 && slave.pregKnown === 1 && slave.eggType === "human") { + if ((slave.assignment !== Job.DAIRY || V.dairyPregSetting === 0) && (slave.assignment !== Job.FARMYARD || V.farmyardBreeding === 0)) { + let title = document.createElement('div'); + let link = document.createElement('div'); + link.className = "choices"; + if (_WL - _reservedNursery === 0) { + title.textContent = `${His} children are already reserved for ${V.nurseryName}`; + title.style.fontStyle = "italic"; + } else { + const freeTanks = (V.incubator - V.tanks.length); + if (_reservedIncubator > 0) { + if (_WL === 1) { + title.textContent = `${His} child will be placed in ${V.incubatorName}. `; + } else if (_reservedIncubator < _WL) { + title.textContent = `${_reservedIncubator} of ${his} children will be placed in ${V.incubatorName}.`; + } else if (_WL === 2) { + title.textContent = `Both of ${his} children will be placed in ${V.incubatorName}. `; + } else { + title.textContent = `All ${_reservedIncubator} of ${his} children will be placed in ${V.incubatorName}. `; + } + if ((_reservedIncubator + _reservedNursery < _WL) && (V.reservedChildren < freeTanks)) { + link.appendChild( + App.UI.DOM.link(`Keep another child`, () => wombUpdateIncubator(1, true)) + ); + if (_reservedIncubator > 0) { + link.append(` | `); + link.appendChild( + App.UI.DOM.link(`Keep one less child`, () => wombUpdateIncubator(1, false)) + ); + } + if (_reservedIncubator > 1) { + link.append(` | `); + link.appendChild( + App.UI.DOM.link(`Keep none of ${his} children`, () => wombUpdateIncubator(9999, false)) + ); + } + if ((V.reservedChildren + _WL - _reservedIncubator) <= freeTanks) { + link.append(` | `); + link.appendChild( + App.UI.DOM.link(`Keep the rest of ${his} children`, () => wombUpdateIncubator(9999, true)) + ); + } + } else if ((_reservedIncubator === _WL) || (V.reservedChildren === freeTanks) || (_reservedIncubator - _reservedNursery >= 0)) { + link.appendChild( + App.UI.DOM.link(`Keep one less child`, () => wombUpdateIncubator(1, false)) + ); + if (_reservedIncubator > 1) { + link.append(` | `); + link.appendChild( + App.UI.DOM.link(`Keep none of ${his} children`, () => wombUpdateIncubator(9999, false)) + ); + } + } + } else if (V.reservedChildren < freeTanks) { + title.textContent = `${He} is pregnant and you have `; + if (freeTanks === 1) { + title.textContent += `an `; + } + let tank = document.createElement('span'); + tank.className = "lime"; + tank.textContent = `available aging tank`; + if (freeTanks > 1) { + tank.textContent += `s`; + } + tank.textContent += `.`; + let _cCount = (_WL > 1 ? "a" : "the"); + link.appendChild( + App.UI.DOM.link(`Keep ${_cCount} child`, () => wombUpdateIncubator(1, true)) + ); + title.appendChild(tank); + if ((_WL > 1) && (V.reservedChildren + _WL) <= freeTanks) { + link.append(` | `); + link.appendChild( + App.UI.DOM.link(`Keep all of ${his} children`, () => wombUpdateIncubator(9999, true)) + ); + } + } else if (V.reservedChildren === freeTanks) { + title.textContent = `You have no available tanks for ${his} children. `; + } + } + el.append(title); + el.append(link); + } + } + } + + function wombUpdateIncubator(count, addToWomb) { + if (addToWomb) { + WombAddToGenericReserve(slave, "incubator", count); + } else { + WombCleanGenericReserve(slave, "incubator", count); + } + V.reservedChildren = FetusGlobalReserveCount("incubator"); + refresh(); + } + + return el; + } + + function nursery() { + let el = document.createElement('div'); + if (V.nursery > 0) { + V.reservedChildrenNursery = FetusGlobalReserveCount("nursery"); + let reservedIncubator = WombReserveCount(slave, "incubator"); + let reservedNursery = WombReserveCount(slave, "nursery"); + let _WL = slave.womb.length; + if (slave.preg > 0 && slave.broodmother === 0 && slave.pregKnown === 1 && slave.eggType === "human") { + if ((slave.assignment !== Job.DAIRY || V.dairyPregSetting === 0) && (slave.assignment !== Job.FARMYARD || V.farmyardBreeding === 0)) { + let title = document.createElement('div'); + let link = document.createElement('div'); + link.className = "choices"; + if (_WL - reservedIncubator === 0) { + V.reservedChildren = 0; + title.textContent = `${His} children are already reserved for ${V.incubatorName}`; + title.style.fontStyle = "italic"; + } else { + const freeCribs = (V.nursery - V.cribs.length); + if (reservedNursery > 0) { + if (_WL === 1) { + title.textContent = `${His} child will be placed in ${V.nurseryName}. `; + } else if (reservedNursery < _WL) { + title.textContent = `_reservedNursery of ${his} children will be placed in ${V.nurseryName}.`; + } else if (_WL === 2) { + title.textContent = `Both of ${his} children will be placed in ${V.nurseryName}. `; + } else { + title.textContent = `All ${reservedNursery} of ${his} children will be placed in ${V.nurseryName}. `; + } + if ((reservedIncubator + reservedNursery < _WL) && (V.reservedChildrenNursery < freeCribs)) { + link.appendChild( + App.UI.DOM.link(`Keep another child`, () => wombUpdateNursery(1, true)) + ); + + if (reservedNursery > 0) { + link.append(` | `); + link.appendChild( + App.UI.DOM.link(`Keep one less child`, () => wombUpdateNursery(1, false)) + ); + } + if (reservedNursery > 1) { + link.append(` | `); + link.appendChild( + App.UI.DOM.link(`Keep none of ${his} children`, () => wombUpdateNursery(9999, false)) + ); + } + if ((V.reservedChildrenNursery + _WL - reservedNursery) <= freeCribs) { + link.append(` | `); + link.appendChild( + App.UI.DOM.link(`Keep the rest of ${his} children`, () => wombUpdateNursery(9999, true)) + ); + } + } else if ((reservedNursery === _WL) || (V.reservedChildrenNursery === freeCribs) || (reservedNursery - reservedIncubator >= 0)) { + link.appendChild( + App.UI.DOM.link(`Keep one less child`, () => wombUpdateNursery(1, false)) + ); + + if (reservedNursery > 1) { + link.append(` | `); + link.appendChild( + App.UI.DOM.link(`Keep none of ${his} children`, () => wombUpdateNursery(9999, false)) + ); + } + } + } else if (V.reservedChildrenNursery < freeCribs) { + title.textContent = `${He} is pregnant and you have `; + if (freeCribs === 1) { + title.textContent += `an `; + } + let crib = document.createElement('span'); + crib.className = "lime"; + crib.textContent = `available room`; + if (freeCribs > 1) { + crib.textContent += `s`; + } + crib.textContent += `.`; + let _cCount = (_WL > 1 ? "a" : "the"); + link.appendChild( + App.UI.DOM.link(`Keep ${_cCount} child`, () => wombUpdateNursery(1, true)) + ); + title.appendChild(crib); + if ((_WL > 1) && (V.reservedChildrenNursery + _WL) <= freeCribs) { + link.append(` | `); + link.appendChild( + App.UI.DOM.link(`Keep all of ${his} children`, () => wombUpdateNursery(9999, true)) + ); + } + } else if (V.reservedChildrenNursery === freeCribs) { + title.textContent = `You have no available rooms for ${his} children. `; + } + } + el.append(title); + el.append(link); + } + } + } + + function wombUpdateNursery(count, addToWomb) { + if (addToWomb) { + WombAddToGenericReserve(slave, "nursery", count); + } else { + WombCleanGenericReserve(slave, "nursery", count); + } V.reservedChildren = FetusGlobalReserveCount("nursery"); + refresh(); + } + + return el; + } + + function breederEligibility() { + const el = document.createElement("div"); + if (V.propOutcome === 1 && V.arcologies[0].FSRestart !== "unset") { + if (slave.breedingMark === 0 && slave.fuckdoll === 0 && slave.eggType === "human" && isFertile(slave) && slave.preg === 0) { + el.classList.add("choices"); + el.append( + App.UI.DOM.passageLink( + `Breeder Eligibility Exam`, + `BreedingTest` + ) + ); + } + } + return el; + } + + function bloating() { + let bloating = document.createElement('div'); + if (slave.inflation > 0) { + let intro = document.createElement('span'); + intro.textContent = "Required Bloating"; + intro.style.textDecoration = "underline"; + bloating.append(intro); + + bloating.append(": "); + + let requirement = document.createElement('span'); + requirement.style.fontWeight = "bold"; + requirement.id = "inflate"; + if (slave.inflation === 3) { + requirement.textContent = `${He} is required to keep 2 gallons of ${slave.inflationType} in ${him} at all times`; + } else if (slave.inflation === 2) { + requirement.textContent = `${He} is required to keep 4 liters of ${slave.inflationType} in ${him} at all times`; + } else if (slave.inflation === 1) { + requirement.textContent = `${He} is required to keep 2 liters of ${slave.inflationType} in ${him} at all times`; + } + bloating.append(requirement); + bloating.append(". "); + + let link = App.UI.DOM.link( + `Let ${him} deflate`, + () => { + deflate(slave); + refresh(); + }, + ); + bloating.append(link); + } + // make sure it updates itself after run + return bloating; + } + + function hormones() { + let el = document.createElement('div'); + const options = []; + const level = []; + + if (slave.hormones !== 0) { + level.push({text: `None`, updateSlave: {hormones: 0}}); + } + + if (slave.indentureRestrictions < 2) { + options.push({text: `Intensive Female`, updateSlave: {hormones: 2}}); + } else { + options.push({text: `Intensive Female`, disabled: `Cannot use intensive hormones on indentured slaves`}); + } + options.push({text: `Female`, updateSlave: {hormones: 1}}); + options.push({text: `Male`, updateSlave: {hormones: -1}}); + if (slave.indentureRestrictions < 2) { + options.push({text: `Intensive Male`, updateSlave: {hormones: -2}}); + } else { + options.push({text: `Intensive Male`, disabled: `Cannot use intensive hormones on indentured slaves`}); + } + + let title = document.createElement('div'); + title.textContent = `Hormones: `; + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + switch (slave.hormones) { + case 2: { + choice.textContent = `intensive female. `; + break; + } + case 1: { + choice.textContent = `female. `; + break; + } + case 0: { + choice.textContent = `none. `; + break; + } + case -1: { + choice.textContent = `male. `; + break; + } + case -2: { + choice.textContent = `intensive male. `; + break; + } + default: { + choice.textContent = `Not set. `; + } + } + + title.append(choice); + title.appendChild(App.UI.SlaveInteract.generateRows(level, slave, "", false, refresh)); + el.append(title); + + let links = document.createElement('div'); + links.appendChild(App.UI.SlaveInteract.generateRows(options, slave, "", false, refresh)); + links.className = "choices"; + el.append(links); + + return el; + } + + function diet() { + let el = document.createElement('div'); + + let title = document.createElement('div'); + title.textContent = `Diet: `; + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = `${capFirstChar(slave.diet)}. `; + + title.append(choice); + el.append(title); + + const health = []; + health.push({text: `Healthy`, updateSlave: {diet: "healthy"}}); + if (V.dietCleanse === 1) { + if (slave.health.condition < 90 || slave.chem >= 10) { + health.push({text: `Cleanse`, updateSlave: {diet: "cleansing"}}); + } else { + health.push({text: `Cleanse`, disabled: `${He} is already healthy`}); + } + } + + const weight = []; + if (slave.weight >= -95) { + weight.push({text: `Lose weight`, updateSlave: {diet: "restricted"}}); + } else { + weight.push({text: `Lose weight`, disabled: `${He} is already underweight`}); + } + if (slave.fuckdoll === 0 && slave.fetish !== "mindbroken" && V.feeder === 1) { + if (slave.weight > 10 || slave.weight < -10) { + weight.push({text: `Correct weight`, updateSlave: {diet: "corrective"}}); + } else { + weight.push({text: `Correct weight`, disabled: `${He} is already a healthy weight`}); + } + } + if (slave.weight <= 200) { + weight.push({text: `Fatten`, updateSlave: {diet: "fattening"}}); + } else { + weight.push({text: `Fatten`, disabled: `${He} is already overweight`}); + } + + const muscle = []; + if (slave.muscles < 100 && !isAmputee(slave)) { + muscle.push({text: `Build muscle`, updateSlave: {diet: "muscle building"}}); + } else if (!isAmputee(slave)) { + muscle.push({text: `Build muscle`, disabled: `${He} is maintaining ${his} enormous musculature`}); + } else { + muscle.push({text: `Build muscle`, disabled: `${He} has no limbs and thus can't effectively build muscle`}); + } + + if ((slave.muscles > 0 || slave.fuckdoll === 0) && canWalk(slave)) { + muscle.push({text: `Slim down`, updateSlave: {diet: "slimming"}}); + } else if (!canWalk(slave)) { + muscle.push({text: `Slim down`, disabled: `${He} can't walk and thus can't trim down`}); + } else if (slave.fuckdoll > 0) { + muscle.push({text: `Slim down`, disabled: `${He} has no muscles left to lose`}); + } + + const production = []; + if (slave.balls > 0 && V.cumProDiet === 1) { + production.push({text: `Cum production`, updateSlave: {diet: "cum production"}}); + } + if (((isFertile(slave) && slave.preg === 0) || (slave.geneticQuirks.superfetation === 2 && canGetPregnant(slave) && V.geneticMappingUpgrade !== 0)) && V.dietFertility === 1) { + production.push({text: `Fertility`, updateSlave: {diet: "fertility"}}); + } + + const hormone = []; + if (V.feeder === 1) { + hormone.push({text: `Estrogen enriched`, updateSlave: {diet: "XX"}}); + hormone.push({text: `Testosterone enriched`, updateSlave: {diet: "XY"}}); + if (V.dietXXY === 1 && slave.balls > 0 && (slave.ovaries === 1 || slave.mpreg === 1)) { + hormone.push({text: `Herm hormone blend`, updateSlave: {diet: "XXY"}}); + } + } + + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Health", health, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Weight", weight, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Muscle", muscle, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Production", production, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Hormone", hormone, slave, refresh); + + return el; + } + + function dietBase() { + let el = document.createElement('div'); + const milk = []; + const cum = []; + + // Milk + if (slave.dietCum < 2) { + milk.push({text: `Milk added`, updateSlave: {dietMilk: 1}}); + if (slave.dietCum < 2) { + milk.push({text: `Milk based`, updateSlave: {dietMilk: 2, dietCum: 0}}); + } + if (slave.dietMilk) { + milk.push({text: `Remove milk`, updateSlave: {dietMilk: 0}}); + } + } else { + milk.push({text: `Milk`, disabled: `Diet is based entirely on cum`}); + } + + // Cum + if (slave.dietMilk < 2) { + cum.push({text: `Cum added`, updateSlave: {dietCum: 1}}); + cum.push({text: `Cum based`, updateSlave: {dietCum: 2, dietMilk: 0}}); + if (slave.dietCum) { + cum.push({text: `Remove cum`, updateSlave: {dietCum: 0}}); + } + } else { + cum.push({text: `Cum`, disabled: `Diet is based entirely on milk`}); + } + + let title = document.createElement('div'); + title.textContent = `Diet base: `; + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + if (slave.dietCum === 2) { + choice.textContent = `cum based. `; + } else if (slave.dietCum === 1 && slave.dietMilk === 0) { + choice.textContent = `cum added. `; + } else if (slave.dietCum === 1 && slave.dietMilk === 1) { + choice.textContent = `cum and milk added. `; + } else if (slave.dietMilk === 1 && slave.dietCum === 0) { + choice.textContent = `milk added. `; + } else if (slave.dietMilk === 2) { + choice.textContent = `milk based. `; + } else if (slave.dietCum === 0 && slave.dietMilk === 0) { + choice.textContent = `normal. `; + } else { + choice.textContent = `THERE HAS BEEN AN ERROR.`; + } + + title.append(choice); + el.append(title); + + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Milk", milk, slave, refresh); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Cum", cum, slave, refresh); + + return el; + } + + function snacks() { + let el = document.createElement('div'); + let options = []; + + if (V.arcologies[0].FSHedonisticDecadenceResearch === 1) { + let title = document.createElement('div'); + title.textContent = `Solid Slave Food Access: `; + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + if (slave.onDiet === 0) { + choice.textContent = `Free to stuff ${himself}.`; + } else { + choice.textContent = `On a strict diet.`; + } + title.append(choice); + el.append(title); + + options.push({text: `No access`, updateSlave: {onDiet: 1}}); + options.push({text: `Full access`, updateSlave: {onDiet: 0}}); + + let links = document.createElement('div'); + links.appendChild(App.UI.SlaveInteract.generateRows(options, slave, "", false, refresh)); + links.className = "choices"; + el.append(links); + } + + return el; + } + } + function refresh() { + jQuery("#si-physical-regimen").empty().append(physicalRegimenContent()); + } +}; diff --git a/src/interaction/siRules.js b/src/interaction/siRules.js new file mode 100644 index 0000000000000000000000000000000000000000..3e8af1a0547b59e298f9afb2b1bee3682cc9f1d5 --- /dev/null +++ b/src/interaction/siRules.js @@ -0,0 +1,389 @@ +App.UI.SlaveInteract.rules = function(slave) { + const el = document.createElement("div"); + el.id = "si-rules"; + el.append(rulesContent()); + return el; + + function rulesContent() { + const frag = new DocumentFragment(); + let p; + let div; + let array; + let choices; + const { + He, His, + he, him, his + } = getPronouns(slave); + + if (V.seePreg !== 0) { + if (V.universalRulesImpregnation === "PC") { + updateBreederLink("you", "PCExclude"); + } else if (V.universalRulesImpregnation === "HG") { + updateBreederLink("the Head Girl", "HGExclude"); + } else if (V.universalRulesImpregnation === "Stud") { + updateBreederLink("your Stud", "StudExclude"); + } + } + + function updateBreederLink(breeder, exclude) { + p = document.createElement('p'); + const exempt = slave[exclude] ? "Exempt" : "Include"; + + p.append(`Will be bred by ${breeder} when fertile. `); + p.append( + App.UI.DOM.link(`${exempt} ${him}`, () => { + slave[exclude] = slave[exclude] ^ 1; // switch 0 and 1 + refresh(); + }) + ); + frag.append(p); + } + + p = document.createElement('p'); + + array = []; + if (slave.useRulesAssistant === 0) { + App.UI.DOM.appendNewElement("span", p, `Not subject `, ["bold", "gray"]); + App.UI.DOM.appendNewElement("span", p, `to the Rules Assistant.`, "gray"); + array.push( + App.UI.DOM.link( + `Include ${him}`, + () => { + slave.useRulesAssistant = 1; + refresh(); + } + ) + ); + } else { + App.UI.DOM.appendNewElement("h3", p, `Rules Assistant`); + + if (slave.hasOwnProperty("currentRules") && slave.currentRules.length > 0) { + const ul = document.createElement("UL"); + ul.style.margin = "0"; + V.defaultRules.filter( + x => ruleApplied(slave, x) + ).map( + x => { + const li = document.createElement('li'); + li.append(x.name); + ul.append(li); + } + ); + + // set up rules display + if ($("ul").has("li").length) { + App.UI.DOM.appendNewElement("div", p, `Rules applied: `); + p.append(ul); + } else { + App.UI.DOM.appendNewElement("div", p, `There are no rules that would apply to ${him}.`, "gray"); + } + } + array.push( + App.UI.DOM.link( + `Apply rules`, + () => { + DefaultRules(slave); + refresh(); + } + ) + ); + array.push( + App.UI.DOM.link( + `Exempt ${him}`, + () => { + slave.useRulesAssistant = 0; + refresh(); + } + ) + ); + array.push(App.UI.DOM.passageLink("Rules Assistant Options", "Rules Assistant")); + } + p.append(App.UI.DOM.generateLinksStrip(array)); + frag.append(p); + + p = document.createElement('p'); + App.UI.DOM.appendNewElement("h3", p, `Other Rules`); + + // Living + if (slave.fuckdoll > 0) { + App.UI.DOM.appendNewElement("span", p, "Rules have little meaning for living sex toys", "note"); + } else { + penthouseCensus(); + p.append("Living standard: "); + App.UI.DOM.appendNewElement("span", p, slave.rules.living, "bold"); + } + if (setup.facilityCareers.includes(slave.assignment)) { + App.UI.DOM.appendNewElement("span", p, ` ${His} living conditions are managed by ${his} assignment.`, "note"); + } else if ((slave.assignment === "be your Head Girl") && (V.HGSuite === 1)) { + App.UI.DOM.appendNewElement("span", p, ` ${He} has ${his} own little luxurious room in the penthouse with everything ${he} needs to be a proper Head Girl.`, "note"); + } else if ((slave.assignment === "guard you") && (V.dojo > 1)) { + App.UI.DOM.appendNewElement("span", p, ` ${He} has a comfortable room in the armory to call ${his} own.`, "note"); + } else { + choices = [ + {value: "spare"}, + {value: "normal"}, + ]; + if (canMoveToRoom(slave) || slave.rules.living === "luxurious") { + choices.push({value: "luxurious"}); + } else { + choices.push({ + title: `Luxurious`, + disabled: ["No luxurious rooms available"] + }); + } + + p.append(listChoices(choices, "living")); + } + + // Rest + if (["be a servant", "be a subordinate slave", "get milked", "please you", "serve in the club", "serve the public", "whore", "work as a farmhand", "work in the brothel", "work a glory hole"].includes(slave.assignment) || (V.dairyRestraintsSetting < 2 && slave.assignment === "work in the dairy")) { + div = document.createElement("div"); + div.append("Sleep rules: "); + App.UI.DOM.appendNewElement("span", div, slave.rules.rest, "bold"); + choices = [ + {value: "none"}, + {value: "cruel"}, + {value: "restrictive"}, + {value: "permissive"}, + {value: "mandatory"}, + ]; + div.append(listChoices(choices, "rest")); + p.append(div); + } + + // Mobility Aids + if (slave.fuckdoll > 0) { + // Sex toys don't move around on their own// + } else if (canMove(slave)) { + div = document.createElement("div"); + div.append("Use of mobility aids: "); + App.UI.DOM.appendNewElement("span", div, slave.rules.mobility, "bold"); + choices = [ + {value: "restrictive"}, + {value: "permissive"}, + ]; + div.append(listChoices(choices, "mobility")); + p.append(div); + } + + // Punishment + div = document.createElement("div"); + div.append("Typical punishment: "); + App.UI.DOM.appendNewElement("span", div, slave.rules.punishment, "bold"); + choices = [ + {value: "confinement"}, + {value: "whipping"}, + {value: "chastity"}, + {value: "situational"}, + ]; + div.append(listChoices(choices, "punishment")); + p.append(div); + + // Reward + div = document.createElement("div"); + div.append("Typical reward: "); + App.UI.DOM.appendNewElement("span", div, slave.rules.reward, "bold"); + choices = [ + {value: "relaxation"}, + {value: "drugs"}, + {value: "orgasm"}, + {value: "situational"}, + ]; + div.append(listChoices(choices, "reward")); + p.append(div); + + // Lactation + if (slave.lactation !== 2) { + div = document.createElement("div"); + div.append("Lactation maintenance: "); + App.UI.DOM.appendNewElement("span", div, slave.rules.lactation, "bold"); + choices = [ + { + title: "Left alone", + value: "none", + }, + ]; + + if (slave.lactation === 0) { + choices.push( + { + title: "Induce lactation", + value: "induce", + } + ); + } else { + choices.push( + { + title: "Maintain lactation", + value: "maintain", + } + ); + } + div.append(listChoices(choices, "lactation")); + p.append(div); + } + + p.append(orgasm(slave)); + + if (slave.voice !== 0) { + div = document.createElement("div"); + div.append("Speech rules: "); + App.UI.DOM.appendNewElement("span", div, slave.rules.speech, "bold"); + choices = [ + {value: "restrictive"}, + {value: "permissive"}, + ]; + if (slave.accent > 0 && slave.accent < 4) { + choices.push( + {value: "accent elimination"}, + ); + } else if (slave.accent > 3) { + choices.push( + {value: "language lessons"}, + ); + } + div.append(listChoices(choices, "speech")); + p.append(div); + } + + div = document.createElement("div"); + div.append("Relationship rules: "); + App.UI.DOM.appendNewElement("span", div, slave.rules.relationship, "bold"); + choices = [ + {value: "restrictive"}, + {value: "just friends"}, + {value: "permissive"}, + ]; + div.append(listChoices(choices, "relationship")); + p.append(div); + + p.append(smartSettings(slave)); + frag.append(p); + return frag; + + function listChoices(choices, property) { + const links = []; + for (const c of choices) { + const title = c.title || capFirstChar(c.value); + if (c.disabled) { + links.push( + App.UI.DOM.disabledLink( + title, c.disabled + ) + ); + } else { + links.push( + App.UI.DOM.link( + title, + () => { + slave.rules[property] = c.value; + refresh(); + } + ) + ); + } + } + return App.UI.DOM.generateLinksStrip(links); + } + function orgasm(slave) { + let el = document.createElement('div'); + + let title = document.createElement('div'); + title.textContent = `Non-assignment orgasm rules: `; + el.append(title); + + makeLinks("Masturbation", "rules.release.masturbation"); + makeLinks("Partner", "rules.release.partner"); + makeLinks("Family", "rules.release.family"); + makeLinks("Other slaves", "rules.release.slaves"); + makeLinks("Master", "rules.release.master", true); + + function makeLinks(text, setting, master = false) { + const options = + [{text: master ? `Grant` : `Allow`, updateSlave: {[setting]: 1}}, + {text: master ? `Deny` : `Forbid`, updateSlave: {[setting]: 0}}]; + + let links = document.createElement('div'); + links.append(`${text}: `); + links.append(status(_.get(slave, setting), master)); + links.appendChild(App.UI.SlaveInteract.generateRows(options, slave)); + links.className = "choices"; + el.append(links); + } + + function status(setting, master) { + let selected = document.createElement('span'); + selected.style.fontWeight = "bold"; + let text; + if (master) { + text = setting ? "granted" : "denied"; + } else { + text = setting ? "allowed" : "denied"; + } + selected.textContent = `${text}. `; + return selected; + } + + return el; + } + + function smartSettings(slave) { + let el = document.createElement('div'); + + const {His} = getPronouns(slave); + const bodyPart = []; + const BDSM = []; + const gender = []; + const level = []; + const usingBulletVibe = slave.vaginalAccessory === "smart bullet vibrator" || slave.dickAccessory === "smart bullet vibrator"; + + if (slave.clitPiercing === 3 || usingBulletVibe) { + // Level + level.push({text: `No sex`, updateSlave: {clitSetting: `none`}}); + level.push({text: `All sex`, updateSlave: {clitSetting: `all`}}); + + // Body part + bodyPart.push({text: `Vanilla`, updateSlave: {clitSetting: `vanilla`}}); + bodyPart.push({text: `Oral`, updateSlave: {clitSetting: `oral`}}); + bodyPart.push({text: `Anal`, updateSlave: {clitSetting: `anal`}}); + bodyPart.push({text: `Boobs`, updateSlave: {clitSetting: `boobs`}}); + if (V.seePreg !== 0) { + bodyPart.push({text: `Preg`, updateSlave: {clitSetting: `pregnancy`}}); + } + // BDSM + BDSM.push({text: `Sub`, updateSlave: {clitSetting: `submissive`}}); + BDSM.push({text: `Dom`, updateSlave: {clitSetting: `dom`}}); + BDSM.push({text: `Masochism`, updateSlave: {clitSetting: `masochist`}}); + BDSM.push({text: `Sadism`, updateSlave: {clitSetting: `sadist`}}); + BDSM.push({text: `Humiliation`, updateSlave: {clitSetting: `humiliation`}}); + + // Gender + gender.push({text: `Men`, updateSlave: {clitSetting: `men`}}); + gender.push({text: `Women`, updateSlave: {clitSetting: `women`}}); + gender.push({text: `Anti-men`, updateSlave: {clitSetting: `anti-men`}}); + gender.push({text: `Anti-women`, updateSlave: {clitSetting: `anti-women`}}); + } + + let label = null; + if (slave.clitPiercing === 3) { + label = `${His} smart ${slave.dick < 1 ? "clit" : "frenulum"} piercing `; + label += (usingBulletVibe) ? `and smart bullet vibrator are set to: ` : `is set to: `; + } + if (label) { + let title = App.UI.DOM.appendNewElement('div', el, label); + let selected = App.UI.DOM.appendNewElement('span', title, `${slave.clitSetting}. `); + selected.style.fontWeight = "bold"; + } + + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Level", level, slave); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Body part", bodyPart, slave); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "BDSM", BDSM, slave); + App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Gender", gender, slave); + + return el; + } + function refresh() { + jQuery("#si-rules").empty().append(rulesContent()); + } + } +}; diff --git a/src/interaction/siUtilities.js b/src/interaction/siUtilities.js new file mode 100644 index 0000000000000000000000000000000000000000..b5569e4a240d44140c4a368d415f1925e08d96cc --- /dev/null +++ b/src/interaction/siUtilities.js @@ -0,0 +1,148 @@ +/** Find the previous and next slaves' IDs based on the current sort order + * @param {App.Entity.SlaveState} slave + * @returns {[number, number]} - previous and next slave ID + */ +App.UI.SlaveInteract.placeInLine = function(slave) { + const useSlave = assignmentVisible(slave) ? ((s) => assignmentVisible(s)) : ((s) => slave.assignment === s.assignment); + const slaveList = V.slaves.filter(useSlave); + SlaveSort.slaves(slaveList); + const curSlaveIndex = slaveList.findIndex((s) => s.ID === slave.ID); + + let nextIndex; + if (curSlaveIndex + 1 > slaveList.length - 1) { + nextIndex = 0; // wrap around to first slave + } else { + nextIndex = curSlaveIndex + 1; + } + let prevIndex; + if (curSlaveIndex - 1 < 0) { + prevIndex = slaveList.length - 1; // wrap around to last slave + } else { + prevIndex = curSlaveIndex - 1; + } + + return [slaveList[prevIndex].ID, slaveList[nextIndex].ID]; +}; + +/** @typedef RowItem + * @type {object} + * @property {string} [FS] - FS requirement, if any + * @property {string} [text] - link text + * @property {object} [updateSlave] - properties to be merged onto the slave + * @property {object} [update] - properties to be merged into global state + * @property {string} [disabled] - text indicating why the option is unavailable + * @property {string} [note] + */ + +/** Append a simple row of choices with a label to a container, if there are choices to be made. + * @param {Node} parent + * @param {string} label + * @param {RowItem[]} array + * @param {App.Entity.SlaveState} slave + * @param {Function} [refresh] + */ +App.UI.SlaveInteract.appendLabeledChoiceRow = function(parent, label, array, slave, refresh) { + if (array.length > 0) { + let links = document.createElement('div'); + links.append(`${label}: `); + links.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "", false, refresh)); + links.className = "choices"; + return parent.appendChild(links); + } +}; + +/** Generate a row of choices + * @param {RowItem[]} array + * @param {App.Entity.SlaveState} slave + * @param {string} [category] - should be in the form of slave.category, the thing we want to update. + * @param {boolean} [accessCheck=false] + * @param {Function} [refresh] + * @returns {HTMLSpanElement} + */ +App.UI.SlaveInteract.generateRows = function(array, slave, category, accessCheck = false, refresh) { + let row = document.createElement('span'); + let useSep = false; + for (let i = 0; i < array.length; i++) { + let link; + const separator = document.createTextNode(` | `); + const keys = Object.keys(array[i]); + + // Test to see if there was a problem with the key + for (let j = 0; j < keys.length; j++) { + if (["FS", "text", "updateSlave", "update", "note", "disabled"].includes(keys[j])) { + continue; + } else { + array[i].text += " ERROR, THIS SCENE WAS NOT ENTERED CORRECTLY"; + console.log("Trash found while generateRows() was running: " + keys[j] + ": " + array[i][keys[j]]); + break; + } + } + // Some items will never be in App.Data.slaveWear, especially "none" if it falls in between harsh and nice data sets. Trying to look it up would cause an error, which is what access check works around. + let unlocked = false; + if (accessCheck === true) { + if (category === "chastity") { + let text = array[i].text.toLowerCase(); // Yucky. Category name does not match for chastity (since it sets multiple kinds of chastity at once). Compare using a lowercase name instead. + unlocked = isItemAccessible.entry(text, category, slave); + } else { + unlocked = isItemAccessible.entry(array[i].updateSlave[category], category, slave); + } + } + if (accessCheck === false || unlocked) { + if (i < array.length && i !== 0 && useSep === true) { // start with separator (after first loop); can't after since the last loop may not have any text. + row.appendChild(separator); + } + useSep = true; // First item may not appear and if it doesn't we don't want the second to start with a '|' + // is it just text? + if (array[i].disabled) { + link = App.UI.DOM.disabledLink(array[i].text, [array[i].disabled]); + } else if (typeof unlocked === 'string') { + link = App.UI.DOM.disabledLink(array[i].text, [unlocked]); + } else { + link = document.createElement('span'); + + // Set up the link + link.appendChild( + App.UI.DOM.link( + `${array[i].text} `, + () => { click(array[i]); }, + ) + ); + + if (array[i].FS) { + let FS = App.UI.DOM.disabledLink(`FS`, [FutureSocieties.displayAdj(array[i].FS)]); + FS.style.fontStyle = "italic"; + link.appendChild(FS); + } + + // add a note node if required + if (array[i].note) { + link.appendChild(App.UI.DOM.makeElement('span', ` ${array[i].note}`, 'note')); + } + } + row.appendChild(link); + } + } + + return row; + + /** @param {RowItem} arrayOption */ + function click(arrayOption) { + if (arrayOption.updateSlave) { + for (const slaveProperty in arrayOption.updateSlave) { + _.set(slave, slaveProperty, arrayOption.updateSlave[slaveProperty]); + } + } + if (arrayOption.update) { + Object.assign(V, arrayOption.update); + } + if (typeof refresh === "function") { + refresh(); + } else { + App.UI.SlaveInteract.refreshAll(slave); + } + } +}; + +App.UI.SlaveInteract.refreshAll = function(slave) { + App.UI.SlaveInteract.custom(slave); +}; diff --git a/src/interaction/siWardrobe.js b/src/interaction/siWardrobe.js new file mode 100644 index 0000000000000000000000000000000000000000..074312444eb65be5967386d41a7420c8947d4c11 --- /dev/null +++ b/src/interaction/siWardrobe.js @@ -0,0 +1,842 @@ +App.UI.SlaveInteract.wardrobe = function(slave) { + const el = document.createElement("p"); + el.id = "si-wardrobe"; + el.append(wardrobeContent()); + return el; + + function wardrobeContent() { + const { + // eslint-disable-next-line no-unused-vars + he, + him, + his, + } = getPronouns(slave); + const el = new DocumentFragment(); + el.append(clothes()); + el.append(collar()); + el.append(mask()); + el.append(mouth()); + el.append(armAccessory()); + el.append(shoes()); + el.append(legAccessory()); + el.append(bellyAccessory()); + el.append(buttplug()); + el.append(buttplugAttachment()); + el.append(vaginalAccessory()); + el.append(vaginalAttachment()); + el.append(dickAccessory()); + el.append(chastity()); + + App.UI.DOM.appendNewElement("h3", el, `Shopping`); + el.append(shopping()); + + return el; + + function clothes() { + let el = document.createElement('div'); + let links; + if (slave.fuckdoll === 0) { + // <<= App.Desc.clothing($activeSlave)>> + + let label = document.createElement('div'); + label.append(`Clothes: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.clothes} `); + label.appendChild(choice); + + // Choose her own + if (slave.clothes !== `choosing her own clothes`) { + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `Let ${him} choose`, updateSlave: {clothes: `choosing her own clothes`, choosesOwnClothes: 1}}); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "clothes", false, refresh)); + } + el.appendChild(label); + + + let niceOptionsArray = []; + let harshOptionsArray = []; + + let clothingOption; + // Nice clothes + App.Data.slaveWear.niceClothes.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {clothes: item.value, choosesOwnClothes: 0}, + FS: item.fs + }; + niceOptionsArray.push(clothingOption); + }); + // Harsh clothes + App.Data.slaveWear.harshClothes.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {clothes: item.value, choosesOwnClothes: 0}, + FS: item.fs + }; + if (item.value !== "choosing her own clothes") { + harshOptionsArray.push(clothingOption); + } + }); + + // Sort + niceOptionsArray = niceOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + harshOptionsArray = harshOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + + // Nice options + links = document.createElement('div'); + links.className = "choices"; + links.append(`Nice: `); + links.appendChild(App.UI.SlaveInteract.generateRows(niceOptionsArray, slave, "clothes", true, refresh)); + el.appendChild(links); + + // Harsh options + links = document.createElement('div'); + links.className = "choices"; + links.append(`Harsh: `); + links.appendChild(App.UI.SlaveInteract.generateRows(harshOptionsArray, slave, "clothes", true, refresh)); + el.appendChild(links); + } + if (slave.fuckdoll !== 0 || slave.clothes === "restrictive latex" || slave.clothes === "a latex catsuit" || slave.clothes === "a cybersuit" || slave.clothes === "a comfortable bodysuit") { + if (V.seeImages === 1 && V.imageChoice === 1) { + // Color options + links = document.createElement('div'); + links.className = "choices"; + links.append(`Color: `); + links.appendChild(colorOptions("clothingBaseColor")); + el.appendChild(links); + } + } + + return el; + } + + function collar() { + if (slave.fuckdoll !== 0) { + return; + } + // <<= App.Desc.collar($activeSlave)>> + let el = document.createElement('div'); + + let label = document.createElement('div'); + label.append(`Collar: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.collar} `); + label.appendChild(choice); + + // Choose her own + if (slave.collar !== `none`) { + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `None`, updateSlave: {collar: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "collar", false, refresh)); + } + + el.appendChild(label); + + let niceOptionsArray = []; + let harshOptionsArray = []; + + let clothingOption; + // Nice collar + App.Data.slaveWear.niceCollars.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {collar: item.value}, + FS: item.fs + }; + niceOptionsArray.push(clothingOption); + }); + // Harsh collar + App.Data.slaveWear.harshCollars.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {collar: item.value}, + FS: item.fs + }; + harshOptionsArray.push(clothingOption); + }); + + // Sort + niceOptionsArray = niceOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + harshOptionsArray = harshOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + + // Nice options + let links = document.createElement('div'); + links.className = "choices"; + links.append(`Nice: `); + links.appendChild(App.UI.SlaveInteract.generateRows(niceOptionsArray, slave, "collar", true, refresh)); + el.appendChild(links); + + // Harsh options + links = document.createElement('div'); + links.className = "choices"; + links.append(`Harsh: `); + links.appendChild(App.UI.SlaveInteract.generateRows(harshOptionsArray, slave, "collar", true, refresh)); + el.appendChild(links); + + return el; + } + + function mask() { + if (slave.fuckdoll !== 0) { + return; + } + let el = document.createElement('div'); + + let label = document.createElement('div'); + label.append(`Mask: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.faceAccessory} `); + label.appendChild(choice); + + // Choose her own + if (slave.faceAccessory !== `none`) { + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `None`, updateSlave: {faceAccessory: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "faceAccessory", false, refresh)); + } + + el.appendChild(label); + + let array = []; + + let clothingOption; + App.Data.slaveWear.faceAccessory.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {faceAccessory: item.value}, + FS: item.fs + }; + array.push(clothingOption); + }); + + // Sort + array = array.sort((a, b) => (a.text > b.text) ? 1 : -1); + + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "faceAccessory", true, refresh)); + el.appendChild(links); + + if (slave.eyewear === "corrective glasses" || slave.eyewear === "glasses" || slave.eyewear === "blurring glasses" || slave.faceAccessory === "porcelain mask") { + // Color options + links = document.createElement('div'); + links.className = "choices"; + links.append(`Color: `); + links.appendChild(colorOptions("glassesColor")); + let note = document.createElement('span'); + note.className = "note"; + note.textContent = ` Only glasses and porcelain masks support a custom color. If both are worn, they will share the same color.`; + links.appendChild(note); + el.appendChild(links); + } + + return el; + } + + function mouth() { + if (slave.fuckdoll !== 0) { + return; + } + let el = document.createElement('div'); + + let label = document.createElement('div'); + label.append(`Gag: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.mouthAccessory} `); + label.appendChild(choice); + + // Choose her own + if (slave.mouthAccessory !== `none`) { + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `None`, updateSlave: {mouthAccessory: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "mouthAccessory", false, refresh)); + } + + el.appendChild(label); + + let array = []; + + let clothingOption; + // mouthAccessory + App.Data.slaveWear.mouthAccessory.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {mouthAccessory: item.value}, + FS: item.fs + }; + array.push(clothingOption); + }); + + // Sort + array = array.sort((a, b) => (a.text > b.text) ? 1 : -1); + + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "mouthAccessory", true, refresh)); + el.appendChild(links); + + return el; + } + + function armAccessory() { + if (slave.fuckdoll !== 0) { + return; + } + + let el = document.createElement('div'); + // App.Desc.armwear(slave) + + let label = document.createElement('div'); + label.append(`Arm accessory: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.armAccessory} `); + label.appendChild(choice); + + let array = []; + + // Choose her own + if (slave.armAccessory !== "none") { + array.push({text: `None`, updateSlave: {armAccessory: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "armAccessory", false, refresh)); + } + + el.appendChild(label); + + let links = document.createElement('div'); + links.className = "choices"; + array = [ + {text: "Hand gloves", updateSlave: {armAccessory: "hand gloves"}}, + {text: "Elbow gloves", updateSlave: {armAccessory: "elbow gloves"}} + ]; + links.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "armAccessory", false, refresh)); + el.appendChild(links); + + return el; + } + + function shoes() { + if (slave.fuckdoll !== 0) { + return; + } + let el = document.createElement('div'); + + let label = document.createElement('div'); + label.append(`Shoes: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.shoes} `); + label.appendChild(choice); + + /* We have "barefoot" in App.Data.slaveWear to cover for this + // Choose her own + if (slave.shoes !== `none`) { + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `None`, updateSlave: {shoes: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "shoes", false, refresh)); + } + */ + el.appendChild(label); + + let optionsArray = []; + + let clothingOption; + App.Data.slaveWear.shoes.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {shoes: item.value}, + FS: item.fs + }; + optionsArray.push(clothingOption); + }); + + // Sort + // No sort here since we want light -> advanced. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + + // Options + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "shoes", true, refresh)); + el.appendChild(links); + + if (V.seeImages === 1 && V.imageChoice === 1 && slave.shoes !== "none") { + // Color options + links = document.createElement('div'); + links.className = "choices"; + links.append(`Color: `); + links.appendChild(colorOptions("shoeColor")); + el.appendChild(links); + } + + return el; + } + + function legAccessory() { + if (slave.fuckdoll !== 0) { + return; + } + + let el = document.createElement('div'); + + let label = document.createElement('div'); + label.append(`Leg accessory: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.legAccessory} `); + label.appendChild(choice); + + let array = []; + + // Choose her own + if (slave.legAccessory !== "none") { + array.push({text: `None`, updateSlave: {legAccessory: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "legAccessory", false, refresh)); + } + + el.appendChild(label); + + let links = document.createElement('div'); + links.className = "choices"; + array = [ + {text: "Short stockings", updateSlave: {legAccessory: "short stockings"}}, + {text: "Long stockings", updateSlave: {legAccessory: "long stockings"}} + ]; + links.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "legAccessory", false, refresh)); + el.appendChild(links); + + return el; + } + + function bellyAccessory() { + if (slave.fuckdoll !== 0) { + return; + } + // <<waistDescription>><<= App.Desc.pregnancy($activeSlave)>><<clothingCorsetDescription>> + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `None`, updateSlave: {bellyAccessory: `none`}}); + + let optionsArray = []; + + let clothingOption; + App.Data.slaveWear.bellyAccessories.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {bellyAccessory: item.value}, + FS: item.fs + }; + if (item.value !== "none") { + // skip none in set, we set the link elsewhere. + optionsArray.push(clothingOption); + } + }); + // Sort + // No sort here since we want small -> large.optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + + let el = document.createElement('div'); + + let label = document.createElement('div'); + label.append(`Belly accessory: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.bellyAccessory} `); + label.appendChild(choice); + + // Choose her own + if (slave.bellyAccessory !== `none`) { + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "bellyAccessory", false, refresh)); + } + + el.appendChild(label); + + // Options + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "bellyAccessory", true, refresh)); + if (slave.pregKnown === 1) { + let note = document.createElement('span'); + note.className = "note"; + note.textContent = ` Extreme corsets will endanger the life within ${him}.`; + links.appendChild(note); + } + el.appendChild(links); + + return el; + } + + function buttplug() { + if (slave.fuckdoll !== 0) { + return; + } + // App.Desc.buttplug(slave) + + let el = document.createElement('div'); + + let label = document.createElement('div'); + label.append(`Anal accessory: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.buttplug} `); + label.appendChild(choice); + + if (slave.buttplug !== `none`) { + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `None`, updateSlave: {buttplug: `none`, buttplugAttachment: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "buttplug", false, refresh)); + } + el.appendChild(label); + + let optionsArray = []; + + let clothingOption; + App.Data.slaveWear.buttplugs.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {buttplug: item.value}, + FS: item.fs + }; + if (item.value !== "none") { + // skip none in set, we set the link elsewhere. + optionsArray.push(clothingOption); + } + }); + + // Sort + // No sort here since we want small -> large. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + + // Options + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "buttplug", true, refresh)); + el.appendChild(links); + + return el; + } + + function buttplugAttachment() { + let el = document.createElement('div'); + if (slave.fuckdoll !== 0 || slave.buttplug === "none") { + return el; + } + + let label = document.createElement('div'); + label.append(`Anal accessory attachment: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.buttplugAttachment} `); + label.appendChild(choice); + + if (slave.buttplugAttachment !== `none`) { + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `None`, updateSlave: {buttplugAttachment: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "buttplugAttachment", false, refresh)); + } + el.appendChild(label); + + let optionsArray = []; + + let clothingOption; + App.Data.slaveWear.buttplugAttachments.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {buttplugAttachment: item.value}, + FS: item.fs + }; + if (item.value !== "none") { + // skip none in set, we set the link elsewhere. + optionsArray.push(clothingOption); + } + }); + + // Sort + optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + + // Options + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "buttplugAttachment", true, refresh)); + el.appendChild(links); + + return el; + } + + function vaginalAccessory() { + if (slave.fuckdoll !== 0) { + return; + } + + // <<vaginalAccessoryDescription>> + + let el = document.createElement('div'); + + let label = document.createElement('div'); + label.append(`Vaginal accessory: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.vaginalAccessory} `); + label.appendChild(choice); + + if (slave.vaginalAccessory !== `none`) { + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `None`, updateSlave: {vaginalAccessory: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "vaginalAccessory", false, refresh)); + } + el.appendChild(label); + + let optionsArray = []; + + let clothingOption; + App.Data.slaveWear.vaginalAccessories.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {vaginalAccessory: item.value}, + FS: item.fs + }; + if (item.value !== "none") { + // skip none in set, we set the link elsewhere. + optionsArray.push(clothingOption); + } + }); + + // Sort + // No sort here since we want small -> large. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + + // Options + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "vaginalAccessory", true, refresh)); + el.appendChild(links); + + return el; + } + + function vaginalAttachment() { + let el = document.createElement('div'); + if (slave.fuckdoll !== 0 || (["none", "bullet vibrator", "smart bullet vibrator"].includes(slave.vaginalAccessory))) { + return el; + } + + let label = document.createElement('div'); + label.append(`Vaginal accessory attachment: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.vaginalAttachment} `); + label.appendChild(choice); + + if (slave.vaginalAttachment !== `none`) { + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `None`, updateSlave: {vaginalAttachment: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "vaginalAttachment", false, refresh)); + } + el.appendChild(label); + + let optionsArray = []; + + let clothingOption; + App.Data.slaveWear.vaginalAttachments.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {vaginalAttachment: item.value}, + FS: item.fs + }; + if (item.value !== "none") { + // skip none in set, we set the link elsewhere. + optionsArray.push(clothingOption); + } + }); + + // Sort + optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + + // Options + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "vaginalAttachment", true, refresh)); + el.appendChild(links); + + return el; + } + + function dickAccessory() { + if (slave.fuckdoll !== 0) { + return; + } + // <<= App.Desc.dickAccessory($activeSlave)>> + let el = document.createElement('div'); + + let label = document.createElement('div'); + label.append(`Dick accessory: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + choice.textContent = (`${slave.dickAccessory} `); + label.appendChild(choice); + + if (slave.dickAccessory !== `none`) { + let choiceOptionsArray = []; + choiceOptionsArray.push({text: `None`, updateSlave: {dickAccessory: `none`}}); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "dickAccessory", false, refresh)); + } + el.appendChild(label); + + let optionsArray = []; + + let clothingOption; + App.Data.slaveWear.dickAccessories.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {dickAccessory: item.value}, + FS: item.fs + }; + if (item.value !== "none") { + // skip none in set, we set the link elsewhere. + optionsArray.push(clothingOption); + } + }); + + // Sort + // No sort here since we want small -> large. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + + // Options + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "dickAccessory", true, refresh)); + el.appendChild(links); + + return el; + } + + function chastity() { + if (slave.fuckdoll !== 0) { + return; + } + + let el = document.createElement('div'); + + let label = document.createElement('div'); + label.append(`Chastity devices: `); + + let choice = document.createElement('span'); + choice.style.fontWeight = "bold"; + if (slave.choosesOwnChastity === 1) { + choice.textContent = `choosing ${his} own chastity `; + } else if (slave.chastityAnus === 1 && slave.chastityPenis === 1 && slave.chastityVagina === 1) { + choice.textContent = `full chastity `; + } else if (slave.chastityPenis === 1 && slave.chastityVagina === 1) { + choice.textContent = `genital chastity `; + } else if (slave.chastityAnus === 1 && slave.chastityPenis === 1) { + choice.textContent = `combined chastity cage `; + } else if (slave.chastityAnus === 1 && slave.chastityVagina === 1) { + choice.textContent = `combined chastity belt `; + } else if (slave.chastityVagina === 1) { + choice.textContent = `chastity belt `; + } else if (slave.chastityPenis === 1) { + choice.textContent = `chastity cage `; + } else if (slave.chastityAnus === 1) { + choice.textContent = `anal chastity `; + } else if (slave.chastityAnus === 0 && slave.chastityPenis === 0 && slave.chastityVagina === 0) { + choice.textContent = `none `; + } else { + choice.textContent = `THERE HAS BEEN AN ERROR `; + } + label.appendChild(choice); + + if (slave.chastityAnus !== 0 || slave.chastityPenis !== 0 || slave.chastityVagina !== 0) { + let choiceOptionsArray = []; + choiceOptionsArray.push({ + text: `None`, + updateSlave: { + choosesOwnChastity: 0, + chastityAnus: 0, + chastityPenis: 0, + chastityVagina: 0 + } + }); + label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "chastity", false, refresh)); + } + el.appendChild(label); + + let optionsArray = []; + + let clothingOption; + App.Data.slaveWear.chastityDevices.forEach(item => { + clothingOption = { + text: item.name, + updateSlave: {}, + FS: item.fs + }; + Object.assign(clothingOption.updateSlave, item.updateSlave); + if (item.value !== "none") { + // skip none in set, we set the link elsewhere. + optionsArray.push(clothingOption); + } + }); + + // Sort + // skip sort for this one too. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); + + // Options + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "chastity", true, refresh)); + el.appendChild(links); + + return el; + } + + function shopping() { + return App.UI.DOM.passageLink( + `Go shopping for more options`, + "Wardrobe" + ); + } + + /** + * @param {string} update + * @returns {Node} + */ + function colorOptions(update) { + let el = new DocumentFragment(); + let colorChoice = App.UI.DOM.colorInput( + slave[update], + v => { + slave[update] = v; + refresh(); + } + ); + el.appendChild(colorChoice); + + if (slave[update]) { + el.appendChild( + App.UI.DOM.link( + ` Reset`, + () => { + delete slave[update]; + refresh(); + }, + ) + ); + } + return el; + } + } + function refresh() { + App.Art.refreshSlaveArt(slave, 3, "art-frame"); + jQuery("#si-wardrobe").empty().append(wardrobeContent()); + } +}; diff --git a/src/interaction/siWork.js b/src/interaction/siWork.js new file mode 100644 index 0000000000000000000000000000000000000000..eef1e0ceccfa742b4eb7ab9748247c20cb41311e --- /dev/null +++ b/src/interaction/siWork.js @@ -0,0 +1,762 @@ +App.UI.SlaveInteract.work = function(slave) { + const el = document.createElement("p"); + el.id = "si-work"; + el.append(work()); + return el; + + function work() { + let el = new DocumentFragment(); + let p; + let div; + let span; + const links = []; + const { + His, He, + his, him + } = getPronouns(slave); + + function appendLink(text, whoreClass, enabled, disabledText) { + const link = {text: text}; + if (enabled) { + link.whoreClass = whoreClass; + } else { + link.disabled = disabledText; + } + links.push(link); + } + + p = document.createElement('p'); + if (slave.assignment === Job.AGENT) { + const arc = V.arcologies.find((a) => a.leaderID === slave.ID); + p.className = "scene-intro"; + p.textContent = `${He} is serving as your Agent${arc ? ` leading ${arc.name}` : ` but is not currently assigned to an arcology`}. `; + p.appendChild(App.UI.DOM.link(`Recall and reenslave ${him}`, () => { removeJob(slave, slave.assignment, false); refresh(); })); + } else if (slave.assignment === Job.AGENTPARTNER) { + const agent = getSlave(slave.relationshipTarget); + const arc = agent ? V.arcologies.find((a) => a.leaderID === agent.ID) : null; + p.className = "scene-intro"; + p.textContent = `${He} is living with your Agent ${SlaveFullName(agent)}${arc ? ` in ${arc.name}` : ``}. `; + p.appendChild(App.UI.DOM.link(`Recall ${him}`, () => { removeJob(slave, slave.assignment, false); refresh(); })); + } else { + div = document.createElement('div'); + div.id = "mini-scene"; + p.appendChild(div); + + span = document.createElement('span'); + span.id = "useSlave"; + p.appendChild(span); + p.appendChild(useSlaveDisplay()); + } + el.append(p); + + p = document.createElement('p'); + span = document.createElement('span'); + span.className = "note"; + switch (slave.assignment) { + case Job.BODYGUARD: + span.textContent = `${He} is your Bodyguard and is not available for other work`; + break; + case Job.MADAM: + span.textContent = `${He} is the Madam and is not available for other work`; + break; + case Job.DJ: + span.textContent = `${He} is the DJ and is not available for other work`; + break; + case Job.MILKMAID: + span.textContent = `${He} is the Milkmaid and is not available for other work`; + break; + case Job.FARMER: + span.textContent = `${He} is the Farmer and is not available for other work`; + break; + case Job.STEWARD: + span.textContent = `${He} is the Stewardess and is not available for other work`; + break; + case Job.HEADGIRL: + span.textContent = `${He} is your Head Girl and is not available for other work`; + break; + case Job.RECRUITER: + span.textContent = `${He} is recruiting slaves and is not available for other work`; + break; + case Job.NURSE: + span.textContent = `${He} is the Nurse and is not available for other work`; + break; + case Job.ATTENDANT: + span.textContent = `${He} is the Attendant of the spa and is not available for other work`; + break; + case Job.MATRON: + span.textContent = `${He} is the Matron of the nursery and is not available for other work`; + break; + case Job.TEACHER: + span.textContent = `${He} is the Schoolteacher and is not available for other work`; + break; + case Job.CONCUBINE: + span.textContent = `${He} is your Concubine and is not available for other work`; + break; + case Job.WARDEN: + span.textContent = `${He} is the Wardeness and is not available for other work`; + break; + default: + // CAN BE REASSIGNED + span.classList.remove("note"); + span.id = "assignmentLinks"; + span.appendChild(assignmentBlock()); + + if ((V.brothel + V.club + V.dairy + V.farmyard + V.servantsQuarters + V.masterSuite + V.spa + V.nursery + V.clinic + V.schoolroom + V.cellblock + V.arcade + V.HGSuite) > 0) { + span.append(`Transfer to: `); + span.appendChild(App.UI.jobLinks.transfersFragment(slave.ID)); + } + + div = document.createElement('div'); + div.id = "fucktoy-pref"; + div.append(fucktoyPref()); + span.appendChild(div); + } + el.append(span); + + if (slave.assignment === Job.WHORE || slave.assignment === Job.BROTHEL) { + div = document.createElement('div'); + div.textContent = `Whoring Target: `; + span = document.createElement('span'); + span.style.fontWeight = "bold"; + + span.id = "whoreClass"; + if (!slave.whoreClass) { + span.textContent = `auto`; + } else if (slave.whoreClass === 1) { + span.textContent = `the lower class`; + } else if (slave.whoreClass === 2) { + span.textContent = `the middle class`; + } else if (slave.whoreClass === 3) { + span.textContent = `the upper class`; + } else if (slave.whoreClass === 4) { + span.textContent = `millionaires`; + } else { + span.textContent = `THERE HAS BEEN AN ERROR`; + } + div.append(span); + div.append(`. `); + + div.append(App.UI.DOM.makeElement('span', `This is the highest class they are allowed to service, when eligible `, 'note')); + + appendLink(`Auto`, 0, true); + appendLink(`Lower Class`, 1, true); + appendLink(`Middle Class`, 2, true); + appendLink(`Upper Class`, 3, true); + appendLink(`Millionaires Class`, 4, true); + div.appendChild(App.UI.DOM.generateLinksStrip(links.map(generateLink))); + + el.append(div); + } + + el.append(tutorBlock()); + return el; + + function generateLink(linkDesc) { + // is it just text? + if (linkDesc.disabled) { return App.UI.DOM.disabledLink(linkDesc.text, [linkDesc.disabled]); } + // Are they already on this whoreClass? + if (linkDesc.whoreClass === slave.whoreClass) { return document.createTextNode(linkDesc.text); } + // Set up the link + const link = App.UI.DOM.link( + linkDesc.text, + () => { + slave.whoreClass = linkDesc.whoreClass; + refresh(); + }, + ); + + // add a note node if required + if (linkDesc.note) { + App.UI.DOM.appendNewElement("span", link, linkDesc.note, "note"); + } + return link; + } + + function assignmentBlock() { + let el = document.createElement('div'); + let title = document.createElement('div'); + let separator = document.createTextNode(` | `); + title.append(`Assignment: `); + + let assign = document.createElement('span'); + assign.style.fontWeight = "bold"; + if (slave.sentence) { + assign.textContent = `${slave.assignment} (${slave.sentence} weeks). `; + } else { + assign.textContent = `${slave.assignment}. `; + } + title.appendChild(assign); + if (V.assignmentRecords[slave.ID] && V.assignmentRecords[slave.ID] !== slave.assignment) { + title.append(`Previously: `); + assign = document.createElement('span'); + assign.style.fontWeight = "bold"; + assign.textContent = `${V.assignmentRecords[slave.ID]}. `; + title.appendChild(assign); + } + if (slave.assignment === Job.SUBORDINATE) { + const target = getSlave(slave.subTarget); + let linkText = ``; + if (target) { + title.appendChild(document.createTextNode(`Serving ${target.slaveName} exclusively. `)); + linkText = `Change`; + } else if (slave.subTarget === -1) { + title.appendChild(document.createTextNode(`Serving as a Stud. `)); + linkText = `Change role`; + } else { + title.appendChild(document.createTextNode(`Serving all your other slaves. `)); + linkText = `Choose a specific slave to submit to`; + } + title.appendChild(App.UI.DOM.passageLink(linkText, "Subordinate Targeting", () => { V.returnTo = "Slave Interact"; })); + title.append(separator); + } + if (slave.assignment !== Job.CHOICE) { + title.appendChild( + App.UI.DOM.link( + `Stay on this assignment for another month`, + () => { + slave.sentence += 4; + refresh(); + }, + ) + ); + } + el.appendChild(title); + + let links = document.createElement('div'); + links.className = "choices"; + links.appendChild( + App.UI.jobLinks.assignmentsFragment( + slave.ID, passage(), + (slave, assignment) => { + assignJob(slave, assignment); + } + ) + ); + el.appendChild(links); + return el; + } + + function tutorBlock() { + let el = App.UI.DOM.makeElement("div"); + let title = App.UI.DOM.appendNewElement("div", el, `Private tutoring: `); + let tutor = tutorForSlave(slave); + + if (tutor === null) { + App.UI.DOM.appendNewElement("span", title, `none.`, "bold"); + } else { + App.UI.DOM.appendNewElement("span", title, tutor + `.`, "bold"); + } + + if (tutor != null) { + App.UI.DOM.appendNewElement("span", title, ` To progress slave needs to be assigned to: "` + Job.CLASSES + `" or "` + Job.SCHOOL + `".`, "note"); + } + + let list = ["None"]; + for (const keys of Object.keys(V.slaveTutor)) { + list.push(keys); + } + const array = list.map((s) => { + if (shouldBeEnabled(slave, s)) { + return App.UI.DOM.link(s, () => setTutorForSlave(slave, s)); + } else { + let reason = ["Already being taught this skill."]; + return App.UI.DOM.disabledLink(s, reason); + } + }); + App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(array)); + + function shouldBeEnabled(slave, key) { + let tutor = tutorForSlave(slave); + if (tutor === null) { + return "None"; + } + return (tutor !== key); + } + + function setTutorForSlave(slave, tutor) { + const cur = tutorForSlave(slave); + + if (tutor !== cur && cur != null) { + V.slaveTutor[cur].delete(slave.ID); + } + + if (cur !== tutor && tutor !== "None") { + V.slaveTutor[tutor].push(slave.ID); + } + refresh(); + } + + return el; + } + + function useSlaveDisplay() { + // Goal: Be able to write the entire "use her" block with only dom fragments. + let el = document.createElement('div'); + + /* + Array of objects. Each object follows the form: { + text: "Link text", + scene: "scene to include", + goto: if another passage is needed + updateSlave: update slave itself if needed, like {trust: 2}, + update: updates V., + note: if a note must appear after the link + } + */ + const sexOptions = []; + const fillFaceOptions = []; + const fillAssOptions = []; + const dairyNameCaps = capFirstChar(V.dairyName); + // if no scene, it's just text, no link. Italicize it. + + if (slave.fuckdoll === 0) { + if (slave.vagina > -1) { + if (canDoVaginal(slave)) { + sexOptions.push({text: `Fuck ${him}`, scene: `FVagina`}); + if (canDoAnal(slave)) { + sexOptions.push({text: `Use ${his} holes`, scene: `FButt`}); + } + } else { + sexOptions.push({text: `Fuck ${him}`, disabled: `Remove ${his} chastity belt if you wish to fuck ${him}`}); + } + } + if (slave.bellyPreg >= 300000) { + if (canDoVaginal(slave) || canDoAnal(slave)) { + sexOptions.push({text: `Fuck ${him} on ${his} belly`, scene: `FBellyFuck`}); + if (V.pregInventions >= 1) { + sexOptions.push({text: `Fuck ${him} in ${his} maternity swing`, scene: `FMaternitySwing`}); + sexOptions.push({text: `Fuck ${him} with the help of ${his} assistants`, scene: `FAssistedSex`}); + sexOptions.push({text: `Fuck ${him} in your goo pool`, scene: `FPoolSex`}); + } + } + } + + if (canDoAnal(slave)) { + sexOptions.push({text: `Fuck ${his} ass`, scene: `FAnus`}); + } else { + sexOptions.push({text: `Fuck ${his} ass`, disabled: `Remove ${his} chastity belt if you wish to fuck ${his} ass`}); + } + sexOptions.push({text: `Use ${his} mouth`, scene: `FLips`}); + sexOptions.push({text: `Kiss ${him}`, scene: `FKiss`}); + if (hasAnyLegs(slave)) { + sexOptions.push({text: `Have ${him} dance for you`, scene: `FDance`}); + } + + sexOptions.push({text: `Play with ${his} tits`, scene: `FBoobs`}); + + sexOptions.push({text: `Caress ${him}`, scene: `FCaress`}); + + sexOptions.push({text: `Give ${him} a hug`, scene: `FEmbrace`}); + if (V.cheatMode === 1) { + sexOptions.push({text: `Pat ${his} head`, scene: `FPat`}); + } + + sexOptions.push({text: `Grope ${his} boobs`, scene: `FondleBoobs`}); + if (slave.nipples === "fuckable" && V.PC.dick > 0) { + sexOptions.push({text: `Fuck ${his} nipples`, scene: `FNippleFuck`}); + } + if (slave.lactation > 0 && slave.boobs >= 2000 && slave.belly < 60000 && hasAnyArms(slave)) { + sexOptions.push({text: `Drink ${his} milk`, scene: `FSuckle`}); + } + + if (canDoAnal(slave)) { + sexOptions.push({text: `Grope ${his} butt`, scene: `FondleButt`}); + } + + + if (slave.vagina > -1) { + if (canDoVaginal(slave)) { + sexOptions.push({text: `Grope ${his} pussy`, scene: `FondleVagina`}); + sexOptions.push({text: `Eat ${him} out`, scene: `FLickPussy`}); + } + } + + if (slave.dick > 0) { + if (!(slave.chastityPenis)) { + sexOptions.push({text: `Grope ${his} dick`, scene: `FondleDick`}); + if (canPenetrate(slave)) { + if (V.policies.sexualOpenness === 1 || slave.toyHole === "dick") { + sexOptions.push({text: `Ride ${his} dick`, scene: `FDick`}); + } + } + } else { + sexOptions.push({text: `Use ${his} dick`, disabled: `Remove ${his} dick chastity belt if you wish to play with ${his} cock`}); + } + } + + if (hasAnyLegs(slave) && V.PC.dick > 0) { + sexOptions.push({text: `Get a footjob`, scene: `FFeet`}); + } + + if (canGetPregnant(slave) && (slave.geneticQuirks.superfetation !== 2 || V.geneticMappingUpgrade !== 0) && (slave.fuckdoll === 0) && V.seePreg !== 0) { + if (canImpreg(slave, V.PC)) { + sexOptions.push({text: `Impregnate ${him} yourself`, scene: `FPCImpreg`}); + } + if (canImpreg(slave, slave)) { + sexOptions.push({text: `Use ${his} own seed to impregnate ${him}`, scene: `FSlaveSelfImpreg`}); + } + sexOptions.push({text: `Use another slave to impregnate ${him}`, scene: `FSlaveImpreg`}); + } + if (slave.assignment !== Job.DAIRY && slave.assignment !== Job.ARCADE && slave.assignment !== Job.CELLBLOCK) { + if (V.dairyPiping === 1) { + if ((V.milkPipeline > 88 && V.milkPipeline !== 0) || V.arcologies[0].FSPastoralistLaw === 1) { + if ((slave.inflation < 3 && slave.pregKnown === 0 && slave.bellyImplant < 1500) || slave.inflation < 1) { + if (slave.inflationType === "milk" || slave.inflationType === "none") { + fillAssOptions.push({text: `Milk`, scene: `FillUpButt`, updateSlave: {inflationType: "milk", inflationMethod: 2}}); + fillFaceOptions.push({text: `Milk`, scene: `FillUpFace`, updateSlave: {inflationType: "milk", inflationMethod: 1}}); + } + } + } else { + fillAssOptions.push({text: `Milk`, disabled: `${dairyNameCaps} is not producing enough milk to pump through the pipes`}); + fillFaceOptions.push({text: `Milk`, disabled: `${dairyNameCaps} is not producing enough milk to pump through the pipes`}); + } + if ((V.cumPipeline > 88 && V.cumPipeline !== 0) || V.arcologies[0].FSPastoralistLaw === 1) { + if ((slave.inflation < 3 && slave.pregKnown === 0 && slave.bellyImplant < 1500) || slave.inflation < 1) { + if (slave.inflationType === "cum" || slave.inflationType === "none") { + fillAssOptions.push({text: `Cum`, scene: `FillUpButt`, updateSlave: {inflationType: "cum", inflationMethod: 2}}); + fillFaceOptions.push({text: `Cum`, scene: `FillUpFace`, updateSlave: {inflationType: "cum", inflationMethod: 1}}); + } + } + } else { + fillAssOptions.push({text: `Cum`, disabled: `${dairyNameCaps} is not producing enough cum to pump through the pipes`}); + fillFaceOptions.push({text: `Cum`, disabled: `${dairyNameCaps} is not producing enough cum to pump through the pipes`}); + } + } /* dairyPiping === 1 */ + if (V.boughtItem.toys.enema === 1) { + if ((slave.inflation < 3 && slave.pregKnown === 0 && slave.bellyImplant < 1500) || slave.inflation < 1) { + if (slave.inflationType === "water" || slave.inflationType === "none") { + fillAssOptions.push({text: `Water`, scene: `FillUpButt`, updateSlave: {inflationType: "water", inflationMethod: 2}}); + } + if (V.boughtItem.toys.medicalEnema === 1) { + if (slave.inflationType === "aphrodisiac" || slave.inflationType === "none") { + fillAssOptions.push({text: `Aphrodisiacs`, scene: `FillUpButt`, updateSlave: {inflationType: "aphrodisiac", inflationMethod: 2}}); + } + if (slave.inflationType === "curative" || slave.inflationType === "none") { + fillAssOptions.push({text: `Curatives`, scene: `FillUpButt`, updateSlave: {inflationType: "curative", inflationMethod: 2}}); + } + if (slave.inflationType === "tightener" || slave.inflationType === "none") { + fillAssOptions.push({text: `Rectal tighteners`, scene: `FillUpButt`, updateSlave: {inflationType: "tightener", inflationMethod: 2}}); + } + } + } /* inflation < 3 */ + } /* enema === 1 */ + if (V.wcPiping === 1) { + if ((slave.inflation < 3 && slave.pregKnown === 0 && slave.bellyImplant < 1500) || slave.inflation < 1) { + if (slave.inflationType === "urine" || slave.inflationType === "none") { + fillAssOptions.push({text: `Urine`, scene: `FillUpButt`, updateSlave: {inflationType: "urine", inflationMethod: 2}}); + } + } + } /* wcPiping === 1 */ + } /* assigned to dairy or arcade */ + if (slave.inflation === 0 && slave.bellyImplant < 1500) { + if (slave.assignment !== Job.DAIRY && slave.assignment !== Job.ARCADE && slave.assignment !== Job.CELLBLOCK) { + if (V.boughtItem.toys.buckets === 1) { + fillFaceOptions.push({text: `Two liters of slave food`, scene: `forceFeeding`, updateSlave: {inflation: 1, inflationType: "food", inflationMethod: 1}}); + if (slave.pregKnown === 0) { + fillFaceOptions.push({text: `A gallon of slave food`, scene: `forceFeeding`, updateSlave: {inflation: 2, inflationType: "food", inflationMethod: 1}}); + fillFaceOptions.push({text: `Two gallons of slave food`, scene: `forceFeeding`, updateSlave: {inflation: 3, inflationType: "food", inflationMethod: 1}}); + } + } + fillFaceOptions.push({text: `Get another slave to do it`, goto: `SlaveOnSlaveFeedingWorkAround`}); + } + } + if (canDoVaginal(slave)) { + sexOptions.push({text: `Have another slave fuck ${his} pussy`, scene: `FSlaveSlaveVag`}); + } + if (canPenetrate(slave)) { + sexOptions.push({text: `Have another slave ride ${his} cock`, scene: `FSlaveSlaveDick`}); + } else if (slave.clit >= 4) { + sexOptions.push({text: `Have another slave ride ${his} clit-dick`, scene: `FSlaveSlaveDick`}); + } + if (V.seeBestiality) { + if (V.farmyardKennels > 0 && V.activeCanine) { + sexOptions.push({text: `Have a ${V.activeCanine.species} mount ${him}`, scene: `BeastFucked`, update: {animalType: "canine"}}); + } + if (V.farmyardStables > 0 && V.activeHooved) { + sexOptions.push({text: `Let a ${V.activeHooved.species} mount ${him}`, scene: `BeastFucked`, update: {animalType: "hooved"}}); + } + if (V.farmyardCages > 0 && V.activeFeline) { + sexOptions.push({text: `Have a ${V.activeFeline.species} mount ${him}`, scene: `BeastFucked`, update: {animalType: "feline"}}); + } + } + sexOptions.push({text: `Abuse ${him}`, scene: `FAbuse`}); + if (V.seeIncest === 1) { + const availRelatives = availableRelatives(slave); + if (availRelatives.mother) { + sexOptions.push({text: `Fuck ${him} with ${his} mother`, scene: `FRelation`, update: {partner: "mother"}}); + } else if (availRelatives.motherName !== null) { + sexOptions.push({text: `${His} mother, ${availRelatives.motherName}, is unavailable`}); + } + /* + if (availRelatives.father) { + sexOptions.push({text: `Fuck ${him} with ${his} father`, scene: `FRelation`, update: {partner: "father"}}); + } else if (availRelatives.fatherName !== null) { + sexOptions.push({text: `${His} father, ${availRelatives.motherName}, is unavailable`}); + } + */ + if (slave.daughters > 0) { + if (availRelatives.daughters === 0) { + if (slave.daughters === 1) { + sexOptions.push({text: `Fuck ${him} with ${his} daughter`, disabled: `${His} ${availRelatives.oneDaughterRel} is unavailable`}); + } else { + sexOptions.push({text: `Fuck ${him} with one of ${his} daughters`, disabled: `${His} daughters are unavailable`}); + } + } else { + if (slave.daughters === 1) { + sexOptions.push({text: `Fuck ${him} with ${his} ${availRelatives.oneDaughterRel}`, scene: `FRelation`, update: {partner: "daughter"}}); + } else { + sexOptions.push({text: `Fuck ${him} with one of ${his} daughters`, scene: `FRelation`, update: {partner: "daughter"}}); + } + /* + if (availRelatives.daughters > 1) { + sexOptions.push({text: `Fuck ${him} with ${his} daughters`, scene: `FRelation`, update: {partner: "daughter"}}); + } + */ + } + } + if (slave.sisters > 0) { + if (availRelatives.sisters === 0) { + if (slave.sisters === 1) { + sexOptions.push({text: `Fuck ${him} with ${his} sister`, disabled: `${His} ${availRelatives.oneSisterRel} is unavailable`}); + } else { + sexOptions.push({text: `Fuck ${him} with one of ${his} sisters`, disabled: `${His} sisters are unavailable`}); + } + } else { + if (slave.sisters === 1) { + sexOptions.push({text: `Fuck ${him} with ${his} ${availRelatives.oneSisterRel}`, scene: `FRelation`, update: {partner: "sister"}}); + } else { + sexOptions.push({text: `Fuck ${him} with one of ${his} sisters`, scene: `FRelation`, update: {partner: "sister"}}); + } + /* + if (availRelatives.sisters > 1) { + sexOptions.push({text: `Fuck ${him} with ${his} sisters`, scene: `FRelation`, update: {partner: "sisters}}); + } + */ + } + } + } + if (slave.relationship > 0) { + const lover = getSlave(slave.relationshipTarget); + if (isSlaveAvailable(lover)) { + sexOptions.push({text: `Fuck ${him} with ${his} ${relationshipTermShort(slave)} ${SlaveFullName(lover)}`, scene: `FRelation`, update: {partner: "relationship"}}); + } else if (lover.assignment === Job.AGENT) { + if (slave.broodmother < 2) { + sexOptions.push({text: `Send ${him} to live with your agent ${SlaveFullName(lover)}`, goto: `Agent Company`, update: {subSlave: lover}}); + } else { + sexOptions.push({text: `A hyper-broodmother cannot be sent to live with your agent`}); + } + } else { + sexOptions.push({text: `${SlaveFullName(lover)} is unavailable`}); + } + } + if (slave.rivalryTarget !== 0 && hasAllLimbs(slave)) { + const rival = getSlave(slave.relationshipTarget); + if (isSlaveAvailable(rival) && hasAnyLegs(rival)) { + sexOptions.push({text: `Abuse ${his} rival with ${him}`, scene: `FRival`}); + } + } + if (slave.fetish !== "mindbroken" && (canTalk(slave) || hasAnyArms(slave))) { + sexOptions.push({text: `Ask ${him} about ${his} feelings`, scene: `FFeelings`}); + if (V.PC.dick > 0) { + sexOptions.push({text: `Make ${him} beg`, scene: `FBeg`}); + } + } + if (slave.devotion >= 100 && slave.relationship < 0 && slave.relationship > -3) { + sexOptions.push({text: `Talk to ${him} about relationships`, goto: `Matchmaking`, update: {subSlave: 0}}); + } + let ML = V.marrying.length; + if ((V.policies.mixedMarriage === 1 || V.cheatMode === 1) && slave.relationship !== 5 && slave.relationship !== -3) { + if (V.marrying.includes(slave.ID)) { + sexOptions.push({text: `Marry ${him}`, disabled: `You are already marrying ${him} this weekend`}); + } else { + if (ML < 2) { + if (V.cheatMode === 1 || ML === 0) { + sexOptions.push({text: `Marry ${him}`, goto: "FMarry"}); + } else { + sexOptions.push({text: `Marry ${him}`, disabled: `You already have a wedding planned for this weekend`}); + } + } else { + sexOptions.push({text: `Marry ${him}`, disabled: `You can only marry up to two slaves per week`}); + } + } + } + if (V.cheatMode === 1) { + sexOptions.push({text: `Check ${his} stats`, goto: `Slave Stats`}); + } + } else { + /* IS A FUCKDOLL */ + sexOptions.push({text: `Fuck ${his} face hole`, scene: `FFuckdollOral`}); + if (canDoVaginal(slave)) { + sexOptions.push({text: `Fuck ${his} front hole`, scene: `FFuckdollVaginal`}); + } + if (canGetPregnant(slave) && (slave.geneticQuirks.superfetation !== 2 || V.geneticMappingUpgrade !== 0) && V.seePreg !== 0) { + if (canImpreg(slave, V.PC)) { + sexOptions.push({text: `Put a baby in ${him}`, scene: `FFuckdollImpreg`}); + } + } + if (canDoAnal(slave)) { + sexOptions.push({text: `Fuck ${his} rear hole`, scene: `FFuckdollAnal`}); + } + } + let activeSlaveRepSacrifice = repGainSacrifice(slave, V.arcologies[0]); + if (activeSlaveRepSacrifice > 0 && V.arcologies[0].FSPaternalist === "unset" && (slave.breedingMark === 0 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) { + sexOptions.push({ + text: `Sacrifice ${him} on the altar`, + goto: `Aztec Slave Sacrifice`, + note: `This will kill ${him} and gain you ${activeSlaveRepSacrifice} reputation`, + update: {sacrificeType: "life"} + }); + } + el.append(`Use ${him}: `); + el.appendChild(generateRows(sexOptions)); + if (!jQuery.isEmptyObject(fillFaceOptions)) { + let fill = document.createElement('div'); + fill.appendChild(document.createTextNode(` Fill ${his} mouth with: `)); + fill.appendChild(generateRows(fillFaceOptions)); + el.appendChild(fill); + } + if (!jQuery.isEmptyObject(fillAssOptions)) { + let fill = document.createElement('div'); + fill.appendChild(document.createTextNode(` Fill ${his} ass with: `)); + fill.appendChild(generateRows(fillAssOptions)); + el.appendChild(fill); + } + + function generateRows(sexArray) { + let row = document.createElement('span'); + for (let i = 0; i < sexArray.length; i++) { + let link; + const separator = document.createTextNode(` | `); + const keys = Object.keys(sexArray[i]); + + // Test to see if there was a problem with the key + for (let j = 0; j < keys.length; j++) { + if (!["disabled", "goto", "note", "scene", "text", "update", "updateSlave"].includes(keys[j])) { + sexArray[i].text += " ERROR, THIS SCENE WAS NOT ENTERED CORRECTLY"; + console.log("Trash found while generateRows() was running: " + keys[j] + ": " + sexArray[i][keys[j]]); + break; + } + } + // is it just text? + if (sexArray[i].disabled) { + link = App.UI.DOM.disabledLink(sexArray[i].text, [sexArray[i].disabled]); + } else { + let passage = ""; + if (sexArray[i].goto) { + passage = sexArray[i].goto; + } + + // Set up the link + link = App.UI.DOM.link( + sexArray[i].text, + () => { click(sexArray[i]); }, + [], + passage + ); + + // add a note node if required + if (sexArray[i].note) { + link.appendChild(App.UI.DOM.makeElement('span', sexArray[i].note, 'note')); + } + } + row.appendChild(link); + if (i < sexArray.length - 1) { + row.appendChild(separator); + } + } + + return row; + + function click(sexOption) { + if (sexOption.updateSlave) { + Object.assign(slave, sexOption.updateSlave); + } + if (sexOption.update) { + Object.assign(V, sexOption.update); + } + + if (sexOption.goto) { + // just play the passage, no need to refresh anything here + Engine.play(sexOption.goto); + } else if (sexOption.scene) { + // Run scene and store render results temporarily + let frag = App.UI.DOM.renderPassage(sexOption.scene); + + // Refresh (clears scene display) + App.UI.SlaveInteract.refreshAll(slave); + + // Display scene render results + $("#mini-scene").append(frag); + } else { + // just refresh + App.UI.SlaveInteract.refreshAll(slave); + } + } + } + return el; + } + + function fucktoyPref() { + const el = document.createElement('div'); + let links = []; + + function appendLink(text, toyHole, enabled, disabledText) { + const link = {text: text}; + if (enabled) { + link.toyHole = toyHole; + } else { + link.disabled = disabledText; + } + links.push(link); + } + + if ((slave.assignment === App.Data.Facilities.penthouse.jobs.fucktoy.assignment) || (slave.assignment === App.Data.Facilities.masterSuite.jobs.fucktoy.assignment) || (slave.assignment === App.Data.Facilities.masterSuite.manager.assignment)) { + App.UI.DOM.appendNewElement("span", el, "Fucktoy use preference:", "story-label"); + el.append(` `); + + const hole = App.UI.DOM.appendNewElement('span', el, `${slave.toyHole}. `); + hole.style.fontWeight = "bold"; + + appendLink('Mouth', 'mouth', true); + appendLink('Tits', 'boobs', true); + if (slave.vagina >= 0) { + appendLink('Pussy', 'pussy', slave.vagina > 0 && canDoVaginal(slave), `Take ${his} virginity before giving ${his} pussy special attention`); + } + appendLink('Ass', 'ass', (slave.anus > 0) && canDoAnal(slave), `Take ${his} anal virginity before giving ${his} ass special attention`); + if (slave.dick > 0 && canPenetrate(slave)) { + appendLink('Dick', 'dick', true); + } + appendLink('No Preference', "all her holes", true); + } + + function generateLink(linkDesc) { + // is it just text? + if (linkDesc.disabled) { return App.UI.DOM.disabledLink(linkDesc.text, [linkDesc.disabled]); } + // Are they already on this toyHole? + if (linkDesc.toyHole === slave.toyHole) { return document.createTextNode(linkDesc.text); } + // Set up the link + const link = App.UI.DOM.link( + linkDesc.text, + () => { + slave.toyHole = linkDesc.toyHole; + jQuery('#fucktoy-pref').empty().append(fucktoyPref()); + }, + ); + + // add a note node if required + if (linkDesc.note) { + App.UI.DOM.appendNewElement("span", link, linkDesc.note, "note"); + } + return link; + } + + el.appendChild(App.UI.DOM.generateLinksStrip(links.map(generateLink))); + + return el; + } + } + + function refresh() { + jQuery("#si-work").empty().append(work()); + } +}; diff --git a/src/interaction/slaveInteract.js b/src/interaction/slaveInteract.js index 6015d8ebe16dc56f5f0c1af8078e04c71df0365c..ea2705d4b2dac9a5208c2100b2a2c9e1c340a6a1 100644 --- a/src/interaction/slaveInteract.js +++ b/src/interaction/slaveInteract.js @@ -1,3395 +1,196 @@ -/* eslint-disable no-unused-vars */ // TODO: remove after testing - -/** Find the previous and next slaves' IDs based on the current sort order - * @param {App.Entity.SlaveState} slave - * @returns {[number, number]} - previous and next slave ID - */ -App.UI.SlaveInteract.placeInLine = function(slave) { - const useSlave = assignmentVisible(slave) ? ((s) => assignmentVisible(s)) : ((s) => slave.assignment === s.assignment); - const slaveList = V.slaves.filter(useSlave); - SlaveSort.slaves(slaveList); - const curSlaveIndex = slaveList.findIndex((s) => s.ID === slave.ID); - - let nextIndex; - if (curSlaveIndex + 1 > slaveList.length - 1) { - nextIndex = 0; // wrap around to first slave - } else { - nextIndex = curSlaveIndex + 1; - } - let prevIndex; - if (curSlaveIndex - 1 < 0) { - prevIndex = slaveList.length - 1; // wrap around to last slave - } else { - prevIndex = curSlaveIndex - 1; - } - - return [slaveList[prevIndex].ID, slaveList[nextIndex].ID]; -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {HTMLParagraphElement} - */ -App.UI.SlaveInteract.navigation = function(slave) { - const p = document.createElement("p"); - p.classList.add("center"); - - if (V.cheatMode) { - const div = document.createElement("div"); - div.classList.add("note"); - div.append(App.UI.DOM.passageLink("Cheat Edit Slave", "MOD_Edit Slave Cheat", () => { V.cheater = 1; }), - " | ", - App.UI.DOM.passageLink("Cheat Edit Slave Alternative", "MOD_Edit Slave Cheat New", () => { V.cheater = 1; })); - p.append(div); - } - - App.UI.DOM.appendNewElement("span", p, App.UI.Hotkeys.hotkeys("prev-slave"), "hotkey"); - const prevSpan = App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Prev", "Slave Interact", - () => { V.AS = App.UI.SlaveInteract.placeInLine(slave)[0]; }), "adjacent-slave"); - prevSpan.id = "prev-slave"; - p.append(" ", prevSpan); - - const centerSpan = document.createElement("span"); - centerSpan.classList.add("interact-name"); - - App.UI.DOM.appendNewElement("span", centerSpan, slave.slaveName, "slave-name"); - - const favSpan = document.createElement("span"); - favSpan.id = "fav-span"; - favSpan.append(favLink()); - - centerSpan.append(" ", favSpan); - p.append(centerSpan); - - const nextSpan = App.UI.DOM.makeElement("span", App.UI.DOM.passageLink("Next", "Slave Interact", - () => { V.AS = App.UI.SlaveInteract.placeInLine(slave)[1]; }), "adjacent-slave"); - nextSpan.id = "next-slave"; - p.append(nextSpan, " "); - App.UI.DOM.appendNewElement("span", p, App.UI.Hotkeys.hotkeys("next-slave"), "hotkey"); - - return p; - - function favLink() { - if (V.favorites.includes(slave.ID)) { - const link = App.UI.DOM.link(String.fromCharCode(0xe800), () => { - V.favorites.delete(slave.ID); - App.UI.DOM.replace("#fav-span", favLink()); - }); - link.classList.add("icons", "favorite"); - return link; - } else { - const link = App.UI.DOM.link(String.fromCharCode(0xe801), () => { - V.favorites.push(slave.ID); - App.UI.DOM.replace("#fav-span", favLink()); - }); - link.classList.add("icons", "not-favorite"); - return link; +App.UI.SlaveInteract.mainPage = function(slave) { + const el = new DocumentFragment(); + App.UI.tabBar.handlePreSelectedTab(V.tabChoice.SlaveInteract); + + if (!assignmentVisible(slave)) { + switch (slave.assignment) { + case "work in the brothel": + case "be the Madam": + V.nextLink = "Brothel"; + break; + case "be confined in the arcade": + V.nextLink = "Arcade"; + break; + case "serve in the club": + case "be the DJ": + V.nextLink = "Club"; + break; + case "work in the dairy": + case "be the Milkmaid": + V.nextLink = "Dairy"; + break; + case "work as a farmhand": + case "be the Farmer": + V.nextLink = "Farmyard"; + break; + case "rest in the spa": + case "be the Attendant": + V.nextLink = "Spa"; + break; + case "work as a nanny": + case "be the Matron": + V.nextLink = "Nursery"; + break; + case "learn in the schoolroom": + case "be the Schoolteacher": + V.nextLink = "Schoolroom"; + break; + case "work as a servant": + case "be the Stewardess": + V.nextLink = "Servants' Quarters"; + break; + case "serve in the master suite": + case "be your Concubine": + V.nextLink = "Master Suite"; + break; + case "be confined in the cellblock": + case "be the Wardeness": + V.nextLink = "Cellblock"; + break; + case "get treatment in the clinic": + case "be the Nurse": + V.nextLink = "Clinic"; + break; + case "live with your Head Girl": + V.nextLink = "Head Girl Suite"; + break; + case "be your agent": + case "live with your agent": + V.nextLink = "Neighbor Interact"; } } -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {Node} - */ -App.UI.SlaveInteract.modify = function(slave) { - const {he, his} = getPronouns(slave); - let el = new DocumentFragment(); - - const isAgent = [Job.AGENT, Job.AGENTPARTNER].includes(slave.assignment); - - App.UI.DOM.appendNewElement('p', el, isAgent ? "Recall your agent to modify them." : "Take slave to another room.", "scene-intro"); - if (isAgent) { - return el; + V.encyclopedia = either("Costs Summary", "Disease in the Free Cities", "Drugs and Their Effects", "From Rebellious to Devoted", "Gender", "Independent Slaves", "Modern Anal", "Nymphomania", "Slave Couture"); + if (slave.dick > 0) { + V.encyclopedia = "Gender"; } + App.Utils.scheduleSidebarRefresh(); /** - * Create a link with a note to send a slave to a specific room - * @param {Node} c - * @param {string} caption - * @param {string} passage - * @param {string} note - * @param {function ():void} [handler] + * @typedef {Object} siCategory + * @property {string} title + * @property {string} id + * @property {Node} node + * @property {Function} [onClick] */ - function makeRoomLink(c, caption, passage, note, handler = () => {}) { - const res = document.createElement('div'); - c.appendChild(res); - res.appendChild(App.UI.DOM.link(caption, handler, [], passage)); - App.UI.DOM.appendNewElement('span', res, note, "note"); - return res; - } - makeRoomLink(el, "Auto salon", "Salon", ' Modify hair (color, length, style), nails, and even skin color.'); - - makeRoomLink(el, "Body mod studio", "Body Modification", ' Mark your slave with piercings, tattoos, brands or even scars.', - () => { - V.degradation = 0; - V.tattooChoice = undefined; + /** @type {Array<siCategory>} */ + const buttons = [ + { + title: "Description", + id: "description", + get node() { return App.UI.SlaveInteract.description(slave); } }, - ); - - makeRoomLink(el, "Remote surgery", "Remote Surgery", ` Surgically modify your slave with state of the art plastic surgery and more. Alter ${his} senses, skeletal structure, organs, and even more.`); - - // Prosthetics - if (V.prostheticsUpgrade > 0) { - makeRoomLink(el, "Configure cybernetics", "Prosthetics Configuration", ` Configure prosthetics, if ${he} has been surgically implanted with interfaces that support it.`, - () => { - V.prostheticsConfig = "main"; - } - ); - } - - // Analyze Pregnancy - if (V.pregnancyMonitoringUpgrade > 0) { - makeRoomLink(el, "Internal scan", "Analyze Pregnancy", ` Full scan of abdomen and reproductive organs.`); - } - - return el; -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {HTMLElement} - */ -App.UI.SlaveInteract.fucktoyPref = function(slave) { - const {his} = getPronouns(slave); - const el = document.createElement('div'); - let links = []; - - function appendLink(text, toyHole, enabled, disabledText) { - const link = {text: text}; - if (enabled) { - link.toyHole = toyHole; - } else { - link.disabled = disabledText; - } - links.push(link); - } - - if ((slave.assignment === App.Data.Facilities.penthouse.jobs.fucktoy.assignment) || (slave.assignment === App.Data.Facilities.masterSuite.jobs.fucktoy.assignment) || (slave.assignment === App.Data.Facilities.masterSuite.manager.assignment)) { - App.UI.DOM.appendNewElement("span", el, "Fucktoy use preference:", "story-label"); - el.append(` `); - - const hole = App.UI.DOM.appendNewElement('span', el, `${slave.toyHole}. `); - hole.style.fontWeight = "bold"; - - appendLink('Mouth', 'mouth', true); - appendLink('Tits', 'boobs', true); - if (slave.vagina >= 0) { - appendLink('Pussy', 'pussy', slave.vagina > 0 && canDoVaginal(slave), `Take ${his} virginity before giving ${his} pussy special attention`); - } - appendLink('Ass', 'ass', (slave.anus > 0) && canDoAnal(slave), `Take ${his} anal virginity before giving ${his} ass special attention`); - if (slave.dick > 0 && canPenetrate(slave)) { - appendLink('Dick', 'dick', true); - } - appendLink('No Preference', "all her holes", true); - } - - function generateLink(linkDesc) { - // is it just text? - if (linkDesc.disabled) { return App.UI.DOM.disabledLink(linkDesc.text, [linkDesc.disabled]); } - // Are they already on this toyHole? - if (linkDesc.toyHole === slave.toyHole) { return document.createTextNode(linkDesc.text); } - // Set up the link - const link = App.UI.DOM.link( - linkDesc.text, - () => { - slave.toyHole = linkDesc.toyHole; - jQuery('#fucktoy-pref').empty().append(App.UI.SlaveInteract.fucktoyPref(slave)); - }, - ); - - // add a note node if required - if (linkDesc.note) { - App.UI.DOM.appendNewElement("span", link, linkDesc.note, "note"); - } - return link; - } - - el.appendChild(App.UI.DOM.generateLinksStrip(links.map(generateLink))); - - return el; -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {JQuery<HTMLElement>} - */ -App.UI.SlaveInteract.work = function(slave) { - let el = new DocumentFragment(); - let p; - let div; - let span; - const links = []; - const { - He, - him - } = getPronouns(slave); - - function appendLink(text, whoreClass, enabled, disabledText) { - const link = {text: text}; - if (enabled) { - link.whoreClass = whoreClass; - } else { - link.disabled = disabledText; - } - links.push(link); - } - - p = document.createElement('p'); - if (slave.assignment === Job.AGENT) { - const arc = V.arcologies.find((a) => a.leaderID === slave.ID); - p.className = "scene-intro"; - p.textContent = `${He} is serving as your Agent${arc ? ` leading ${arc.name}` : ` but is not currently assigned to an arcology`}. `; - p.appendChild(App.UI.DOM.link(`Recall and reenslave ${him}`, () => { removeJob(slave, slave.assignment, false); App.UI.SlaveInteract.work(slave); })); - } else if (slave.assignment === Job.AGENTPARTNER) { - const agent = getSlave(slave.relationshipTarget); - const arc = agent ? V.arcologies.find((a) => a.leaderID === agent.ID) : null; - p.className = "scene-intro"; - p.textContent = `${He} is living with your Agent ${SlaveFullName(agent)}${arc ? ` in ${arc.name}` : ``}. `; - p.appendChild(App.UI.DOM.link(`Recall ${him}`, () => { removeJob(slave, slave.assignment, false); App.UI.SlaveInteract.work(slave); })); - } else { - div = document.createElement('div'); - div.id = "mini-scene"; - p.appendChild(div); - - span = document.createElement('span'); - span.id = "useSlave"; - p.appendChild(span); - p.appendChild(App.UI.SlaveInteract.useSlaveDisplay(slave)); - } - el.append(p); - - p = document.createElement('p'); - span = document.createElement('span'); - span.className = "note"; - switch (slave.assignment) { - case Job.BODYGUARD: - span.textContent = `${He} is your Bodyguard and is not available for other work`; - break; - case Job.MADAM: - span.textContent = `${He} is the Madam and is not available for other work`; - break; - case Job.DJ: - span.textContent = `${He} is the DJ and is not available for other work`; - break; - case Job.MILKMAID: - span.textContent = `${He} is the Milkmaid and is not available for other work`; - break; - case Job.FARMER: - span.textContent = `${He} is the Farmer and is not available for other work`; - break; - case Job.STEWARD: - span.textContent = `${He} is the Stewardess and is not available for other work`; - break; - case Job.HEADGIRL: - span.textContent = `${He} is your Head Girl and is not available for other work`; - break; - case Job.RECRUITER: - span.textContent = `${He} is recruiting slaves and is not available for other work`; - break; - case Job.NURSE: - span.textContent = `${He} is the Nurse and is not available for other work`; - break; - case Job.ATTENDANT: - span.textContent = `${He} is the Attendant of the spa and is not available for other work`; - break; - case Job.MATRON: - span.textContent = `${He} is the Matron of the nursery and is not available for other work`; - break; - case Job.TEACHER: - span.textContent = `${He} is the Schoolteacher and is not available for other work`; - break; - case Job.CONCUBINE: - span.textContent = `${He} is your Concubine and is not available for other work`; - break; - case Job.WARDEN: - span.textContent = `${He} is the Wardeness and is not available for other work`; - break; - default: - // CAN BE REASSIGNED - span.classList.remove("note"); - span.id = "assignmentLinks"; - span.appendChild(App.UI.SlaveInteract.assignmentBlock(slave)); - - if ((V.brothel + V.club + V.dairy + V.farmyard + V.servantsQuarters + V.masterSuite + V.spa + V.nursery + V.clinic + V.schoolroom + V.cellblock + V.arcade + V.HGSuite) > 0) { - span.append(`Transfer to: `); - span.appendChild(App.UI.jobLinks.transfersFragment(slave.ID)); - } - - div = document.createElement('div'); - div.id = "fucktoy-pref"; - div.append(App.UI.SlaveInteract.fucktoyPref(slave)); - span.appendChild(div); - } - el.append(span); - - if (slave.assignment === Job.WHORE || slave.assignment === Job.BROTHEL) { - div = document.createElement('div'); - div.textContent = `Whoring Target: `; - span = document.createElement('span'); - span.style.fontWeight = "bold"; - - span.id = "whoreClass"; - if (!slave.whoreClass) { - span.textContent = `auto`; - } else if (slave.whoreClass === 1) { - span.textContent = `the lower class`; - } else if (slave.whoreClass === 2) { - span.textContent = `the middle class`; - } else if (slave.whoreClass === 3) { - span.textContent = `the upper class`; - } else if (slave.whoreClass === 4) { - span.textContent = `millionaires`; - } else { - span.textContent = `THERE HAS BEEN AN ERROR`; - } - div.append(span); - div.append(`. `); - - div.append(App.UI.DOM.makeElement('span', `This is the highest class they are allowed to service, when eligible `, 'note')); - - appendLink(`Auto`, 0, true); - appendLink(`Lower Class`, 1, true); - appendLink(`Middle Class`, 2, true); - appendLink(`Upper Class`, 3, true); - appendLink(`Millionaires Class`, 4, true); - div.appendChild(App.UI.DOM.generateLinksStrip(links.map(generateLink))); - - el.append(div); - } - - el.append(App.UI.SlaveInteract.tutorBlock(slave)); - - function generateLink(linkDesc) { - // is it just text? - if (linkDesc.disabled) { return App.UI.DOM.disabledLink(linkDesc.text, [linkDesc.disabled]); } - // Are they already on this whoreClass? - if (linkDesc.whoreClass === slave.whoreClass) { return document.createTextNode(linkDesc.text); } - // Set up the link - const link = App.UI.DOM.link( - linkDesc.text, - () => { - slave.whoreClass = linkDesc.whoreClass; - App.UI.SlaveInteract.work(slave); - }, - ); - - // add a note node if required - if (linkDesc.note) { - App.UI.DOM.appendNewElement("span", link, linkDesc.note, "note"); - } - return link; - } - - return jQuery('#work').empty().append(el); -}; - -/** - * @param {App.Entity.SlaveState} slave - * @returns {HTMLElement} - */ -App.UI.SlaveInteract.assignmentBlock = function(slave) { - let el = document.createElement('div'); - let title = document.createElement('div'); - let separator = document.createTextNode(` | `); - title.append(`Assignment: `); - - let assign = document.createElement('span'); - assign.style.fontWeight = "bold"; - if (slave.sentence) { - assign.textContent = `${slave.assignment} (${slave.sentence} weeks). `; - } else { - assign.textContent = `${slave.assignment}. `; - } - title.appendChild(assign); - if (V.assignmentRecords[slave.ID] && V.assignmentRecords[slave.ID] !== slave.assignment) { - title.append(`Previously: `); - assign = document.createElement('span'); - assign.style.fontWeight = "bold"; - assign.textContent = `${V.assignmentRecords[slave.ID]}. `; - title.appendChild(assign); - } - if (slave.assignment === Job.SUBORDINATE) { - const target = getSlave(slave.subTarget); - let linkText = ``; - if (target) { - title.appendChild(document.createTextNode(`Serving ${target.slaveName} exclusively. `)); - linkText = `Change`; - } else if (slave.subTarget === -1) { - title.appendChild(document.createTextNode(`Serving as a Stud. `)); - linkText = `Change role`; - } else { - title.appendChild(document.createTextNode(`Serving all your other slaves. `)); - linkText = `Choose a specific slave to submit to`; + { + title: "Modify", + id: "modify", + get node() { return App.UI.SlaveInteract.modify(slave); } + }, + { + title: "Work", + id: "work", + get node() { return App.UI.SlaveInteract.work(slave); } + }, + { + title: "Appearance", + id: "appearance", + get node() { return App.UI.SlaveInteract.wardrobe(slave); } + }, + { + title: "Physical Regimen", + id: "physical-regimen", + get node() { return App.UI.SlaveInteract.physicalRegimen(slave); } + }, + { + title: "Rules", + id: "rules", + get node() { return App.UI.SlaveInteract.rules(slave); } + }, + { + title: "Financial", + id: "financial", + get node() { return App.UI.SlaveInteract.financial(slave); } + }, + { + title: "Customize", + id: "customize", + get node() { return App.UI.SlaveInteract.custom(slave); } + }, + { + title: "Family", + id: "family-tab", + onClick: () => renderFamilyTree(V.slaves, slave.ID), + get node() { return App.UI.SlaveInteract.family(); } } - title.appendChild(App.UI.DOM.passageLink(linkText, "Subordinate Targeting", () => { V.returnTo = "Slave Interact"; })); - title.append(separator); - } - if (slave.assignment !== Job.CHOICE) { - title.appendChild( - App.UI.DOM.link( - `Stay on this assignment for another month`, - () => { - slave.sentence += 4; - App.UI.SlaveInteract.work(slave); - }, - ) - ); - } - el.appendChild(title); - - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild( - App.UI.jobLinks.assignmentsFragment( - slave.ID, passage(), - (slave, assignment) => { - assignJob(slave, assignment); - } - ) - ); - el.appendChild(links); - return el; -}; + ]; -/** - * @param {App.Entity.SlaveState} slave - * @returns {HTMLDivElement} - */ -App.UI.SlaveInteract.tutorBlock = function(slave) { - let el = App.UI.DOM.makeElement("div"); - let title = App.UI.DOM.appendNewElement("div", el, `Private tutoring: `); - let tutor = tutorForSlave(slave); + el.append(App.UI.SlaveInteract.navigation(slave)); - if (tutor === null) { - App.UI.DOM.appendNewElement("span", title, `none.`, "bold"); + if (V.slaveInteractLongForm) { + el.append(displayWithoutTabs()); } else { - App.UI.DOM.appendNewElement("span", title, tutor + `.`, "bold"); - } - - if (tutor != null) { - App.UI.DOM.appendNewElement("span", title, ` To progress slave needs to be assigned to: "` + Job.CLASSES + `" or "` + Job.SCHOOL + `".`, "note"); - } - - let list = ["None"]; - for (const keys of Object.keys(V.slaveTutor)) { - list.push(keys); - } - const array = list.map((s) => { - if (shouldBeEnabled(slave, s)) { - return App.UI.DOM.link(s, () => setTutorForSlave(slave, s)); - } else { - let reason = ["Already being taught this skill."]; - return App.UI.DOM.disabledLink(s, reason); - } - }); - App.UI.DOM.appendNewElement("div", el, App.UI.DOM.generateLinksStrip(array)); - - function shouldBeEnabled(slave, key) { - let tutor = tutorForSlave(slave); - if (tutor === null) { - return "None"; - } - return (tutor !== key); - } - - function setTutorForSlave(slave, tutor) { - const cur = tutorForSlave(slave); - - if (tutor !== cur && cur != null) { - V.slaveTutor[cur].delete(slave.ID); - } - - if (cur !== tutor && tutor !== "None") { - V.slaveTutor[tutor].push(slave.ID); - } - App.UI.SlaveInteract.work(slave); + el.append(displayWithTabs()); } return el; -}; - -/** - * @param {App.Entity.SlaveState} slave - */ -App.UI.SlaveInteract.drugs = function(slave) { - let el = document.createElement('div'); - const drugLevelOptions = []; - const lips = []; - const breasts = []; - const nipples = []; - const butt = []; - const dick = []; - const balls = []; - const fertility = []; - const hormones = []; - const psych = []; - const misc = []; + function displayWithTabs() { + const el = new DocumentFragment(); - if (slave.drugs !== "no drugs") { - drugLevelOptions.push({text: `None`, updateSlave: {drugs: `no drugs`}}); - } - if (slave.indentureRestrictions < 2) { - // Psych - if (slave.intelligence > -100 && slave.indentureRestrictions < 1) { - psych.push({text: `Psychosuppressants`, updateSlave: {drugs: `psychosuppressants`}}); - } else if (slave.intelligence > -100) { - psych.push({text: `Psychosuppressants`, disabled: `Cannot suppress indentured slave`}); - } else if (slave.indentureRestrictions < 1) { - psych.push({text: `Psychosuppressants`, disabled: `Too stupid to suppress`}); - } else { - psych.push({text: `Psychosuppressants`, disabled: `Too stupid and indentured to suppress`}); - } - if (V.arcologies[0].FSSlaveProfessionalismResearch === 1) { - if (canImproveIntelligence(slave)) { - psych.push({text: `Psychostimulants`, updateSlave: {drugs: `psychostimulants`}}); - } else { - psych.push({text: `Psychostimulants`, disabled: `Cannot improve intelligence`}); - } - } + const tabBar = document.createElement("div"); + tabBar.classList.add("tab-bar"); + const tabContents = new DocumentFragment(); - // Breasts - if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { - if ((slave.boobs - slave.boobsImplant - slave.boobsMilk) > 100) { - breasts.push({text: `Reducers`, updateSlave: {drugs: `breast redistributors`}}); - } else { - breasts.push({text: `Reducers`, disabled: `Boobs are too small`}); - } - } - if (slave.boobs < 50000) { - breasts.push({text: `Enhancement`, updateSlave: {drugs: `breast injections`}}); - breasts.push({text: `Intensive enhancement`, updateSlave: {drugs: `intensive breast injections`}}); - } else { - breasts.push({text: `Enhancement`, disabled: `Boobs are too large`}); - } - if (V.arcologies[0].FSAssetExpansionistResearch === 1) { - if (slave.boobs < 50000) { - breasts.push({text: `Hyper enhancement`, updateSlave: {drugs: `hyper breast injections`}}); - } else { - breasts.push({text: `Hyper enhancement`, disabled: `Boobs are too large`}); - } + for (const item of buttons) { + tabBar.append(makeTabButton(item)); + tabContents.append(makeTabContents(item)); } - // Nipples - if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { - if (slave.nipples === "huge" || slave.nipples === "puffy" || slave.nipples === "cute") { - nipples.push({text: `Reducers`, updateSlave: {drugs: `nipple atrophiers`}}); - } else { - nipples.push({text: `Reducers`, disabled: `Nipples are ${slave.nipples}`}); - } - } - if (V.dispensary) { - if (["inverted", "partially inverted", "cute", "tiny", "puffy"].includes(slave.nipples)) { - nipples.push({text: `Enhancement`, updateSlave: {drugs: `nipple enhancers`}}); - } else if (slave.nipples === "huge") { - nipples.push({text: `Enhancement`, disabled: `Nipples are already huge`}); - } else { - nipples.push({text: `Enhancement`, disabled: `Has no effect on ${slave.nipples} nipples`}); - } - } + el.append(tabBar); - // Butt - if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { - if (slave.butt - slave.buttImplant > 0) { - butt.push({text: `Reducers`, updateSlave: {drugs: `butt redistributors`}}); - } else { - butt.push({text: `Reducers`, disabled: `Butt is too small`}); - } - } - if (slave.butt < 9) { - butt.push({text: `Enhancement`, updateSlave: {drugs: `butt injections`}}); - butt.push({text: `Intensive enhancement`, updateSlave: {drugs: `intensive butt injections`}}); - } else { - butt.push({text: `Enhancement`, disabled: `Butt is too large`}); - } - if (V.arcologies[0].FSAssetExpansionistResearch === 1) { - if (slave.butt < 20) { - butt.push({text: `Hyper enhancement`, updateSlave: {drugs: `hyper butt injections`}}); - } else { - butt.push({text: `Hyper enhancement`, disabled: `Butt is too large`}); - } - } + App.Events.drawEventArt(el, slave); - // Lips - if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { - if (slave.lips - slave.lipsImplant > 0) { - lips.push({text: `Reducers`, updateSlave: {drugs: `lip atrophiers`}}); - } else { - lips.push({text: `Reducers`, disabled: `Lips are too small`}); - } - } - if (slave.lips <= 95 || (slave.lips <= 85 && V.seeExtreme !== 1)) { - lips.push({text: `Enhancement`, updateSlave: {drugs: `lip injections`}}); - } else { - lips.push({text: `Enhancement`, disabled: `Lips are too large`}); - } + el.append(tabContents); - // Fertility - fertility.push({text: `Fertility`, updateSlave: {drugs: `fertility drugs`}}); - if (V.seeHyperPreg === 1 && slave.indentureRestrictions < 1 && V.superFertilityDrugs === 1 && (slave.breedingMark !== 1 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) { - fertility.push({text: `Fertility+`, updateSlave: {drugs: `super fertility drugs`}}); - } + return el; - // Dick/clit - if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { - if (slave.dick > 1) { - dick.push({text: `Reducers`, updateSlave: {drugs: `penis atrophiers`}}); - } else if (slave.dick === 1) { - dick.push({text: `Reducers`, disabled: `Dick is already at minimum size`}); - } - if (slave.clit > 0) { - dick.push({text: `Reducers`, updateSlave: {drugs: `clitoris atrophiers`}}); - } - } - if (slave.dick > 0) { - if (slave.dick < 10) { - dick.push({text: `Enhancement`, updateSlave: {drugs: `penis enhancement`}}); - dick.push({text: `Intensive enhancement`, updateSlave: {drugs: `intensive penis enhancement`}}); - } else { - dick.push({text: `Enhancement`, disabled: `Dick is too large`}); - } - } else { - if (slave.clit < 5) { - dick.push({text: `Enhancement`, updateSlave: {drugs: `penis enhancement`}}); - dick.push({text: `Intensive enhancement`, updateSlave: {drugs: `intensive penis enhancement`}}); - } else { - dick.push({text: `Enhancement`, disabled: `Clit is too large`}); - } - } - if (V.arcologies[0].FSAssetExpansionistResearch === 1) { - if (slave.dick > 0) { - if (slave.dick < 31) { - dick.push({text: `Hyper enhancement`, updateSlave: {drugs: `hyper penis enhancement`}}); - } else { - dick.push({text: `Hyper enhancement`, disabled: `Dick is too large`}); + function makeTabButton(item) { + const btn = document.createElement("button"); + btn.className = "tab-links"; + btn.id = `tab ${item.id}`; + btn.innerHTML = item.title; + btn.onclick = (event) => { + App.UI.tabBar.openTab(event, item.id); + if (item.hasOwnProperty("onClick")){ + item.onClick(); } - } else { - if (slave.clit < 5) { - dick.push({text: `Hyper enhancement`, updateSlave: {drugs: `penis enhancement`}}); - } else { - dick.push({text: `Hyper enhancement`, disabled: `Clit is too large`}); - } - } - } - if (slave.dick > 0 && slave.dick < 11 && !canAchieveErection(slave) && slave.chastityPenis !== 1) { - dick.push({text: `Erectile dysfunction circumvention`, updateSlave: {drugs: `priapism agents`}}); - } - - // Balls - if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { - if (slave.balls > 1) { - balls.push({text: `Reducers`, updateSlave: {drugs: `testicle atrophiers`}}); - } else if (slave.balls === 1) { - balls.push({text: `Reducers`, disabled: `Balls are already at minimum size`}); - } - } - if (slave.balls > 0) { - balls.push({text: `Enhancement`, updateSlave: {drugs: `testicle enhancement`}}); - balls.push({text: `Intensive enhancement`, updateSlave: {drugs: `intensive testicle enhancement`}}); - if (V.arcologies[0].FSAssetExpansionistResearch === 1) { - balls.push({text: `Hyper enhancement`, updateSlave: {drugs: `hyper testicle enhancement`}}); - } - } - - // Hormones - if (V.precociousPuberty === 1 && V.pubertyHormones === 1 && (slave.breedingMark !== 1 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) { - if ((slave.ovaries === 1 || slave.mpreg === 1) && slave.pubertyXX === 0) { - hormones.push({text: `Female injections`, updateSlave: {drugs: `female hormone injections`}}); - } - if (slave.balls > 0 && slave.pubertyXY === 0) { - hormones.push({text: `Male injections`, updateSlave: {drugs: `male hormone injections`}}); - } - } - hormones.push({text: `Blockers`, updateSlave: {drugs: `hormone blockers`}}); - hormones.push({text: `Enhancement`, updateSlave: {drugs: `hormone enhancers`}}); - - // Misc - if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { - if (slave.labia > 0) { - misc.push({text: `Labia reducers`, updateSlave: {drugs: `labia atrophiers`}}); - } - } - if (V.growthStim === 1) { - if (canImproveHeight(slave)) { - misc.push({text: `Growth Stimulants`, updateSlave: {drugs: `growth stimulants`}}); - } else { - misc.push({text: `Growth Stimulants`, disabled: `Cannot increase height further`}); - } - } - if (V.arcologies[0].FSSlimnessEnthusiastResearch === 1) { - if (slave.weight > -95) { - misc.push({text: `Weight loss pills`, updateSlave: {drugs: `appetite suppressors`}}); - } else { - misc.push({text: `Weight loss pills`, disabled: `Slave is already at low weight`}); - } - } - misc.push({text: `Steroids`, updateSlave: {drugs: `steroids`}}); - if (slave.boobs > 250 && slave.boobShape !== "saggy" && V.purchasedSagBGone === 1) { - misc.push({text: `Sag-B-Gone breast lifting cream`, updateSlave: {drugs: `sag-B-gone`}}); - } - if (V.arcologies[0].FSYouthPreferentialistResearch === 1) { - if (slave.visualAge > 18) { - misc.push({text: `Anti-aging cream`, updateSlave: {drugs: `anti-aging cream`}}); - } else { - misc.push({text: `Anti-aging cream`, disabled: `Slave already looks young enough`}); - } - } - } - - let title = document.createElement('div'); - title.textContent = `Drugs: `; - let chosenDrug = document.createElement('span'); - chosenDrug.textContent = `${capFirstChar(slave.drugs)}. `; - chosenDrug.style.fontWeight = "bold"; - title.append(chosenDrug); - title.appendChild(App.UI.SlaveInteract.generateRows(drugLevelOptions, slave)); - el.append(title); - - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Lips", lips, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Breasts", breasts, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Nipples", nipples, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Butt", butt, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, slave.dick > 0 ? "Dick" : "Clit", dick, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Balls", balls, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Fertility", fertility, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Hormones", hormones, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Psych", psych, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Misc", misc, slave); - - return jQuery('#drugs').empty().append(el); -}; - -App.UI.SlaveInteract.hormones = function(slave) { - let el = document.createElement('div'); - const options = []; - const level = []; - - if (slave.hormones !== 0) { - level.push({text: `None`, updateSlave: {hormones: 0}}); - } - - if (slave.indentureRestrictions < 2) { - options.push({text: `Intensive Female`, updateSlave: {hormones: 2}}); - } else { - options.push({text: `Intensive Female`, disabled: `Cannot use intensive hormones on indentured slaves`}); - } - options.push({text: `Female`, updateSlave: {hormones: 1}}); - options.push({text: `Male`, updateSlave: {hormones: -1}}); - if (slave.indentureRestrictions < 2) { - options.push({text: `Intensive Male`, updateSlave: {hormones: -2}}); - } else { - options.push({text: `Intensive Male`, disabled: `Cannot use intensive hormones on indentured slaves`}); - } + }; - let title = document.createElement('div'); - title.textContent = `Hormones: `; - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - switch (slave.hormones) { - case 2: { - choice.textContent = `intensive female. `; - break; + return btn; } - case 1: { - choice.textContent = `female. `; - break; - } - case 0: { - choice.textContent = `none. `; - break; - } - case -1: { - choice.textContent = `male. `; - break; - } - case -2: { - choice.textContent = `intensive male. `; - break; - } - default: { - choice.textContent = `Not set. `; - } - } - - title.append(choice); - title.appendChild(App.UI.SlaveInteract.generateRows(level, slave)); - el.append(title); - - let links = document.createElement('div'); - links.appendChild(App.UI.SlaveInteract.generateRows(options, slave)); - links.className = "choices"; - el.append(links); - - return jQuery('#hormones').empty().append(el); -}; - -App.UI.SlaveInteract.diet = function(slave) { - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - let el = document.createElement('div'); - - let title = document.createElement('div'); - title.textContent = `Diet: `; - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = `${capFirstChar(slave.diet)}. `; - - title.append(choice); - el.append(title); - - const health = []; - health.push({text: `Healthy`, updateSlave: {diet: "healthy"}}); - if (V.dietCleanse === 1) { - if (slave.health.condition < 90 || slave.chem >= 10) { - health.push({text: `Cleanse`, updateSlave: {diet: "cleansing"}}); - } else { - health.push({text: `Cleanse`, disabled: `${He} is already healthy`}); - } - } - - const weight = []; - if (slave.weight >= -95) { - weight.push({text: `Lose weight`, updateSlave: {diet: "restricted"}}); - } else { - weight.push({text: `Lose weight`, disabled: `${He} is already underweight`}); - } - if (slave.fuckdoll === 0 && slave.fetish !== "mindbroken" && V.feeder === 1) { - if (slave.weight > 10 || slave.weight < -10) { - weight.push({text: `Correct weight`, updateSlave: {diet: "corrective"}}); - } else { - weight.push({text: `Correct weight`, disabled: `${He} is already a healthy weight`}); - } - } - if (slave.weight <= 200) { - weight.push({text: `Fatten`, updateSlave: {diet: "fattening"}}); - } else { - weight.push({text: `Fatten`, disabled: `${He} is already overweight`}); - } - - const muscle = []; - if (slave.muscles < 100 && !isAmputee(slave)) { - muscle.push({text: `Build muscle`, updateSlave: {diet: "muscle building"}}); - } else if (!isAmputee(slave)) { - muscle.push({text: `Build muscle`, disabled: `${He} is maintaining ${his} enormous musculature`}); - } else { - muscle.push({text: `Build muscle`, disabled: `${He} has no limbs and thus can't effectively build muscle`}); - } - - if ((slave.muscles > 0 || slave.fuckdoll === 0) && canWalk(slave)) { - muscle.push({text: `Slim down`, updateSlave: {diet: "slimming"}}); - } else if (!canWalk(slave)) { - muscle.push({text: `Slim down`, disabled: `${He} can't walk and thus can't trim down`}); - } else if (slave.fuckdoll > 0) { - muscle.push({text: `Slim down`, disabled: `${He} has no muscles left to lose`}); - } - - const production = []; - if (slave.balls > 0 && V.cumProDiet === 1) { - production.push({text: `Cum production`, updateSlave: {diet: "cum production"}}); - } - if (((isFertile(slave) && slave.preg === 0) || (slave.geneticQuirks.superfetation === 2 && canGetPregnant(slave) && V.geneticMappingUpgrade !== 0)) && V.dietFertility === 1) { - production.push({text: `Fertility`, updateSlave: {diet: "fertility"}}); - } - - const hormone = []; - if (V.feeder === 1) { - hormone.push({text: `Estrogen enriched`, updateSlave: {diet: "XX"}}); - hormone.push({text: `Testosterone enriched`, updateSlave: {diet: "XY"}}); - if (V.dietXXY === 1 && slave.balls > 0 && (slave.ovaries === 1 || slave.mpreg === 1)) { - hormone.push({text: `Herm hormone blend`, updateSlave: {diet: "XXY"}}); - } - } - - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Health", health, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Weight", weight, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Muscle", muscle, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Production", production, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Hormone", hormone, slave); - - return jQuery('#diet').empty().append(el); -}; - -App.UI.SlaveInteract.dietBase = function(slave) { - let el = document.createElement('div'); - const milk = []; - const cum = []; - - // Milk - if (slave.dietCum < 2) { - milk.push({text: `Milk added`, updateSlave: {dietMilk: 1}}); - if (slave.dietCum < 2) { - milk.push({text: `Milk based`, updateSlave: {dietMilk: 2, dietCum: 0}}); - } - if (slave.dietMilk) { - milk.push({text: `Remove milk`, updateSlave: {dietMilk: 0}}); - } - } else { - milk.push({text: `Milk`, disabled: `Diet is based entirely on cum`}); - } - - // Cum - if (slave.dietMilk < 2) { - cum.push({text: `Cum added`, updateSlave: {dietCum: 1}}); - cum.push({text: `Cum based`, updateSlave: {dietCum: 2, dietMilk: 0}}); - if (slave.dietCum) { - cum.push({text: `Remove cum`, updateSlave: {dietCum: 0}}); - } - } else { - cum.push({text: `Cum`, disabled: `Diet is based entirely on milk`}); - } - - let title = document.createElement('div'); - title.textContent = `Diet base: `; - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - if (slave.dietCum === 2) { - choice.textContent = `cum based. `; - } else if (slave.dietCum === 1 && slave.dietMilk === 0) { - choice.textContent = `cum added. `; - } else if (slave.dietCum === 1 && slave.dietMilk === 1) { - choice.textContent = `cum and milk added. `; - } else if (slave.dietMilk === 1 && slave.dietCum === 0) { - choice.textContent = `milk added. `; - } else if (slave.dietMilk === 2) { - choice.textContent = `milk based. `; - } else if (slave.dietCum === 0 && slave.dietMilk === 0) { - choice.textContent = `normal. `; - } else { - choice.textContent = `THERE HAS BEEN AN ERROR.`; } - title.append(choice); - el.append(title); - - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Milk", milk, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Cum", cum, slave); - - return jQuery('#diet-base').empty().append(el); -}; - -App.UI.SlaveInteract.snacks = function(slave) { - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - let el = document.createElement('div'); - let options = []; - - if (V.arcologies[0].FSHedonisticDecadenceResearch === 1) { - let title = document.createElement('div'); - title.textContent = `Solid Slave Food Access: `; - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - if (slave.onDiet === 0) { - choice.textContent = `Free to stuff ${himself}.`; - } else { - choice.textContent = `On a strict diet.`; + function displayWithoutTabs() { + const el = new DocumentFragment(); + App.Events.drawEventArt(el, slave); + for (const item of buttons) { + App.UI.DOM.appendNewElement("h2", el, item.title); + el.append(item.node); + if (item.hasOwnProperty("onClick")){ + item.onClick(); + } } - title.append(choice); - el.append(title); - - options.push({text: `No access`, updateSlave: {onDiet: 1}}); - options.push({text: `Full access`, updateSlave: {onDiet: 0}}); - - let links = document.createElement('div'); - links.appendChild(App.UI.SlaveInteract.generateRows(options, slave)); - links.className = "choices"; - el.append(links); + return el; } + function makeTabContents(item) { + const wrapperEl = document.createElement("div"); + wrapperEl.id = item.id; + wrapperEl.classList.add("tab-content"); - return jQuery('#snacks').empty().append(el); -}; - -App.UI.SlaveInteract.useSlaveDisplay = function(slave) { - // Goal: Be able to write the entire "use her" block with only dom fragments. - let el = document.createElement('div'); - - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - - /* - Array of objects. Each object follows the form: { - text: "Link text", - scene: "scene to include", - goto: if another passage is needed - updateSlave: update slave itself if needed, like {trust: 2}, - update: updates V., - note: if a note must appear after the link + const classEl = document.createElement("div"); + classEl.classList.add("content"); + classEl.append(item.node); + wrapperEl.append(classEl); + return wrapperEl; } - */ - const sexOptions = []; - const fillFaceOptions = []; - const fillAssOptions = []; - const dairyNameCaps = capFirstChar(V.dairyName); - // if no scene, it's just text, no link. Italicize it. - - if (slave.fuckdoll === 0) { - if (slave.vagina > -1) { - if (canDoVaginal(slave)) { - sexOptions.push({text: `Fuck ${him}`, scene: `FVagina`}); - if (canDoAnal(slave)) { - sexOptions.push({text: `Use ${his} holes`, scene: `FButt`}); - } - } else { - sexOptions.push({text: `Fuck ${him}`, disabled: `Remove ${his} chastity belt if you wish to fuck ${him}`}); - } - } - if (slave.bellyPreg >= 300000) { - if (canDoVaginal(slave) || canDoAnal(slave)) { - sexOptions.push({text: `Fuck ${him} on ${his} belly`, scene: `FBellyFuck`}); - if (V.pregInventions >= 1) { - sexOptions.push({text: `Fuck ${him} in ${his} maternity swing`, scene: `FMaternitySwing`}); - sexOptions.push({text: `Fuck ${him} with the help of ${his} assistants`, scene: `FAssistedSex`}); - sexOptions.push({text: `Fuck ${him} in your goo pool`, scene: `FPoolSex`}); - } - } - } - - if (canDoAnal(slave)) { - sexOptions.push({text: `Fuck ${his} ass`, scene: `FAnus`}); - } else { - sexOptions.push({text: `Fuck ${his} ass`, disabled: `Remove ${his} chastity belt if you wish to fuck ${his} ass`}); - } - sexOptions.push({text: `Use ${his} mouth`, scene: `FLips`}); - sexOptions.push({text: `Kiss ${him}`, scene: `FKiss`}); - if (hasAnyLegs(slave)) { - sexOptions.push({text: `Have ${him} dance for you`, scene: `FDance`}); - } - - sexOptions.push({text: `Play with ${his} tits`, scene: `FBoobs`}); - - sexOptions.push({text: `Caress ${him}`, scene: `FCaress`}); - - sexOptions.push({text: `Give ${him} a hug`, scene: `FEmbrace`}); - if (V.cheatMode === 1) { - sexOptions.push({text: `Pat ${his} head`, scene: `FPat`}); - } - - sexOptions.push({text: `Grope ${his} boobs`, scene: `FondleBoobs`}); - if (slave.nipples === "fuckable" && V.PC.dick > 0) { - sexOptions.push({text: `Fuck ${his} nipples`, scene: `FNippleFuck`}); - } - if (slave.lactation > 0 && slave.boobs >= 2000 && slave.belly < 60000 && hasAnyArms(slave)) { - sexOptions.push({text: `Drink ${his} milk`, scene: `FSuckle`}); - } - - if (canDoAnal(slave)) { - sexOptions.push({text: `Grope ${his} butt`, scene: `FondleButt`}); - } - - - if (slave.vagina > -1) { - if (canDoVaginal(slave)) { - sexOptions.push({text: `Grope ${his} pussy`, scene: `FondleVagina`}); - sexOptions.push({text: `Eat ${him} out`, scene: `FLickPussy`}); - } - } - - if (slave.dick > 0) { - if (!(slave.chastityPenis)) { - sexOptions.push({text: `Grope ${his} dick`, scene: `FondleDick`}); - if (canPenetrate(slave)) { - if (V.policies.sexualOpenness === 1 || slave.toyHole === "dick") { - sexOptions.push({text: `Ride ${his} dick`, scene: `FDick`}); - } - } - } else { - sexOptions.push({text: `Use ${his} dick`, disabled: `Remove ${his} dick chastity belt if you wish to play with ${his} cock`}); - } - } - - if (hasAnyLegs(slave) && V.PC.dick > 0) { - sexOptions.push({text: `Get a footjob`, scene: `FFeet`}); - } - - if (canGetPregnant(slave) && (slave.geneticQuirks.superfetation !== 2 || V.geneticMappingUpgrade !== 0) && (slave.fuckdoll === 0) && V.seePreg !== 0) { - if (canImpreg(slave, V.PC)) { - sexOptions.push({text: `Impregnate ${him} yourself`, scene: `FPCImpreg`}); - } - if (canImpreg(slave, slave)) { - sexOptions.push({text: `Use ${his} own seed to impregnate ${him}`, scene: `FSlaveSelfImpreg`}); - } - sexOptions.push({text: `Use another slave to impregnate ${him}`, scene: `FSlaveImpreg`}); - } - if (slave.assignment !== Job.DAIRY && slave.assignment !== Job.ARCADE && slave.assignment !== Job.CELLBLOCK) { - if (V.dairyPiping === 1) { - if ((V.milkPipeline > 88 && V.milkPipeline !== 0) || V.arcologies[0].FSPastoralistLaw === 1) { - if ((slave.inflation < 3 && slave.pregKnown === 0 && slave.bellyImplant < 1500) || slave.inflation < 1) { - if (slave.inflationType === "milk" || slave.inflationType === "none") { - fillAssOptions.push({text: `Milk`, scene: `FillUpButt`, updateSlave: {inflationType: "milk", inflationMethod: 2}}); - fillFaceOptions.push({text: `Milk`, scene: `FillUpFace`, updateSlave: {inflationType: "milk", inflationMethod: 1}}); - } - } - } else { - fillAssOptions.push({text: `Milk`, disabled: `${dairyNameCaps} is not producing enough milk to pump through the pipes`}); - fillFaceOptions.push({text: `Milk`, disabled: `${dairyNameCaps} is not producing enough milk to pump through the pipes`}); - } - if ((V.cumPipeline > 88 && V.cumPipeline !== 0) || V.arcologies[0].FSPastoralistLaw === 1) { - if ((slave.inflation < 3 && slave.pregKnown === 0 && slave.bellyImplant < 1500) || slave.inflation < 1) { - if (slave.inflationType === "cum" || slave.inflationType === "none") { - fillAssOptions.push({text: `Cum`, scene: `FillUpButt`, updateSlave: {inflationType: "cum", inflationMethod: 2}}); - fillFaceOptions.push({text: `Cum`, scene: `FillUpFace`, updateSlave: {inflationType: "cum", inflationMethod: 1}}); - } - } - } else { - fillAssOptions.push({text: `Cum`, disabled: `${dairyNameCaps} is not producing enough cum to pump through the pipes`}); - fillFaceOptions.push({text: `Cum`, disabled: `${dairyNameCaps} is not producing enough cum to pump through the pipes`}); - } - } /* dairyPiping === 1 */ - if (V.boughtItem.toys.enema === 1) { - if ((slave.inflation < 3 && slave.pregKnown === 0 && slave.bellyImplant < 1500) || slave.inflation < 1) { - if (slave.inflationType === "water" || slave.inflationType === "none") { - fillAssOptions.push({text: `Water`, scene: `FillUpButt`, updateSlave: {inflationType: "water", inflationMethod: 2}}); - } - if (V.boughtItem.toys.medicalEnema === 1) { - if (slave.inflationType === "aphrodisiac" || slave.inflationType === "none") { - fillAssOptions.push({text: `Aphrodisiacs`, scene: `FillUpButt`, updateSlave: {inflationType: "aphrodisiac", inflationMethod: 2}}); - } - if (slave.inflationType === "curative" || slave.inflationType === "none") { - fillAssOptions.push({text: `Curatives`, scene: `FillUpButt`, updateSlave: {inflationType: "curative", inflationMethod: 2}}); - } - if (slave.inflationType === "tightener" || slave.inflationType === "none") { - fillAssOptions.push({text: `Rectal tighteners`, scene: `FillUpButt`, updateSlave: {inflationType: "tightener", inflationMethod: 2}}); - } - } - } /* inflation < 3 */ - } /* enema === 1 */ - if (V.wcPiping === 1) { - if ((slave.inflation < 3 && slave.pregKnown === 0 && slave.bellyImplant < 1500) || slave.inflation < 1) { - if (slave.inflationType === "urine" || slave.inflationType === "none") { - fillAssOptions.push({text: `Urine`, scene: `FillUpButt`, updateSlave: {inflationType: "urine", inflationMethod: 2}}); - } - } - } /* wcPiping === 1 */ - } /* assigned to dairy or arcade */ - if (slave.inflation === 0 && slave.bellyImplant < 1500) { - if (slave.assignment !== Job.DAIRY && slave.assignment !== Job.ARCADE && slave.assignment !== Job.CELLBLOCK) { - if (V.boughtItem.toys.buckets === 1) { - fillFaceOptions.push({text: `Two liters of slave food`, scene: `forceFeeding`, updateSlave: {inflation: 1, inflationType: "food", inflationMethod: 1}}); - if (slave.pregKnown === 0) { - fillFaceOptions.push({text: `A gallon of slave food`, scene: `forceFeeding`, updateSlave: {inflation: 2, inflationType: "food", inflationMethod: 1}}); - fillFaceOptions.push({text: `Two gallons of slave food`, scene: `forceFeeding`, updateSlave: {inflation: 3, inflationType: "food", inflationMethod: 1}}); - } - } - fillFaceOptions.push({text: `Get another slave to do it`, goto: `SlaveOnSlaveFeedingWorkAround`}); - } - } - if (canDoVaginal(slave)) { - sexOptions.push({text: `Have another slave fuck ${his} pussy`, scene: `FSlaveSlaveVag`}); - } - if (canPenetrate(slave)) { - sexOptions.push({text: `Have another slave ride ${his} cock`, scene: `FSlaveSlaveDick`}); - } else if (slave.clit >= 4) { - sexOptions.push({text: `Have another slave ride ${his} clit-dick`, scene: `FSlaveSlaveDick`}); - } - if (V.seeBestiality) { - const - isVowel = char => /[aeiou]/.test(char), - a = name => isVowel(name.charAt(0).toLowerCase()) ? `an` : `a`; - let text = name => `Have ${a(name)} ${name} mount ${him}`; - - if (slave.assignment === Job.FUCKTOY || slave.assignment === Job.MASTERSUITE) { - if (slave.toyHole === "mouth") { - text = name => `Have ${him} suck off ${a(name)} ${name}`; - } else if (slave.toyHole === "ass") { - text = name => `Have ${a(name)} ${name} fuck ${his} ass`; - } - } - - if (V.farmyardKennels > 0 && V.activeCanine) { - sexOptions.push({ - text: text(V.activeCanine.name), - scene: `BeastFucked`, - update: {animalType: "canine"}}); - } - if (V.farmyardStables > 0 && V.activeHooved) { - sexOptions.push({ - text: text(V.activeHooved.name), - scene: `BeastFucked`, - update: {animalType: "hooved"}}); - } - if (V.farmyardCages > 0 && V.activeFeline) { - sexOptions.push({ - text: text(V.activeFeline.name), - scene: `BeastFucked`, - update: {animalType: "feline"}}); - } - } - sexOptions.push({text: `Abuse ${him}`, scene: `FAbuse`}); - if (V.seeIncest === 1) { - const availRelatives = availableRelatives(slave); - if (availRelatives.mother) { - sexOptions.push({text: `Fuck ${him} with ${his} mother`, scene: `FRelation`, update: {partner: "mother"}}); - } else if (availRelatives.motherName !== null) { - sexOptions.push({text: `${His} mother, ${availRelatives.motherName}, is unavailable`}); - } - /* - if (availRelatives.father) { - sexOptions.push({text: `Fuck ${him} with ${his} father`, scene: `FRelation`, update: {partner: "father"}}); - } else if (availRelatives.fatherName !== null) { - sexOptions.push({text: `${His} father, ${availRelatives.motherName}, is unavailable`}); - } - */ - if (slave.daughters > 0) { - if (availRelatives.daughters === 0) { - if (slave.daughters === 1) { - sexOptions.push({text: `Fuck ${him} with ${his} daughter`, disabled: `${His} ${availRelatives.oneDaughterRel} is unavailable`}); - } else { - sexOptions.push({text: `Fuck ${him} with one of ${his} daughters`, disabled: `${His} daughters are unavailable`}); - } - } else { - if (slave.daughters === 1) { - sexOptions.push({text: `Fuck ${him} with ${his} ${availRelatives.oneDaughterRel}`, scene: `FRelation`, update: {partner: "daughter"}}); - } else { - sexOptions.push({text: `Fuck ${him} with one of ${his} daughters`, scene: `FRelation`, update: {partner: "daughter"}}); - } - /* - if (availRelatives.daughters > 1) { - sexOptions.push({text: `Fuck ${him} with ${his} daughters`, scene: `FRelation`, update: {partner: "daughter"}}); - } - */ - } - } - if (slave.sisters > 0) { - if (availRelatives.sisters === 0) { - if (slave.sisters === 1) { - sexOptions.push({text: `Fuck ${him} with ${his} sister`, disabled: `${His} ${availRelatives.oneSisterRel} is unavailable`}); - } else { - sexOptions.push({text: `Fuck ${him} with one of ${his} sisters`, disabled: `${His} sisters are unavailable`}); - } - } else { - if (slave.sisters === 1) { - sexOptions.push({text: `Fuck ${him} with ${his} ${availRelatives.oneSisterRel}`, scene: `FRelation`, update: {partner: "sister"}}); - } else { - sexOptions.push({text: `Fuck ${him} with one of ${his} sisters`, scene: `FRelation`, update: {partner: "sister"}}); - } - /* - if (availRelatives.sisters > 1) { - sexOptions.push({text: `Fuck ${him} with ${his} sisters`, scene: `FRelation`, update: {partner: "sisters}}); - } - */ - } - } - } - if (slave.relationship > 0) { - const lover = getSlave(slave.relationshipTarget); - if (isSlaveAvailable(lover)) { - sexOptions.push({text: `Fuck ${him} with ${his} ${relationshipTermShort(slave)} ${SlaveFullName(lover)}`, scene: `FRelation`, update: {partner: "relationship"}}); - } else if (lover.assignment === Job.AGENT) { - if (slave.broodmother < 2) { - sexOptions.push({text: `Send ${him} to live with your agent ${SlaveFullName(lover)}`, goto: `Agent Company`, update: {subSlave: lover}}); - } else { - sexOptions.push({text: `A hyper-broodmother cannot be sent to live with your agent`}); - } - } else { - sexOptions.push({text: `${SlaveFullName(lover)} is unavailable`}); - } - } - if (slave.rivalryTarget !== 0 && hasAllLimbs(slave)) { - const rival = getSlave(slave.relationshipTarget); - if (isSlaveAvailable(rival) && hasAnyLegs(rival)) { - sexOptions.push({text: `Abuse ${his} rival with ${him}`, scene: `FRival`}); - } - } - if (slave.fetish !== "mindbroken" && (canTalk(slave) || hasAnyArms(slave))) { - sexOptions.push({text: `Ask ${him} about ${his} feelings`, scene: `FFeelings`}); - if (V.PC.dick > 0) { - sexOptions.push({text: `Make ${him} beg`, scene: `FBeg`}); - } - } - if (slave.devotion >= 100 && slave.relationship < 0 && slave.relationship > -3) { - sexOptions.push({text: `Talk to ${him} about relationships`, goto: `Matchmaking`, update: {subSlave: 0}}); - } - let ML = V.marrying.length; - if ((V.policies.mixedMarriage === 1 || V.cheatMode === 1) && slave.relationship !== 5 && slave.relationship !== -3) { - if (V.marrying.includes(slave.ID)) { - sexOptions.push({text: `Marry ${him}`, disabled: `You are already marrying ${him} this weekend`}); - } else { - if (ML < 2) { - if (V.cheatMode === 1 || ML === 0) { - sexOptions.push({text: `Marry ${him}`, goto: "FMarry"}); - } else { - sexOptions.push({text: `Marry ${him}`, disabled: `You already have a wedding planned for this weekend`}); - } - } else { - sexOptions.push({text: `Marry ${him}`, disabled: `You can only marry up to two slaves per week`}); - } - } - } - if (V.cheatMode === 1) { - sexOptions.push({text: `Check ${his} stats`, goto: `Slave Stats`}); - } - } else { - /* IS A FUCKDOLL */ - sexOptions.push({text: `Fuck ${his} face hole`, scene: `FFuckdollOral`}); - if (canDoVaginal(slave)) { - sexOptions.push({text: `Fuck ${his} front hole`, scene: `FFuckdollVaginal`}); - } - if (canGetPregnant(slave) && (slave.geneticQuirks.superfetation !== 2 || V.geneticMappingUpgrade !== 0) && V.seePreg !== 0) { - if (canImpreg(slave, V.PC)) { - sexOptions.push({text: `Put a baby in ${him}`, scene: `FFuckdollImpreg`}); - } - } - if (canDoAnal(slave)) { - sexOptions.push({text: `Fuck ${his} rear hole`, scene: `FFuckdollAnal`}); - } - } - let activeSlaveRepSacrifice = repGainSacrifice(slave, V.arcologies[0]); - if (activeSlaveRepSacrifice > 0 && V.arcologies[0].FSPaternalist === "unset" && (slave.breedingMark === 0 || V.propOutcome === 0 || V.eugenicsFullControl === 1 || V.arcologies[0].FSRestart === "unset")) { - sexOptions.push({ - text: `Sacrifice ${him} on the altar`, - goto: `Aztec Slave Sacrifice`, - note: `This will kill ${him} and gain you ${activeSlaveRepSacrifice} reputation`, - update: {sacrificeType: "life"} - }); - } - el.append(`Use ${him}: `); - el.appendChild(generateRows(sexOptions)); - if (!jQuery.isEmptyObject(fillFaceOptions)) { - let fill = document.createElement('div'); - fill.appendChild(document.createTextNode(` Fill ${his} mouth with: `)); - fill.appendChild(generateRows(fillFaceOptions)); - el.appendChild(fill); - } - if (!jQuery.isEmptyObject(fillAssOptions)) { - let fill = document.createElement('div'); - fill.appendChild(document.createTextNode(` Fill ${his} ass with: `)); - fill.appendChild(generateRows(fillAssOptions)); - el.appendChild(fill); - } - - function generateRows(sexArray) { - let row = document.createElement('span'); - for (let i = 0; i < sexArray.length; i++) { - let link; - const separator = document.createTextNode(` | `); - const keys = Object.keys(sexArray[i]); - - // Test to see if there was a problem with the key - for (let j = 0; j < keys.length; j++) { - if (!["disabled", "goto", "note", "scene", "text", "update", "updateSlave"].includes(keys[j])) { - sexArray[i].text += " ERROR, THIS SCENE WAS NOT ENTERED CORRECTLY"; - console.log("Trash found while generateRows() was running: " + keys[j] + ": " + sexArray[i][keys[j]]); - break; - } - } - // is it just text? - if (sexArray[i].disabled) { - link = App.UI.DOM.disabledLink(sexArray[i].text, [sexArray[i].disabled]); - } else { - let passage = ""; - if (sexArray[i].goto) { - passage = sexArray[i].goto; - } - - // Set up the link - link = App.UI.DOM.link( - sexArray[i].text, - () => { click(sexArray[i]); }, - [], - passage - ); - - // add a note node if required - if (sexArray[i].note) { - link.appendChild(App.UI.DOM.makeElement('span', sexArray[i].note, 'note')); - } - } - row.appendChild(link); - if (i < sexArray.length - 1) { - row.appendChild(separator); - } - } - - return row; - - function click(sexOption) { - if (sexOption.updateSlave) { - Object.assign(slave, sexOption.updateSlave); - } - if (sexOption.update) { - Object.assign(V, sexOption.update); - } - - if (sexOption.goto) { - // just play the passage, no need to refresh anything here - Engine.play(sexOption.goto); - } else if (sexOption.scene) { - // Run scene and store render results temporarily - let frag = App.UI.DOM.renderPassage(sexOption.scene); - - // Refresh (clears scene display) - App.UI.SlaveInteract.refreshAll(slave); - - // Display scene render results - $("#mini-scene").append(frag); - } else { - // just refresh - App.UI.SlaveInteract.refreshAll(slave); - } - } - } - return el; -}; - -App.UI.SlaveInteract.bloating = function(slave) { - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - let bloating = document.createElement('div'); - if (slave.inflation > 0) { - let intro = document.createElement('span'); - intro.textContent = "Required Bloating"; - intro.style.textDecoration = "underline"; - bloating.append(intro); - - bloating.append(": "); - - let requirement = document.createElement('span'); - requirement.style.fontWeight = "bold"; - requirement.id = "inflate"; - if (slave.inflation === 3) { - requirement.textContent = `${He} is required to keep 2 gallons of ${slave.inflationType} in ${him} at all times`; - } else if (slave.inflation === 2) { - requirement.textContent = `${He} is required to keep 4 liters of ${slave.inflationType} in ${him} at all times`; - } else if (slave.inflation === 1) { - requirement.textContent = `${He} is required to keep 2 liters of ${slave.inflationType} in ${him} at all times`; - } - bloating.append(requirement); - bloating.append(". "); - - let link = App.UI.DOM.link( - `Let ${him} deflate`, - () => { - deflate(slave); - App.UI.SlaveInteract.refreshAll(slave); - }, - ); - bloating.append(link); - } - // make sure it updates itself after run - return jQuery('#bloating').empty().append(bloating); -}; - -App.UI.SlaveInteract.fertility = function(slave) { - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - let fertilityBlock = document.createElement('span'); - let linkArray = []; - if (slave.ovaries === 1 || slave.mpreg === 1 || slave.preg > 0) { - let note = ""; - if (slave.preg < -1) { - note += `${He} is sterile`; - } else if (slave.pubertyXX === 0 && slave.preg < 1) { - note += `${He} is not yet fertile`; - } else if (slave.ovaryAge >= 47 && slave.preg < 1) { - note += `${He} is too old to become pregnant`; - if (slave.preg === -1) { - slave.preg = 0; - SetBellySize(slave); - } - } else if (slave.broodmotherOnHold === 1) { - note += `${His} pregnancy implant is turned off`; - if (slave.broodmotherCountDown > 0) { - note += `${he} is expected to be completely emptied of ${his} remaining brood in ${slave.broodmotherCountDown} week`; - if (slave.broodmotherCountDown > 1) { - note += `s`; - } - note += `.`; - linkArray.push(App.UI.DOM.link( - `Turn on implant`, - () => { - slave.broodmotherOnHold = 0; - slave.broodmotherCountDown = 0; - App.UI.SlaveInteract.refreshAll(slave); - }, - )); - } - } else if (slave.preg >= -1) { - fertilityBlock.append("Contraception and fertility: "); - let fertility = ""; - // fertility.id = "fertility"; - if (slave.preg === -1) { - fertility = "using contraceptives"; - } else if (slave.pregWeek < 0) { - fertility = "postpartum"; - } else if (slave.preg === 0) { - fertility = "fertile"; - } else if (slave.preg < 4 && (slave.broodmother === 0 || slave.broodmotherOnHold === 1)) { - fertility = "may be pregnant"; - } else if (slave.preg < 2) { - fertility = "1 week pregnant"; - } else { - fertility = `${Math.trunc(slave.preg * 1000) / 1000} weeks pregnant`; // * and / needed to avoid seeing something like 20.1000000008 in some cases. - if (slave.broodmother > 0) { - fertility += " broodmother"; - } - } - fertility += ". "; - App.UI.DOM.appendNewElement("span", fertilityBlock, fertility, "bold"); - - if (slave.preg === 0) { - linkArray.push(App.UI.DOM.link( - `Use contraceptives`, - () => { - slave.preg = -1; - App.UI.SlaveInteract.refreshAll(slave); - }, - )); - } else if (slave.preg === -1) { - linkArray.push(App.UI.DOM.link( - `Let ${him} get pregnant`, - () => { - slave.preg = 0; - App.UI.SlaveInteract.refreshAll(slave); - }, - )); - } else if (isInduced(slave)) { - note += `Hormones are being slipped into ${his} food; ${he} will give birth suddenly and rapidly this week`; - } else if ( - slave.preg > slave.pregData.normalBirth - 2 && - slave.preg > slave.pregData.minLiveBirth && - slave.broodmother === 0 && - !isInLabor(slave) - ) { - linkArray.push(App.UI.DOM.link( - `Induce labor`, - () => { - induce(slave); - App.UI.SlaveInteract.refreshAll(slave); - }, - )); - linkArray.push(App.UI.DOM.passageLink(`Give ${him} a cesarean section`, "csec")); - } else if (slave.broodmother > 0) { - if (slave.broodmotherOnHold !== 1) { - linkArray.push(App.UI.DOM.link( - `Turn off implant`, - () => { - slave.broodmotherOnHold = 1; - slave.broodmotherCountDown = 38 - WombMinPreg(slave); - App.UI.SlaveInteract.refreshAll(slave); - }, - )); - } - if (slave.preg > 37) { - linkArray.push(App.UI.DOM.passageLink(`Induce mass childbirth`, "BirthStorm")); - } - } else if (slave.preg > slave.pregData.minLiveBirth) { - linkArray.push(App.UI.DOM.link( - `Give ${him} a cesarean section`, - () => { - slave.broodmotherOnHold = 0; - slave.broodmotherCountDown = 0; - }, - [], - "csec" - )); - } else if (slave.preg > 0 && slave.breedingMark === 1 && V.propOutcome === 1 && V.arcologies[0].FSRestart !== "unset" && V.eugenicsFullControl !== 1 && (slave.pregSource === -1 || slave.pregSource === -6)) { - note += "You are forbidden from aborting an Elite child"; - } else if (slave.preg > 0) { - linkArray.push(App.UI.DOM.link( - `Abort ${his} pregnancy`, - () => { - slave.broodmotherOnHold = 0; - slave.broodmotherCountDown = 0; - }, - [], - "Abort" - )); - } - } - App.UI.DOM.appendNewElement("span", fertilityBlock, note, "note"); - App.UI.DOM.appendNewElement("div", fertilityBlock, App.UI.DOM.generateLinksStrip(linkArray), "choices"); - } - if ( - (slave.pregKnown === 1) && - (V.pregSpeedControl === 1) && - ( - slave.breedingMark !== 1 || - V.propOutcome === 0 || - V.eugenicsFullControl === 1 || - V.arcologies[0].FSRestart === "unset" - ) && - (slave.indentureRestrictions < 1) && - (slave.broodmother === 0) && - V.seePreg !== 0 - ) { - let title = document.createElement('div'); - let underline = document.createElement('span'); - underline.style.textDecoration = "underline"; - underline.textContent = "Pregnancy control"; - title.appendChild(underline); - title.append(": "); - - if (slave.pregControl === "labor suppressors") { - title.append("Labor is suppressed. "); - } else if (slave.pregControl === "slow gestation") { - title.append("Slowed gestation speed. "); - } else if (slave.pregControl === "speed up") { - title.append("Faster gestation speed, staffed clinic recommended. "); - } else { - title.append("Normal gestation and birth. "); - } - fertilityBlock.appendChild(title); - - linkArray = []; - if (slave.pregControl !== "none") { - linkArray.push(App.UI.DOM.link( - `Normal ${slave.preg < slave.pregData.normalBirth ? "Gestation" : "Birth"}`, - () => { - slave.pregControl = "none"; - App.UI.SlaveInteract.fertility(slave); - }, - )); - } - if (slave.preg < slave.pregData.normalBirth) { - if (slave.pregControl !== "slow gestation") { - linkArray.push(App.UI.DOM.link( - `Slow Gestation`, - () => { - slave.pregControl = "slow gestation"; - App.UI.SlaveInteract.fertility(slave); - }, - )); - } - if (slave.pregControl !== "speed up") { - linkArray.push(App.UI.DOM.link( - `Fast Gestation`, - () => { - slave.pregControl = "speed up"; - App.UI.SlaveInteract.fertility(slave); - }, - )); - } - } - if (slave.preg >= slave.pregData.minLiveBirth) { - if (slave.pregControl !== "labor suppressors") { - linkArray.push(App.UI.DOM.link( - `Suppress Labor`, - () => { - slave.pregControl = "labor suppressors"; - App.UI.SlaveInteract.fertility(slave); - }, - )); - } - } - App.UI.DOM.appendNewElement("div", fertilityBlock, App.UI.DOM.generateLinksStrip(linkArray), "choices"); - } - return jQuery('#fertility-block').empty().append(fertilityBlock); -}; - -App.UI.SlaveInteract.curatives = function(slave) { - const curativeOptions = []; - - curativeOptions.push({text: `None`, updateSlave: {curatives: 0}}); - curativeOptions.push({text: `Preventatives`, updateSlave: {curatives: 1}}); - curativeOptions.push({text: `Curatives`, updateSlave: {curatives: 2}}); - - let el = document.createElement('div'); - let title = document.createElement('div'); - title.append(`Health: `); - let chosenOption = document.createElement('span'); - chosenOption.style.fontWeight = "bold"; - if (slave.curatives > 1) { - chosenOption.textContent = `curatives`; - } else if (slave.curatives > 0) { - chosenOption.textContent = `preventatives`; - } else { - chosenOption.textContent = `none`; - } - title.appendChild(chosenOption); - title.append(`.`); - let link = document.createElement('div'); - link.className = "choices"; - link.appendChild(App.UI.SlaveInteract.generateRows(curativeOptions, slave)); - el.append(title); - el.append(link); - return jQuery('#curatives').empty().append(el); -}; - -App.UI.SlaveInteract.aphrodisiacs = function(slave) { - const aphrodisiacOptions = []; - - aphrodisiacOptions.push({text: `None`, updateSlave: {aphrodisiacs: 0}}); - aphrodisiacOptions.push({text: `Aphrodisiacs`, updateSlave: {aphrodisiacs: 1}}); - aphrodisiacOptions.push({text: `Extreme aphrodisiacs`, updateSlave: {aphrodisiacs: 2}}); - aphrodisiacOptions.push({text: `Anaphrodisiacs`, updateSlave: {aphrodisiacs: -1}, note: `Suppresses libido`}); - - - let el = document.createElement('div'); - let title = document.createElement('div'); - title.append(`Aphrodisiacs: `); - let chosenOption = document.createElement('span'); - chosenOption.style.fontWeight = "bold"; - if (slave.aphrodisiacs > 1) { - chosenOption.textContent = `extreme`; - } else if (slave.aphrodisiacs > 0) { - chosenOption.textContent = `applied`; - } else if (slave.aphrodisiacs === -1) { - chosenOption.textContent = `anaphrodisiacs`; - } else { - chosenOption.textContent = `none`; - } - title.appendChild(chosenOption); - title.append(`.`); - let link = document.createElement('div'); - link.className = "choices"; - link.appendChild(App.UI.SlaveInteract.generateRows(aphrodisiacOptions, slave)); - el.append(title); - el.append(link); - return jQuery('#aphrodisiacs').empty().append(el); -}; - -/** - * @param {App.Entity.SlaveState} slave - */ -App.UI.SlaveInteract.incubator = function(slave) { - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - V.reservedChildren = FetusGlobalReserveCount("incubator"); - let _reservedIncubator = WombReserveCount(slave, "incubator"); - let _reservedNursery = WombReserveCount(slave, "nursery"); - let _WL = slave.womb.length; - let el = document.createElement('div'); - - if (V.incubator > 0) { - if (slave.preg > 0 && slave.broodmother === 0 && slave.pregKnown === 1 && slave.eggType === "human") { - if ((slave.assignment !== Job.DAIRY || V.dairyPregSetting === 0) && (slave.assignment !== Job.FARMYARD || V.farmyardBreeding === 0)) { - let title = document.createElement('div'); - let link = document.createElement('div'); - link.className = "choices"; - if (_WL - _reservedNursery === 0) { - title.textContent = `${His} children are already reserved for ${V.nurseryName}`; - title.style.fontStyle = "italic"; - } else { - const freeTanks = (V.incubator - V.tanks.length); - if (_reservedIncubator > 0) { - if (_WL === 1) { - title.textContent = `${His} child will be placed in ${V.incubatorName}. `; - } else if (_reservedIncubator < _WL) { - title.textContent = `${_reservedIncubator} of ${his} children will be placed in ${V.incubatorName}.`; - } else if (_WL === 2) { - title.textContent = `Both of ${his} children will be placed in ${V.incubatorName}. `; - } else { - title.textContent = `All ${_reservedIncubator} of ${his} children will be placed in ${V.incubatorName}. `; - } - if ((_reservedIncubator + _reservedNursery < _WL) && (V.reservedChildren < freeTanks)) { - link.appendChild( - App.UI.DOM.link(`Keep another child`, () => wombUpdateIncubator(1, true)) - ); - if (_reservedIncubator > 0) { - link.append(` | `); - link.appendChild( - App.UI.DOM.link(`Keep one less child`, () => wombUpdateIncubator(1, false)) - ); - } - if (_reservedIncubator > 1) { - link.append(` | `); - link.appendChild( - App.UI.DOM.link(`Keep none of ${his} children`, () => wombUpdateIncubator(9999, false)) - ); - } - if ((V.reservedChildren + _WL - _reservedIncubator) <= freeTanks) { - link.append(` | `); - link.appendChild( - App.UI.DOM.link(`Keep the rest of ${his} children`, () => wombUpdateIncubator(9999, true)) - ); - } - } else if ((_reservedIncubator === _WL) || (V.reservedChildren === freeTanks) || (_reservedIncubator - _reservedNursery >= 0)) { - link.appendChild( - App.UI.DOM.link(`Keep one less child`, () => wombUpdateIncubator(1, false)) - ); - if (_reservedIncubator > 1) { - link.append(` | `); - link.appendChild( - App.UI.DOM.link(`Keep none of ${his} children`, () => wombUpdateIncubator(9999, false)) - ); - } - } - } else if (V.reservedChildren < freeTanks) { - title.textContent = `${He} is pregnant and you have `; - if (freeTanks === 1) { - title.textContent += `an `; - } - let tank = document.createElement('span'); - tank.className = "lime"; - tank.textContent = `available aging tank`; - if (freeTanks > 1) { - tank.textContent += `s`; - } - tank.textContent += `.`; - let _cCount = (_WL > 1 ? "a" : "the"); - link.appendChild( - App.UI.DOM.link(`Keep ${_cCount} child`, () => wombUpdateIncubator(1, true)) - ); - title.appendChild(tank); - if ((_WL > 1) && (V.reservedChildren + _WL) <= freeTanks) { - link.append(` | `); - link.appendChild( - App.UI.DOM.link(`Keep all of ${his} children`, () => wombUpdateIncubator(9999, true)) - ); - } - } else if (V.reservedChildren === freeTanks) { - title.textContent = `You have no available tanks for ${his} children. `; - } - } - el.append(title); - el.append(link); - } - } - } - - function wombUpdateIncubator(count, addToWomb) { - if (addToWomb) { - WombAddToGenericReserve(slave, "incubator", count); - } else { - WombCleanGenericReserve(slave, "incubator", count); - } - V.reservedChildren = FetusGlobalReserveCount("incubator"); - App.UI.SlaveInteract.refreshAll(slave); - } - - return jQuery('#incubator').empty().append(el); -}; - -App.UI.SlaveInteract.nursery = function(slave) { - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - let el = document.createElement('div'); - if (V.nursery > 0) { - V.reservedChildrenNursery = FetusGlobalReserveCount("nursery"); - let reservedIncubator = WombReserveCount(slave, "incubator"); - let reservedNursery = WombReserveCount(slave, "nursery"); - let _WL = slave.womb.length; - if (slave.preg > 0 && slave.broodmother === 0 && slave.pregKnown === 1 && slave.eggType === "human") { - if ((slave.assignment !== Job.DAIRY || V.dairyPregSetting === 0) && (slave.assignment !== Job.FARMYARD || V.farmyardBreeding === 0)) { - let title = document.createElement('div'); - let link = document.createElement('div'); - link.className = "choices"; - if (_WL - reservedIncubator === 0) { - V.reservedChildren = 0; - title.textContent = `${His} children are already reserved for ${V.incubatorName}`; - title.style.fontStyle = "italic"; - } else { - const freeCribs = (V.nursery - V.cribs.length); - if (reservedNursery > 0) { - if (_WL === 1) { - title.textContent = `${His} child will be placed in ${V.nurseryName}. `; - } else if (reservedNursery < _WL) { - title.textContent = `_reservedNursery of ${his} children will be placed in ${V.nurseryName}.`; - } else if (_WL === 2) { - title.textContent = `Both of ${his} children will be placed in ${V.nurseryName}. `; - } else { - title.textContent = `All ${reservedNursery} of ${his} children will be placed in ${V.nurseryName}. `; - } - if ((reservedIncubator + reservedNursery < _WL) && (V.reservedChildrenNursery < freeCribs)) { - link.appendChild( - App.UI.DOM.link(`Keep another child`, () => wombUpdateNursery(1, true)) - ); - - if (reservedNursery > 0) { - link.append(` | `); - link.appendChild( - App.UI.DOM.link(`Keep one less child`, () => wombUpdateNursery(1, false)) - ); - } - if (reservedNursery > 1) { - link.append(` | `); - link.appendChild( - App.UI.DOM.link(`Keep none of ${his} children`, () => wombUpdateNursery(9999, false)) - ); - } - if ((V.reservedChildrenNursery + _WL - reservedNursery) <= freeCribs) { - link.append(` | `); - link.appendChild( - App.UI.DOM.link(`Keep the rest of ${his} children`, () => wombUpdateNursery(9999, true)) - ); - } - } else if ((reservedNursery === _WL) || (V.reservedChildrenNursery === freeCribs) || (reservedNursery - reservedIncubator >= 0)) { - link.appendChild( - App.UI.DOM.link(`Keep one less child`, () => wombUpdateNursery(1, false)) - ); - - if (reservedNursery > 1) { - link.append(` | `); - link.appendChild( - App.UI.DOM.link(`Keep none of ${his} children`, () => wombUpdateNursery(9999, false)) - ); - } - } - } else if (V.reservedChildrenNursery < freeCribs) { - title.textContent = `${He} is pregnant and you have `; - if (freeCribs === 1) { - title.textContent += `an `; - } - let crib = document.createElement('span'); - crib.className = "lime"; - crib.textContent = `available room`; - if (freeCribs > 1) { - crib.textContent += `s`; - } - crib.textContent += `.`; - let _cCount = (_WL > 1 ? "a" : "the"); - link.appendChild( - App.UI.DOM.link(`Keep ${_cCount} child`, () => wombUpdateNursery(1, true)) - ); - title.appendChild(crib); - if ((_WL > 1) && (V.reservedChildrenNursery + _WL) <= freeCribs) { - link.append(` | `); - link.appendChild( - App.UI.DOM.link(`Keep all of ${his} children`, () => wombUpdateNursery(9999, true)) - ); - } - } else if (V.reservedChildrenNursery === freeCribs) { - title.textContent = `You have no available rooms for ${his} children. `; - } - } - el.append(title); - el.append(link); - } - } - } - - function wombUpdateNursery(count, addToWomb) { - if (addToWomb) { - WombAddToGenericReserve(slave, "nursery", count); - } else { - WombCleanGenericReserve(slave, "nursery", count); - } V.reservedChildren = FetusGlobalReserveCount("nursery"); - App.UI.SlaveInteract.refreshAll(slave); - } - - return jQuery('#nursery').empty().append(el); -}; - -App.UI.SlaveInteract.rules = function(slave) { - const frag = new DocumentFragment(); - let p; - let div; - let array; - let choices; - const { - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - if (V.seePreg !== 0) { - if (V.universalRulesImpregnation === "PC") { - updateBreederLink("you", "PCExclude"); - } else if (V.universalRulesImpregnation === "HG") { - updateBreederLink("the Head Girl", "HGExclude"); - } else if (V.universalRulesImpregnation === "Stud") { - updateBreederLink("your Stud", "StudExclude"); - } - } - - function updateBreederLink(breeder, exclude) { - p = document.createElement('p'); - const exempt = slave[exclude] ? "Exempt" : "Include"; - - p.append(`Will be bred by ${breeder} when fertile. `); - p.append( - App.UI.DOM.link(`${exempt} ${him}`, () => { - slave[exclude] = slave[exclude] ^ 1; // switch 0 and 1 - App.UI.SlaveInteract.rules(slave); - }) - ); - frag.append(p); - } - - p = document.createElement('p'); - - array = []; - if (slave.useRulesAssistant === 0) { - App.UI.DOM.appendNewElement("span", p, `Not subject `, ["bold", "gray"]); - App.UI.DOM.appendNewElement("span", p, `to the Rules Assistant.`, "gray"); - array.push( - App.UI.DOM.link( - `Include ${him}`, - () => { - slave.useRulesAssistant = 1; - App.UI.SlaveInteract.rules(slave); - } - ) - ); - } else { - App.UI.DOM.appendNewElement("h3", p, `Rules Assistant`); - - if (slave.hasOwnProperty("currentRules") && slave.currentRules.length > 0) { - const ul = document.createElement("UL"); - ul.style.margin = "0"; - V.defaultRules.filter( - x => ruleApplied(slave, x) - ).map( - x => { - const li = document.createElement('li'); - li.append(x.name); - ul.append(li); - } - ); - - // set up rules display - if ($("ul").has("li").length ) { - App.UI.DOM.appendNewElement("div", p, `Rules applied: `); - p.append(ul); - } else { - App.UI.DOM.appendNewElement("div", p, `There are no rules that would apply to ${him}.`, "gray"); - } - } - array.push( - App.UI.DOM.link( - `Apply rules`, - () => { - DefaultRules(slave); - App.UI.SlaveInteract.rules(slave); - } - ) - ); - array.push( - App.UI.DOM.link( - `Exempt ${him}`, - () => { - slave.useRulesAssistant = 0; - App.UI.SlaveInteract.rules(slave); - } - ) - ); - array.push(App.UI.DOM.passageLink("Rules Assistant Options", "Rules Assistant")); - } - p.append(App.UI.DOM.generateLinksStrip(array)); - frag.append(p); - - p = document.createElement('p'); - App.UI.DOM.appendNewElement("h3", p, `Other Rules`); - - // Living - if (slave.fuckdoll > 0) { - App.UI.DOM.appendNewElement("span", p, "Rules have little meaning for living sex toys", "note"); - } else { - penthouseCensus(); - p.append("Living standard: "); - App.UI.DOM.appendNewElement("span", p, slave.rules.living, "bold"); - } - if (setup.facilityCareers.includes(slave.assignment)) { - App.UI.DOM.appendNewElement("span", p, ` ${His} living conditions are managed by ${his} assignment.`, "note"); - } else if ((slave.assignment === "be your Head Girl") && (V.HGSuite === 1)) { - App.UI.DOM.appendNewElement("span", p, ` ${He} has ${his} own little luxurious room in the penthouse with everything ${he} needs to be a proper Head Girl.`, "note"); - } else if ((slave.assignment === "guard you") && (V.dojo > 1)) { - App.UI.DOM.appendNewElement("span", p, ` ${He} has a comfortable room in the armory to call ${his} own.`, "note"); - } else { - choices = [ - {value: "spare"}, - {value: "normal"}, - ]; - if (canMoveToRoom(slave) || slave.rules.living === "luxurious") { - choices.push({value: "luxurious"}); - } else { - choices.push({ - title: `Luxurious`, - disabled: ["No luxurious rooms available"] - }); - } - - p.append(listChoices(choices, "living")); - } - - // Rest - if (["be a servant", "be a subordinate slave", "get milked", "please you", "serve in the club", "serve the public", "whore", "work as a farmhand", "work in the brothel", "work a glory hole"].includes(slave.assignment) || (V.dairyRestraintsSetting < 2 && slave.assignment === "work in the dairy")) { - div = document.createElement("div"); - div.append("Sleep rules: "); - App.UI.DOM.appendNewElement("span", div, slave.rules.rest, "bold"); - choices = [ - {value: "none"}, - {value: "cruel"}, - {value: "restrictive"}, - {value: "permissive"}, - {value: "mandatory"}, - ]; - div.append(listChoices(choices, "rest")); - p.append(div); - } - - // Mobility Aids - if (slave.fuckdoll > 0) { - // Sex toys don't move around on their own// - } else if (canMove(slave)) { - div = document.createElement("div"); - div.append("Use of mobility aids: "); - App.UI.DOM.appendNewElement("span", div, slave.rules.mobility, "bold"); - choices = [ - {value: "restrictive"}, - {value: "permissive"}, - ]; - div.append(listChoices(choices, "mobility")); - p.append(div); - } - - // Punishment - div = document.createElement("div"); - div.append("Typical punishment: "); - App.UI.DOM.appendNewElement("span", div, slave.rules.punishment, "bold"); - choices = [ - {value: "confinement"}, - {value: "whipping"}, - {value: "chastity"}, - {value: "situational"}, - ]; - div.append(listChoices(choices, "punishment")); - p.append(div); - - // Reward - div = document.createElement("div"); - div.append("Typical reward: "); - App.UI.DOM.appendNewElement("span", div, slave.rules.reward, "bold"); - choices = [ - {value: "relaxation"}, - {value: "drugs"}, - {value: "orgasm"}, - {value: "situational"}, - ]; - div.append(listChoices(choices, "reward")); - p.append(div); - - // Lactation - if (slave.lactation !== 2) { - div = document.createElement("div"); - div.append("Lactation maintenance: "); - App.UI.DOM.appendNewElement("span", div, slave.rules.lactation, "bold"); - choices = [ - { - title: "Left alone", - value: "none", - }, - ]; - - if (slave.lactation === 0) { - choices.push( - { - title: "Induce lactation", - value: "induce", - } - ); - } else { - choices.push( - { - title: "Maintain lactation", - value: "maintain", - } - ); - } - div.append(listChoices(choices, "lactation")); - p.append(div); - } - - p.append(orgasm(slave)); - - if (slave.voice !== 0) { - div = document.createElement("div"); - div.append("Speech rules: "); - App.UI.DOM.appendNewElement("span", div, slave.rules.speech, "bold"); - choices = [ - {value: "restrictive"}, - {value: "permissive"}, - ]; - if (slave.accent > 0 && slave.accent < 4) { - choices.push( - {value: "accent elimination"}, - ); - } else if (slave.accent > 3) { - choices.push( - {value: "language lessons"}, - ); - } - div.append(listChoices(choices, "speech")); - p.append(div); - } - - div = document.createElement("div"); - div.append("Relationship rules: "); - App.UI.DOM.appendNewElement("span", div, slave.rules.relationship, "bold"); - choices = [ - {value: "restrictive"}, - {value: "just friends"}, - {value: "permissive"}, - ]; - div.append(listChoices(choices, "relationship")); - p.append(div); - - p.append(smartSettings(slave)); - frag.append(p); - return jQuery('#rules').empty().append(frag); - - function listChoices(choices, property) { - const links = []; - for (const c of choices) { - const title = c.title || capFirstChar(c.value); - if (c.disabled) { - links.push( - App.UI.DOM.disabledLink( - title, c.disabled - ) - ); - } else { - links.push( - App.UI.DOM.link( - title, - () => { - slave.rules[property] = c.value; - App.UI.SlaveInteract.rules(slave); - } - ) - ); - } - } - return App.UI.DOM.generateLinksStrip(links); - } - function orgasm(slave) { - let el = document.createElement('div'); - - let title = document.createElement('div'); - title.textContent = `Non-assignment orgasm rules: `; - el.append(title); - - makeLinks("Masturbation", "rules.release.masturbation"); - makeLinks("Partner", "rules.release.partner"); - makeLinks("Family", "rules.release.family"); - makeLinks("Other slaves", "rules.release.slaves"); - makeLinks("Master", "rules.release.master", true); - - function makeLinks(text, setting, master = false) { - const options = - [{text: master ? `Grant` : `Allow`, updateSlave: {[setting]: 1}}, - {text: master ? `Deny` : `Forbid`, updateSlave: {[setting]: 0}}]; - - let links = document.createElement('div'); - links.append(`${text}: `); - links.append(status(_.get(slave, setting), master)); - links.appendChild(App.UI.SlaveInteract.generateRows(options, slave)); - links.className = "choices"; - el.append(links); - } - - function status(setting, master) { - let selected = document.createElement('span'); - selected.style.fontWeight = "bold"; - let text; - if (master) { - text = setting ? "granted" : "denied"; - } else { - text = setting ? "allowed" : "denied"; - } - selected.textContent = `${text}. `; - return selected; - } - - return el; - } - - function smartSettings(slave) { - let el = document.createElement('div'); - - const {His} = getPronouns(slave); - const bodyPart = []; - const BDSM = []; - const gender = []; - const level = []; - const usingBulletVibe = slave.vaginalAccessory === "smart bullet vibrator" || slave.dickAccessory === "smart bullet vibrator"; - - if (slave.clitPiercing === 3 || usingBulletVibe) { - // Level - level.push({text: `No sex`, updateSlave: {clitSetting: `none`}}); - level.push({text: `All sex`, updateSlave: {clitSetting: `all`}}); - - // Body part - bodyPart.push({text: `Vanilla`, updateSlave: {clitSetting: `vanilla`}}); - bodyPart.push({text: `Oral`, updateSlave: {clitSetting: `oral`}}); - bodyPart.push({text: `Anal`, updateSlave: {clitSetting: `anal`}}); - bodyPart.push({text: `Boobs`, updateSlave: {clitSetting: `boobs`}}); - if (V.seePreg !== 0) { - bodyPart.push({text: `Preg`, updateSlave: {clitSetting: `pregnancy`}}); - } - // BDSM - BDSM.push({text: `Sub`, updateSlave: {clitSetting: `submissive`}}); - BDSM.push({text: `Dom`, updateSlave: {clitSetting: `dom`}}); - BDSM.push({text: `Masochism`, updateSlave: {clitSetting: `masochist`}}); - BDSM.push({text: `Sadism`, updateSlave: {clitSetting: `sadist`}}); - BDSM.push({text: `Humiliation`, updateSlave: {clitSetting: `humiliation`}}); - - // Gender - gender.push({text: `Men`, updateSlave: {clitSetting: `men`}}); - gender.push({text: `Women`, updateSlave: {clitSetting: `women`}}); - gender.push({text: `Anti-men`, updateSlave: {clitSetting: `anti-men`}}); - gender.push({text: `Anti-women`, updateSlave: {clitSetting: `anti-women`}}); - } - - let label = null; - if (slave.clitPiercing === 3) { - label = `${His} smart ${slave.dick < 1 ? "clit" : "frenulum"} piercing `; - label += (usingBulletVibe) ? `and smart bullet vibrator are set to: ` : `is set to: `; - } - if (label) { - let title = App.UI.DOM.appendNewElement('div', el, label); - let selected = App.UI.DOM.appendNewElement('span', title, `${slave.clitSetting}. `); - selected.style.fontWeight = "bold"; - } - - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Level", level, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Body part", bodyPart, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "BDSM", BDSM, slave); - App.UI.SlaveInteract.appendLabeledChoiceRow(el, "Gender", gender, slave); - - return el; - } -}; - -App.UI.SlaveInteract.custom = (function() { - let el; - let label; - let result; - let textbox; - return custom; - - function custom(slave) { - let title; - el = document.createElement('div'); - - el.appendChild(intro(slave)); - - title = document.createElement('h3'); - title.textContent = `Art`; - el.appendChild(title); - el.appendChild(customSlaveImage(slave)); - el.appendChild(customHairImage(slave)); - - title = document.createElement('h3'); - title.textContent = `Names`; - el.appendChild(title); - el.appendChild(playerTitle(slave)); - el.appendChild(slaveFullName(slave)); - - title = document.createElement('h3'); - title.textContent = `Description`; - el.appendChild(title); - el.appendChild(hair(slave)); - el.appendChild(eyeColor(slave)); - el.appendChild(customTattoo(slave)); - el.appendChild(customOriginStory(slave)); - el.appendChild(customDescription(slave)); - el.appendChild(customLabel(slave)); - - return jQuery('#custom').empty().append(el); - } - - function intro(slave) { - const frag = new DocumentFragment(); - let p; - p = document.createElement('p'); - p.id = "rename"; - frag.append(p); - - p = document.createElement('p'); - p.className = "scene-p"; - p.append(`You may enter custom descriptors for your slave's hair color, hair style, tattoos, or anything else here. After typing, press `); - p.appendChild(App.UI.DOM.makeElement("kbd", "enter")); - p.append(` to commit your change. These custom descriptors will appear in descriptions of your slave, but will have no gameplay effect. Changing them is free.`); - frag.append(p); - return frag; - } - - function playerTitle(slave) { - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - let playerTitle = document.createElement('p'); - label = document.createElement('div'); - if (slave.devotion >= -50) { - if (slave.custom.title !== "") { - label.textContent = `You have instructed ${him} to always refer to you as ${slave.custom.title}, which, should ${he} lisp, comes out as ${slave.custom.titleLisp}.`; - } else { - label.textContent = `You expect ${him} to refer to you as all your other slaves do.`; - } - result = document.createElement('div'); - result.id = "result"; - result.className = "choices"; - - let hiddenTextBox = document.createElement('span'); - let shownTextBox = document.createElement('span'); - if (slave.custom.title === "") { - hiddenTextBox.appendChild( - App.UI.DOM.link( - `Set a custom title for ${him} to address you as`, - () => { - jQuery('#result').empty().append(shownTextBox); - } - ) - ); - result.appendChild(hiddenTextBox); - shownTextBox.textContent = `Custom title: `; - textbox = App.UI.DOM.makeTextBox( - "", - v => { - slave.custom.title = v; - jQuery('#result').empty().append( - document.createTextNode(`${He}'ll try ${his} best to call you ${slave.custom.title}.`) - ); - slave.custom.titleLisp = lispReplace(slave.custom.title); - }); - shownTextBox.appendChild(textbox); - } else { - result.append(`${He}'s trying ${his} best to call you `); - textbox = App.UI.DOM.makeTextBox( - slave.custom.title, - v => { - slave.custom.title = v; - jQuery('#result').empty().append( - document.createTextNode(`${He}'ll try ${his} best to call you ${slave.custom.title}.`) - ); - slave.custom.titleLisp = lispReplace(slave.custom.title); - }); - result.appendChild(textbox); - result.appendChild( - App.UI.DOM.link( - ` Stop using a custom title`, - () => { - jQuery('#result').empty().append( - document.createTextNode(`${He} will no longer refer to you with a special title.`) - ); - slave.custom.title = ""; - slave.custom.titleLisp = ""; - } - ) - ); - } - label.appendChild(result); - } else { - label.textContent = `You must break ${his} will further before ${he} will refer to you by a new title. `; - if (SlaveStatsChecker.checkForLisp(slave)) { - if (slave.custom.titleLisp && slave.custom.titleLisp !== "") { - label.textContent += `For now, ${he} intends to keep calling you "${slave.custom.titleLisp}."`; - } - } else { - if (slave.custom.title && slave.custom.title !== "") { - label.textContent += `For now, ${he} intends to keep calling you "${slave.custom.title}."`; - } - } - } - playerTitle.appendChild(label); - return playerTitle; - } - - function slaveFullName(slave) { - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - let slaveFullNameNode = document.createElement('span'); - if ( - ((slave.devotion >= -50 || slave.trust < -20) && (slave.birthName !== slave.slaveName)) || - (slave.devotion > 20 || slave.trust < -20) - ) { - slaveFullNameNode.appendChild(slaveName()); - slaveFullNameNode.appendChild(slaveSurname()); - } else { - slaveFullNameNode.textContent = `You must break ${his} will further before you can successfully force a new name on ${him}.`; - slaveFullNameNode.className = "note"; - } - - return slaveFullNameNode; - - function slaveName() { - const oldName = slave.slaveName; - const oldSurname = slave.slaveSurname; - // Slave Name - let slaveNameNode = document.createElement('p'); - label = document.createElement('div'); - result = document.createElement('div'); - result.id = "result"; - result.className = "choices"; - const linkArray = []; - - label.append(`Change ${his} given name`); - if (slave.birthName !== slave.slaveName) { - label.append(` (${his} birth name was ${slave.birthName})`); - } - label.append(`: `); - - textbox = App.UI.DOM.makeTextBox( - slave.slaveName, - v => { - slave.slaveName = v; - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - ); - label.appendChild(textbox); - - slaveNameNode.appendChild(label); - - if (slave.slaveName === slave.birthName) { - linkArray.push(App.UI.DOM.disabledLink(`${He} has ${his} birth name`, [`Nothing to reset`])); - } else { - linkArray.push(App.UI.DOM.link( - `Restore ${his} birth name`, - () => { - slave.slaveName = slave.birthName; - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - )); - } - - if (V.arcologies[0].FSPastoralist !== "unset") { - if (slave.lactation > 0) { - linkArray.push(chooseThreeNames(`Choose a random cow name for ${him}`, setup.cowSlaveNames, "cow-names")); - } - } - if (V.arcologies[0].FSIntellectualDependency !== "unset") { - if (slave.intelligence + slave.intelligenceImplant < -10) { - linkArray.push(chooseThreeNames(`Give ${him} a random stripper given name`, setup.bimboSlaveNames, "bimbo-names")); - } - } - if (V.arcologies[0].FSChattelReligionist !== "unset") { - linkArray.push(chooseThreeNames(`Give ${him} a random devotional given name`, setup.chattelReligionistSlaveNames, "devotional-names")); - } - result.append(App.UI.DOM.generateLinksStrip(linkArray)); - slaveNameNode.appendChild(result); - return slaveNameNode; - - function chooseThreeNames(title, array, id) { - const el = document.createElement("span"); - el.id = id; - el.append( - App.UI.DOM.link( - title, - () => { - linkGuts(); - } - ) - ); - return el; - function linkGuts() { - // Randomize the array - const shuffled = array.sort(() => 0.5 - Math.random()); - - // Get the first three new names - const names = []; - for (let i = 0; names.length < 3; i++) { - if (i > shuffled.length) { - break; - } - if (shuffled[i] !== slave.slaveName) { - names.push(shuffled[i]); - } - } - - // return the three names as links - const nameLinks = []; - for (const name of names) { - nameLinks.push( - App.UI.DOM.link( - name, - () => { - slave.slaveName = name; - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - } - ) - ); - } - nameLinks.push( - App.UI.DOM.link( - "...", - () => { - linkGuts(); - } - ) - ); - jQuery(`#${id}`).empty().append(App.UI.DOM.generateLinksStrip(nameLinks)); - } - } - } - - function slaveSurname() { - // Slave Surname - const oldName = slave.slaveName; - const oldSurname = slave.slaveSurname; - let slaveSurnameNode = document.createElement('p'); - label = document.createElement('div'); - result = document.createElement('div'); - result.id = "result"; - result.className = "choices"; - - label.append(`Change ${his} surname`); - if (slave.birthSurname !== slave.slaveSurname) { - label.append(` (${his} birth surname was ${slave.birthSurname})`); - } - label.append(`: `); - - textbox = App.UI.DOM.makeTextBox( - slave.slaveSurname, - v => { - slave.slaveSurname = textbox.value; - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - ); - label.appendChild(textbox); - - slaveSurnameNode.appendChild(label); - - if (slave.slaveSurname === slave.birthSurname) { - result.append(` ${He} has ${his} birth surname`); - } else { - result.appendChild(App.UI.DOM.link( - ` Restore ${his} birth surname`, - () => { - slave.slaveSurname = slave.birthSurname; - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - )); - } - - if (slave.slaveSurname) { - result.append(` | `); - result.appendChild(App.UI.DOM.link( - `Take ${his} surname away`, - () => { - slave.slaveSurname = 0; - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - )); - } - if (slave.relationship >= 5) { - const spouse = getSlave(slave.relationshipTarget); - if (spouse.slaveSurname && slave.slaveSurname !== spouse.slaveSurname) { - result.append(` | `); - const wifePronouns = getPronouns(spouse); - result.appendChild(App.UI.DOM.link( - `Give ${him} ${his} ${wifePronouns.wife}'s surname`, - () => { - slave.slaveSurname = spouse.slaveSurname; - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - )); - } - } - if (slave.relationship === -3) { - if (V.PC.slaveSurname && slave.slaveSurname !== V.PC.slaveSurname) { - result.append(` | `); - result.appendChild(App.UI.DOM.link( - `Give ${him} your surname`, - () => { - slave.slaveSurname = V.PC.slaveSurname; - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - )); - } - } - if (V.arcologies[0].FSRomanRevivalist !== "unset") { - result.append(` | `); - result.appendChild(App.UI.DOM.link( - `Give ${him} a random full Roman name`, - () => { - slave.slaveName = setup.romanSlaveNames.random(); - slave.slaveSurname = setup.romanSlaveSurnames.random(); - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - )); - } else if (V.arcologies[0].FSAztecRevivalist !== "unset") { - result.append(` | `); - result.appendChild(App.UI.DOM.link( - `Give ${him} a random full Aztec name`, - () => { - slave.slaveName = setup.aztecSlaveNames.random(); - slave.slaveSurname = 0; - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - )); - } else if (V.arcologies[0].FSEgyptianRevivalist !== "unset") { - result.append(` | `); - result.appendChild(App.UI.DOM.link( - `Give ${him} a random full ancient Egyptian name`, - () => { - slave.slaveName = setup.ancientEgyptianSlaveNames.random(); - slave.slaveSurname = 0; - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - )); - } else if (V.arcologies[0].FSEdoRevivalist !== "unset") { - result.append(` | `); - result.appendChild(App.UI.DOM.link( - `Give ${him} a random full feudal Japanese name`, - () => { - slave.slaveName = setup.edoSlaveNames.random(); - slave.slaveSurname = setup.edoSlaveSurnames.random(); - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - )); - } - if (V.arcologies[0].FSDegradationist > -1) { - result.append(` | `); - result.appendChild(App.UI.DOM.link( - `Give ${him} a degrading full name`, - () => { - DegradingName(slave); - updateName(slave, {oldName: oldName, oldSurname: oldSurname}); - }, - false, - )); - } - slaveSurnameNode.appendChild(result); - return slaveSurnameNode; - } - function updateName(slave, {oldName: oldName, oldSurname: oldSurname}) { - App.UI.SlaveInteract.custom(slave); - App.UI.SlaveInteract.rename(slave, {oldName: oldName, oldSurname: oldSurname}); - } - } - - /** - * @param {App.Entity.SlaveState} slave - */ - function hair(slave) { - let hairNode = new DocumentFragment(); - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - - hairNode.appendChild(hairStyle()); - hairNode.appendChild(hairColor()); - return hairNode; - - function hairStyle() { - let hairStyleNode = document.createElement('p'); - let label = document.createElement('div'); - label.append(`Custom hair description: `); - - let textbox = App.UI.DOM.makeTextBox( - slave.hStyle, - v => { - slave.hStyle = v; - App.UI.SlaveInteract.custom(slave); - }); - label.appendChild(textbox); - - switch (slave.hStyle) { - case "tails": - case "dreadlocks": - case "cornrows": - label.append(` "${His} hair is in ${slave.hStyle}."`); - break; - case "ponytail": - label.append(` "${His} hair is in a ${slave.hStyle}."`); - break; - default: - label.append(` "${His} hair is ${slave.hStyle}."`); - break; - } - hairStyleNode.appendChild(label); - - let choices = document.createElement('div'); - choices.className = "choices"; - choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, use a short, uncapitalized and unpunctuated description; for example: 'back in a ponytail'`, 'note')); - hairStyleNode.appendChild(choices); - return hairStyleNode; - } - - function hairColor() { - let hairStyleNode = document.createElement('p'); - let label = document.createElement('div'); - label.append(`Custom hair color: `); - - let textbox = App.UI.DOM.makeTextBox( - slave.hColor, - v => { - slave.hColor = v; - App.UI.SlaveInteract.custom(slave); - }); - label.appendChild(textbox); - label.append(` "${His} hair is ${slave.hColor}."`); - hairStyleNode.appendChild(label); - - let choices = document.createElement('div'); - choices.className = "choices"; - choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, use a short, uncapitalized and unpunctuated description; for example: 'black with purple highlights'`, 'note')); - hairStyleNode.appendChild(choices); - return hairStyleNode; - } - } - - /** - * @param {App.Entity.SlaveState} slave - */ - function eyeColor(slave) { - let eyeColorNode = document.createElement('p'); - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - let label = document.createElement('div'); - if (getLenseCount(slave) > 0) { - label.textContent = `${He} is wearing ${App.Desc.eyesColor(slave, "", "lense", "lenses")}.`; - } else { - label.textContent = `${He} has ${App.Desc.eyesColor(slave)}.`; - } - eyeColorNode.appendChild(label); - - let choices = document.createElement('div'); - choices.className = "choices"; - - let eye; - let textbox; - - if (hasLeftEye(slave)) { - eye = document.createElement('div'); - eye.append(`Custom left eye color: `); - textbox = App.UI.DOM.makeTextBox( - slave.eye.left.iris, - v => { - slave.eye.left.iris = v; - App.UI.SlaveInteract.custom(slave); - }); - eye.appendChild(textbox); - choices.appendChild(eye); - } - if (hasRightEye(slave)) { - eye = document.createElement('div'); - eye.append(`Custom right eye color: `); - textbox = App.UI.DOM.makeTextBox( - slave.eye.right.iris, - v => { - slave.eye.right.iris = v; - App.UI.SlaveInteract.custom(slave); - }); - eye.appendChild(textbox); - choices.appendChild(eye); - } - choices.appendChild(App.UI.DOM.makeElement('span', `For best results, use a short, uncapitalized and unpunctuated description; for example: 'blue'`, 'note')); - eyeColorNode.appendChild(choices); - return eyeColorNode; - } - - /** - * @param {App.Entity.SlaveState} slave - */ - function customTattoo(slave) { - let el = document.createElement('p'); - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - el.append(`Change ${his} custom tattoo: `); - el.appendChild(App.UI.DOM.makeTextBox( - slave.custom.tattoo, - v => { - slave.custom.tattoo = v; - App.UI.SlaveInteract.custom(slave); - })); - - let choices = document.createElement('div'); - choices.className = "choices"; - choices.appendChild(App.UI.DOM.makeElement('span', `For best results, use complete sentences; for example: '${He} has blue stars tattooed along ${his} cheekbones.'`, 'note')); - el.appendChild(choices); - - return el; - } - - function customOriginStory(slave) { - let el = document.createElement('p'); - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - - el.append(`Change ${his} origin story: `); - el.appendChild(App.UI.DOM.makeTextBox( - slave.origin, - v => { - slave.origin = v; - App.UI.SlaveInteract.custom(slave); - })); - - let choices = document.createElement('div'); - choices.className = "choices"; - choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, use complete, capitalized and punctuated sentences; for example: '${He} followed you home from the pet store.'`, 'note')); - el.appendChild(choices); - - return el; - } - - function customDescription(slave) { - let el = document.createElement('p'); - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - - el.append(`Change ${his} custom description: `); - el.appendChild(App.UI.DOM.makeTextBox( - pronounsForSlaveProp(slave, slave.custom.desc), - v => { - slave.custom.desc = v; - App.UI.SlaveInteract.custom(slave); - })); - - let choices = document.createElement('div'); - choices.className = "choices"; - choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, use complete, capitalized and punctuated sentences; for example: '${He} has a beauty mark above ${his} left nipple.'`, 'note')); - el.appendChild(choices); - - return el; - } - - function customLabel(slave) { - let el = document.createElement('p'); - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - - el.append(`Change ${his} custom label: `); - el.appendChild(App.UI.DOM.makeTextBox( - slave.custom.label, - v => { - slave.custom.label = v; - App.UI.SlaveInteract.custom(slave); - })); - - let choices = document.createElement('div'); - choices.className = "choices"; - choices.appendChild(App.UI.DOM.makeElement('span', ` For best results, use a short phrase; for example: 'Breeder.'`, 'note')); - el.appendChild(choices); - - return el; - } - - - function customSlaveImage(slave) { - let el = document.createElement('p'); - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - el.append(`Assign ${him} a custom image: `); - - let textbox = document.createElement("INPUT"); - textbox.id = "customImageValue"; - el.appendChild(textbox); - - - let kbd = document.createElement('kbd'); - let select = document.createElement('SELECT'); - select.id = "customImageFormatSelector"; - select.style.border = "none"; - - let filetypes = [ - "png", - "jpg", - "gif", - "webm", - "webp", - "mp4" - ]; - - filetypes.forEach((fileType) => { - let el = document.createElement('OPTION'); - el.value = fileType; - el.text = fileType.toUpperCase(); - select.add(el); - }); - kbd.append(`.`); - kbd.appendChild(select); - el.appendChild(kbd); - - el.appendChild( - App.UI.DOM.link( - ` Reset`, - () => { - slave.custom.image = null; - App.UI.SlaveInteract.custom(slave); - App.Art.refreshSlaveArt(slave, 3, "art-frame"); - }, - ) - ); - - let choices = document.createElement('div'); - choices.className = "choices"; - let note = document.createElement('span'); - note.className = "note"; - note.append(`Place file in the `); - - kbd = document.createElement('kbd'); - kbd.append(`resources`); - note.appendChild(kbd); - - note.append(` folder. Choose the extension from the menu first, then enter the filename in the space and press enter. For example, for a file with the path `); - - kbd = document.createElement('kbd'); - kbd.textContent = `\\bin\\resources\\headgirl.`; - let filetypeDesc = document.createElement('span'); - filetypeDesc.id = "customImageFormatValue"; - filetypeDesc.textContent = "png"; - kbd.appendChild(filetypeDesc); - note.appendChild(kbd); - - note.append(`, choose `); - - kbd = document.createElement('kbd'); - kbd.textContent = `PNG`; - note.appendChild(kbd); - - note.append(` then enter `); - - kbd = document.createElement('kbd'); - kbd.textContent = `headgirl`; - note.appendChild(kbd); - - note.append(`.`); - choices.appendChild(note); - el.appendChild(choices); - - jQuery(function() { - function activeSlave() { - return slave; - } - - jQuery("#customImageFormatValue").text(activeSlave().custom.image === null ? "png" : activeSlave().custom.image.format); - jQuery("#customImageValue") - .val(activeSlave().custom.image === null ? - "" : activeSlave().custom.image.filename) - .on("change", function(e) { - const c = activeSlave().custom; - if (this.value.length === 0) { - c.image = null; - } else { - if (c.image === null) { - c.image = { - filename: this.value, - format: jQuery("#customImageFormatSelector").val() - }; - App.Art.refreshSlaveArt(slave, 3, "art-frame"); - } else { - c.image.filename = this.value; - App.Art.refreshSlaveArt(slave, 3, "art-frame"); - } - } - }); - jQuery("#customImageFormatSelector") - .val(activeSlave().custom.image ? activeSlave().custom.image.format : "png") - .on("change", function(e) { - if (activeSlave().custom.image !== null) { - activeSlave().custom.image.format = this.value; - } - jQuery("#customImageFormatValue").text(this.value); - }); - }); - return el; - } - - function customHairImage(slave) { - let el = document.createElement('p'); - const { - // eslint-disable-next-line no-unused-vars - he, - him, - his, - hers, - himself, - boy, - He, - His - } = getPronouns(slave); - - if (V.seeImages === 1 && V.imageChoice === 1) { - if (!slave.custom.hairVector) { - slave.custom.hairVector = 0; - } - el.append(`Assign ${him} a custom hair SVG image: `); - - el.appendChild(App.UI.DOM.makeTextBox( - slave.custom.hairVector, - v => { - slave.custom.hairVector = v; - App.UI.SlaveInteract.custom(slave); - })); - - el.appendChild( - App.UI.DOM.link( - ` Reset`, - () => { - slave.custom.hairVector = 0; - App.UI.SlaveInteract.custom(slave); - App.Art.refreshSlaveArt(slave, 3, "art-frame"); - }, - ) - ); - } - - return el; - } -})(); - -/** @typedef RowItem - * @type {object} - * @property {string} [FS] - FS requirement, if any - * @property {string} [text] - link text - * @property {object} [updateSlave] - properties to be merged onto the slave - * @property {object} [update] - properties to be merged into global state - * @property {string} [disabled] - text indicating why the option is unavailable - * @property {string} [note] - */ - -/** Append a simple row of choices with a label to a container, if there are choices to be made. - * @param {Node} parent - * @param {string} label - * @param {RowItem[]} array - * @param {App.Entity.SlaveState} slave - */ -App.UI.SlaveInteract.appendLabeledChoiceRow = function(parent, label, array, slave) { - if (array.length > 0) { - let links = document.createElement('div'); - links.append(`${label}: `); - links.appendChild(App.UI.SlaveInteract.generateRows(array, slave)); - links.className = "choices"; - return parent.appendChild(links); - } -}; - -/** Generate a row of choices - * @param {RowItem[]} array - * @param {App.Entity.SlaveState} slave - * @param {string} [category] - should be in the form of slave.category, the thing we want to update. - * @param {boolean} [accessCheck=false] - * @returns {HTMLSpanElement} - */ -App.UI.SlaveInteract.generateRows = function(array, slave, category, accessCheck = false) { - let row = document.createElement('span'); - let useSep = false; - for (let i = 0; i < array.length; i++) { - let link; - const separator = document.createTextNode(` | `); - const keys = Object.keys(array[i]); - - // Test to see if there was a problem with the key - for (let j = 0; j < keys.length; j++) { - if (["FS", "text", "updateSlave", "update", "note", "disabled"].includes(keys[j])) { - continue; - } else { - array[i].text += " ERROR, THIS SCENE WAS NOT ENTERED CORRECTLY"; - console.log("Trash found while generateRows() was running: " + keys[j] + ": " + array[i][keys[j]]); - break; - } - } - // Some items will never be in App.Data.slaveWear, especially "none" if it falls in between harsh and nice data sets. Trying to look it up would cause an error, which is what access check works around. - let unlocked = false; - if (accessCheck === true) { - if (category === "chastity") { - let text = array[i].text.toLowerCase(); // Yucky. Category name does not match for chastity (since it sets multiple kinds of chastity at once). Compare using a lowercase name instead. - unlocked = isItemAccessible.entry(text, category, slave); - } else { - unlocked = isItemAccessible.entry(array[i].updateSlave[category], category, slave); - } - } - if (accessCheck === false || unlocked) { - if (i < array.length && i !== 0 && useSep === true) { // start with separator (after first loop); can't after since the last loop may not have any text. - row.appendChild(separator); - } - useSep = true; // First item may not appear and if it doesn't we don't want the second to start with a '|' - // is it just text? - if (array[i].disabled) { - link = App.UI.DOM.disabledLink(array[i].text, [array[i].disabled]); - } else if (typeof unlocked === 'string') { - link = App.UI.DOM.disabledLink(array[i].text, [unlocked]); - } else { - link = document.createElement('span'); - - // Set up the link - link.appendChild( - App.UI.DOM.link( - `${array[i].text} `, - () => { click(array[i]); }, - ) - ); - - if (array[i].FS) { - let FS = App.UI.DOM.disabledLink(`FS`, [FutureSocieties.displayAdj(array[i].FS)]); - FS.style.fontStyle = "italic"; - link.appendChild(FS); - } - - // add a note node if required - if (array[i].note) { - link.appendChild(App.UI.DOM.makeElement('span', ` ${array[i].note}`, 'note')); - } - } - row.appendChild(link); - } - } - - return row; - - /** @param {RowItem} arrayOption */ - function click(arrayOption) { - if (arrayOption.updateSlave) { - for (const slaveProperty in arrayOption.updateSlave) { - _.set(slave, slaveProperty, arrayOption.updateSlave[slaveProperty]); - } - } - if (arrayOption.update) { - Object.assign(V, arrayOption.update); - } - App.UI.Wardrobe.refreshAll(slave); - App.UI.SlaveInteract.refreshAll(slave); - } -}; - -App.UI.SlaveInteract.refreshAll = function(slave) { - App.UI.SlaveInteract.drugs(slave); - App.UI.SlaveInteract.bloating(slave); - App.UI.SlaveInteract.fertility(slave); - App.UI.SlaveInteract.curatives(slave); - App.UI.SlaveInteract.aphrodisiacs(slave); - App.UI.SlaveInteract.incubator(slave); - App.UI.SlaveInteract.nursery(slave); - App.UI.SlaveInteract.custom(slave); - App.UI.SlaveInteract.hormones(slave); - App.UI.SlaveInteract.diet(slave); - App.UI.SlaveInteract.dietBase(slave); - App.UI.SlaveInteract.snacks(slave); - App.UI.SlaveInteract.rules(slave); - App.UI.SlaveInteract.work(slave); }; diff --git a/src/interaction/wardrobeUse.js b/src/interaction/wardrobeUse.js deleted file mode 100644 index 772d8800f22d362d24390ad902940a9c8e6c0f86..0000000000000000000000000000000000000000 --- a/src/interaction/wardrobeUse.js +++ /dev/null @@ -1,888 +0,0 @@ -App.UI.Wardrobe = {}; - -App.UI.Wardrobe.clothes = function(slave) { - const { - // eslint-disable-next-line no-unused-vars - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - let el = document.createElement('div'); - let links; - if (slave.fuckdoll === 0) { - // <<= App.Desc.clothing($activeSlave)>> - - let label = document.createElement('div'); - label.append(`Clothes: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.clothes} `); - label.appendChild(choice); - - // Choose her own - if (slave.clothes !== `choosing her own clothes`) { - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `Let ${him} choose`, updateSlave: {clothes: `choosing her own clothes`, choosesOwnClothes: 1}}); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "clothes", false)); - } - el.appendChild(label); - - - let niceOptionsArray = []; - let harshOptionsArray = []; - - let clothingOption; - // Nice clothes - App.Data.slaveWear.niceClothes.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {clothes: item.value, choosesOwnClothes: 0}, - FS: item.fs - }; - niceOptionsArray.push(clothingOption); - }); - // Harsh clothes - App.Data.slaveWear.harshClothes.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {clothes: item.value, choosesOwnClothes: 0}, - FS: item.fs - }; - if (item.value !== "choosing her own clothes") { - harshOptionsArray.push(clothingOption); - } - }); - - // Sort - niceOptionsArray = niceOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - harshOptionsArray = harshOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - - // Nice options - links = document.createElement('div'); - links.className = "choices"; - links.append(`Nice: `); - links.appendChild(App.UI.SlaveInteract.generateRows(niceOptionsArray, slave, "clothes", true)); - el.appendChild(links); - - // Harsh options - links = document.createElement('div'); - links.className = "choices"; - links.append(`Harsh: `); - links.appendChild(App.UI.SlaveInteract.generateRows(harshOptionsArray, slave, "clothes", true)); - el.appendChild(links); - } - if (slave.fuckdoll !== 0 || slave.clothes === "restrictive latex" || slave.clothes === "a latex catsuit" || slave.clothes === "a cybersuit" || slave.clothes === "a comfortable bodysuit") { - if (V.seeImages === 1 && V.imageChoice === 1) { - // Color options - links = document.createElement('div'); - links.className = "choices"; - links.append(`Color: `); - links.appendChild(App.UI.Wardrobe.colorOptions(slave, "clothingBaseColor")); - el.appendChild(links); - } - } - - return jQuery('#clothes').empty().append(el); -}; - -App.UI.Wardrobe.collar = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - // <<= App.Desc.collar($activeSlave)>> - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Collar: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.collar} `); - label.appendChild(choice); - - // Choose her own - if (slave.collar !== `none`) { - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `None`, updateSlave: {collar: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "collar", false)); - } - - el.appendChild(label); - - let niceOptionsArray = []; - let harshOptionsArray = []; - - let clothingOption; - // Nice collar - App.Data.slaveWear.niceCollars.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {collar: item.value}, - FS: item.fs - }; - niceOptionsArray.push(clothingOption); - }); - // Harsh collar - App.Data.slaveWear.harshCollars.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {collar: item.value}, - FS: item.fs - }; - harshOptionsArray.push(clothingOption); - }); - - // Sort - niceOptionsArray = niceOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - harshOptionsArray = harshOptionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - - // Nice options - let links = document.createElement('div'); - links.className = "choices"; - links.append(`Nice: `); - links.appendChild(App.UI.SlaveInteract.generateRows(niceOptionsArray, slave, "collar", true)); - el.appendChild(links); - - // Harsh options - links = document.createElement('div'); - links.className = "choices"; - links.append(`Harsh: `); - links.appendChild(App.UI.SlaveInteract.generateRows(harshOptionsArray, slave, "collar", true)); - el.appendChild(links); - - return jQuery('#collar').empty().append(el); -}; - -App.UI.Wardrobe.mask = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Mask: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.faceAccessory} `); - label.appendChild(choice); - - // Choose her own - if (slave.faceAccessory !== `none`) { - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `None`, updateSlave: {faceAccessory: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "faceAccessory", false)); - } - - el.appendChild(label); - - let array = []; - - let clothingOption; - App.Data.slaveWear.faceAccessory.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {faceAccessory: item.value}, - FS: item.fs - }; - array.push(clothingOption); - }); - - // Sort - array = array.sort((a, b) => (a.text > b.text) ? 1 : -1); - - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "faceAccessory", true)); - el.appendChild(links); - - if (slave.eyewear === "corrective glasses" || slave.eyewear === "glasses" || slave.eyewear === "blurring glasses" || slave.faceAccessory === "porcelain mask") { - // Color options - links = document.createElement('div'); - links.className = "choices"; - links.append(`Color: `); - links.appendChild(App.UI.Wardrobe.colorOptions(slave, "glassesColor")); - let note = document.createElement('span'); - note.className = "note"; - note.textContent = ` Only glasses and porcelain masks support a custom color. If both are worn, they will share the same color.`; - links.appendChild(note); - el.appendChild(links); - } - - return jQuery('#faceAccessory').empty().append(el); -}; - -App.UI.Wardrobe.mouth = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Gag: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.mouthAccessory} `); - label.appendChild(choice); - - // Choose her own - if (slave.mouthAccessory !== `none`) { - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `None`, updateSlave: {mouthAccessory: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "mouthAccessory", false)); - } - - el.appendChild(label); - - let array = []; - - let clothingOption; - // mouthAccessory - App.Data.slaveWear.mouthAccessory.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {mouthAccessory: item.value}, - FS: item.fs - }; - array.push(clothingOption); - }); - - // Sort - array = array.sort((a, b) => (a.text > b.text) ? 1 : -1); - - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "mouthAccessory", true)); - el.appendChild(links); - - return jQuery('#mouthAccessory').empty().append(el); -}; - -App.UI.Wardrobe.armAccessory = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - - let el = document.createElement('div'); - // App.Desc.armwear(slave) - - let label = document.createElement('div'); - label.append(`Arm accessory: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.armAccessory} `); - label.appendChild(choice); - - let array = []; - - // Choose her own - if (slave.armAccessory !== "none") { - array.push({text: `None`, updateSlave: {armAccessory: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "armAccessory", false)); - } - - el.appendChild(label); - - let links = document.createElement('div'); - links.className = "choices"; - array = [ - {text: "Hand gloves", updateSlave: {armAccessory: "hand gloves"}}, - {text: "Elbow gloves", updateSlave: {armAccessory: "elbow gloves"}} - ]; - links.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "armAccessory", false)); - el.appendChild(links); - - return jQuery('#armAccessory').empty().append(el); -}; - -App.UI.Wardrobe.shoes = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - - const - { - // eslint-disable-next-line no-unused-vars - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Shoes: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.shoes} `); - label.appendChild(choice); - - /* We have "barefoot" in App.Data.slaveWear to cover for this - // Choose her own - if (slave.shoes !== `none`) { - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `None`, updateSlave: {shoes: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "shoes", false)); - } - */ - el.appendChild(label); - - let optionsArray = []; - - let clothingOption; - App.Data.slaveWear.shoes.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {shoes: item.value}, - FS: item.fs - }; - optionsArray.push(clothingOption); - }); - - // Sort - // No sort here since we want light -> advanced. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - - // Options - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "shoes", true)); - el.appendChild(links); - - if (V.seeImages === 1 && V.imageChoice === 1 && slave.shoes !== "none") { - // Color options - links = document.createElement('div'); - links.className = "choices"; - links.append(`Color: `); - links.appendChild(App.UI.Wardrobe.colorOptions(slave, "shoeColor")); - el.appendChild(links); - } - - return jQuery('#shoes').empty().append(el); -}; - -App.UI.Wardrobe.legAccessory = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - - const { - // eslint-disable-next-line no-unused-vars - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Leg accessory: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.legAccessory} `); - label.appendChild(choice); - - let array = []; - - // Choose her own - if (slave.legAccessory !== "none") { - array.push({text: `None`, updateSlave: {legAccessory: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "legAccessory", false)); - } - - el.appendChild(label); - - let links = document.createElement('div'); - links.className = "choices"; - array = [ - {text: "Short stockings", updateSlave: {legAccessory: "short stockings"}}, - {text: "Long stockings", updateSlave: {legAccessory: "long stockings"}} - ]; - links.appendChild(App.UI.SlaveInteract.generateRows(array, slave, "legAccessory", false)); - el.appendChild(links); - - return jQuery('#legAccessory').empty().append(el); -}; - -App.UI.Wardrobe.bellyAccessory = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - // <<waistDescription>><<= App.Desc.pregnancy($activeSlave)>><<clothingCorsetDescription>> - - const { - // eslint-disable-next-line no-unused-vars - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `None`, updateSlave: {bellyAccessory: `none`}}); - - let optionsArray = []; - - let clothingOption; - App.Data.slaveWear.bellyAccessories.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {bellyAccessory: item.value}, - FS: item.fs - }; - if (item.value !== "none") { - // skip none in set, we set the link elsewhere. - optionsArray.push(clothingOption); - } - }); - // Sort - // No sort here since we want small -> large.optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Belly accessory: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.bellyAccessory} `); - label.appendChild(choice); - - // Choose her own - if (slave.bellyAccessory !== `none`) { - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "bellyAccessory", false)); - } - - el.appendChild(label); - - // Options - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "bellyAccessory", true)); - if (slave.pregKnown === 1) { - let note = document.createElement('span'); - note.className = "note"; - note.textContent = ` Extreme corsets will endanger the life within ${him}.`; - links.appendChild(note); - } - el.appendChild(links); - - return jQuery('#bellyAccessory').empty().append(el); -}; - -App.UI.Wardrobe.buttplug = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - // App.Desc.buttplug(slave) - - const { - // eslint-disable-next-line no-unused-vars - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Anal accessory: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.buttplug} `); - label.appendChild(choice); - - if (slave.buttplug !== `none`) { - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `None`, updateSlave: {buttplug: `none`, buttplugAttachment: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "buttplug", false)); - } - el.appendChild(label); - - let optionsArray = []; - - let clothingOption; - App.Data.slaveWear.buttplugs.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {buttplug: item.value}, - FS: item.fs - }; - if (item.value !== "none") { - // skip none in set, we set the link elsewhere. - optionsArray.push(clothingOption); - } - }); - - // Sort - // No sort here since we want small -> large. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - - // Options - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "buttplug", true)); - el.appendChild(links); - - return jQuery('#buttplug').empty().append(el); -}; - -App.UI.Wardrobe.buttplugAttachment = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } else if (slave.buttplug === "none") { - return jQuery('#buttplugAttachment').empty(); - } - - const { - // eslint-disable-next-line no-unused-vars - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Anal accessory attachment: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.buttplugAttachment} `); - label.appendChild(choice); - - if (slave.buttplugAttachment !== `none`) { - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `None`, updateSlave: {buttplugAttachment: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "buttplugAttachment", false)); - } - el.appendChild(label); - - let optionsArray = []; - - let clothingOption; - App.Data.slaveWear.buttplugAttachments.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {buttplugAttachment: item.value}, - FS: item.fs - }; - if (item.value !== "none") { - // skip none in set, we set the link elsewhere. - optionsArray.push(clothingOption); - } - }); - - // Sort - optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - - // Options - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "buttplugAttachment", true)); - el.appendChild(links); - - return jQuery('#buttplugAttachment').empty().append(el); -}; - -App.UI.Wardrobe.vaginalAccessory = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - - // <<vaginalAccessoryDescription>> - const { - // eslint-disable-next-line no-unused-vars - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Vaginal accessory: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.vaginalAccessory} `); - label.appendChild(choice); - - if (slave.vaginalAccessory !== `none`) { - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `None`, updateSlave: {vaginalAccessory: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "vaginalAccessory", false)); - } - el.appendChild(label); - - let optionsArray = []; - - let clothingOption; - App.Data.slaveWear.vaginalAccessories.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {vaginalAccessory: item.value}, - FS: item.fs - }; - if (item.value !== "none") { - // skip none in set, we set the link elsewhere. - optionsArray.push(clothingOption); - } - }); - - // Sort - // No sort here since we want small -> large. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - - // Options - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "vaginalAccessory", true)); - el.appendChild(links); - - return jQuery('#vaginalAccessory').empty().append(el); -}; - -App.UI.Wardrobe.vaginalAttachment = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } else if (["none", "bullet vibrator", "smart bullet vibrator"].includes(slave.vaginalAccessory)) { - return jQuery('#vaginalAttachment').empty(); - } - // App.Desc.vaginalAttachment(slave); - - const { - // eslint-disable-next-line no-unused-vars - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Vaginal accessory attachment: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.vaginalAttachment} `); - label.appendChild(choice); - - if (slave.vaginalAttachment !== `none`) { - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `None`, updateSlave: {vaginalAttachment: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "vaginalAttachment", false)); - } - el.appendChild(label); - - let optionsArray = []; - - let clothingOption; - App.Data.slaveWear.vaginalAttachments.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {vaginalAttachment: item.value}, - FS: item.fs - }; - if (item.value !== "none") { - // skip none in set, we set the link elsewhere. - optionsArray.push(clothingOption); - } - }); - - // Sort - optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - - // Options - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "vaginalAttachment", true)); - el.appendChild(links); - - return jQuery('#vaginalAttachment').empty().append(el); -}; - -App.UI.Wardrobe.dickAccessory = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - // <<= App.Desc.dickAccessory($activeSlave)>> - - const { - // eslint-disable-next-line no-unused-vars - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Dick accessory: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - choice.textContent = (`${slave.dickAccessory} `); - label.appendChild(choice); - - if (slave.dickAccessory !== `none`) { - let choiceOptionsArray = []; - choiceOptionsArray.push({text: `None`, updateSlave: {dickAccessory: `none`}}); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "dickAccessory", false)); - } - el.appendChild(label); - - let optionsArray = []; - - let clothingOption; - App.Data.slaveWear.dickAccessories.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {dickAccessory: item.value}, - FS: item.fs - }; - if (item.value !== "none") { - // skip none in set, we set the link elsewhere. - optionsArray.push(clothingOption); - } - }); - - // Sort - // No sort here since we want small -> large. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - - // Options - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "dickAccessory", true)); - el.appendChild(links); - - return jQuery('#dickAccessory').empty().append(el); -}; - -App.UI.Wardrobe.chastity = function(slave) { - if (slave.fuckdoll !== 0) { - return; - } - - const { - // eslint-disable-next-line no-unused-vars - he, him, his, hers, himself, boy, He, His - } = getPronouns(slave); - - let el = document.createElement('div'); - - let label = document.createElement('div'); - label.append(`Chastity devices: `); - - let choice = document.createElement('span'); - choice.style.fontWeight = "bold"; - if (slave.choosesOwnChastity === 1) { - choice.textContent = `choosing ${his} own chastity `; - } else if (slave.chastityAnus === 1 && slave.chastityPenis === 1 && slave.chastityVagina === 1) { - choice.textContent = `full chastity `; - } else if (slave.chastityPenis === 1 && slave.chastityVagina === 1) { - choice.textContent = `genital chastity `; - } else if (slave.chastityAnus === 1 && slave.chastityPenis === 1) { - choice.textContent = `combined chastity cage `; - } else if (slave.chastityAnus === 1 && slave.chastityVagina === 1) { - choice.textContent = `combined chastity belt `; - } else if (slave.chastityVagina === 1) { - choice.textContent = `chastity belt `; - } else if (slave.chastityPenis === 1) { - choice.textContent = `chastity cage `; - } else if (slave.chastityAnus === 1) { - choice.textContent = `anal chastity `; - } else if (slave.chastityAnus === 0 && slave.chastityPenis === 0 && slave.chastityVagina === 0) { - choice.textContent = `none `; - } else { - choice.textContent = `THERE HAS BEEN AN ERROR `; - } - label.appendChild(choice); - - if (slave.chastityAnus !== 0 || slave.chastityPenis !== 0 || slave.chastityVagina !== 0) { - let choiceOptionsArray = []; - choiceOptionsArray.push({ - text: `None`, - updateSlave: { - choosesOwnChastity: 0, - chastityAnus: 0, - chastityPenis: 0, - chastityVagina: 0 - } - }); - label.appendChild(App.UI.SlaveInteract.generateRows(choiceOptionsArray, slave, "chastity", false)); - } - el.appendChild(label); - - let optionsArray = []; - - let clothingOption; - App.Data.slaveWear.chastityDevices.forEach(item => { - clothingOption = { - text: item.name, - updateSlave: {}, - FS: item.fs - }; - Object.assign(clothingOption.updateSlave, item.updateSlave); - if (item.value !== "none") { - // skip none in set, we set the link elsewhere. - optionsArray.push(clothingOption); - } - }); - - // Sort - // skip sort for this one too. optionsArray = optionsArray.sort((a, b) => (a.text > b.text) ? 1 : -1); - - // Options - let links = document.createElement('div'); - links.className = "choices"; - links.appendChild(App.UI.SlaveInteract.generateRows(optionsArray, slave, "chastity", true)); - el.appendChild(links); - - return jQuery('#chastity').empty().append(el); -}; - -App.UI.Wardrobe.shopping = function(slave) { - return jQuery('#shopping').empty().append( - App.UI.DOM.link( - ` Go shopping for more options`, - () => {}, - [], - "Wardrobe" - ) - ); -}; - -/** - * @param {App.Entity.SlaveState} slave - * @param {string} update - * @returns {Node} - */ -App.UI.Wardrobe.colorOptions = function(slave, update) { - let el = new DocumentFragment(); - let colorChoice = App.UI.DOM.colorInput( - slave[update], - v => { - slave[update] = v; - App.UI.Wardrobe.refreshAll(slave); - } - ); - el.appendChild(colorChoice); - - if (slave[update]) { - el.appendChild( - App.UI.DOM.link( - ` Reset`, - () => { - delete slave[update]; - App.UI.Wardrobe.refreshAll(slave); - }, - ) - ); - } - return el; -}; - -App.UI.Wardrobe.refreshAll = function(slave) { - App.UI.Wardrobe.clothes(slave); - App.UI.Wardrobe.collar(slave); - App.UI.Wardrobe.mask(slave); - App.UI.Wardrobe.mouth(slave); - App.UI.Wardrobe.armAccessory(slave); - App.UI.Wardrobe.shoes(slave); - App.UI.Wardrobe.legAccessory(slave); - App.UI.Wardrobe.bellyAccessory(slave); - App.UI.Wardrobe.buttplug(slave); - App.UI.Wardrobe.buttplugAttachment(slave); - App.UI.Wardrobe.vaginalAccessory(slave); - App.UI.Wardrobe.vaginalAttachment(slave); - App.UI.Wardrobe.dickAccessory(slave); - App.UI.Wardrobe.chastity(slave); - App.Art.refreshSlaveArt(slave, 3, "art-frame"); - return; -}; diff --git a/src/js/economyJS.js b/src/js/economyJS.js index 0c038acd1b15672e49b03a512fd0fb68592c04e4..cadcaf463c68551353c437bc9c2fe3673eb36074 100644 --- a/src/js/economyJS.js +++ b/src/js/economyJS.js @@ -1023,7 +1023,7 @@ globalThis.getSlaveCostArray = function(s) { } break; } - + cost = Math.trunc(cost); retval.push({text: "Living Expenses", value: cost}); cost = 0; diff --git a/src/js/slaveSummaryHelpers.js b/src/js/slaveSummaryHelpers.js index e65fc07f1df1afeb87d8e79804ea2daa1861f682..e3bdd7e521fdff02fbfdfbeb24b7fad3df28852a 100644 --- a/src/js/slaveSummaryHelpers.js +++ b/src/js/slaveSummaryHelpers.js @@ -343,11 +343,11 @@ App.UI.SlaveSummaryImpl = function() { } } else if (slave.daughters > 1) { if (slave.daughters > 10) { - makeSpan(block, bits.daughtersGt10, cssClassName); + makeSpan(block, bits.daughters10, cssClassName); } else if (slave.daughters > 5) { - makeSpan(block, bits.daughtersGt5, cssClassName); + makeSpan(block, bits.daughters5, cssClassName); } else { - makeSpan(block, bits.daughtersGt1, cssClassName); + makeSpan(block, bits.daughters1, cssClassName); } } if (slave.sisters === 1) { diff --git a/src/js/wombJS.js b/src/js/wombJS.js index bc917e9d1a17bf624e99affcde6ecc3383deb176..e17d8f955c8ccdc082baa9695465eba88fae4dfe 100644 --- a/src/js/wombJS.js +++ b/src/js/wombJS.js @@ -337,6 +337,7 @@ globalThis.WombGetVolume = function(actor) { // most legacy code from pregJS.tw ft.volume = ((4 / 3) * (Math.PI) * (phi / 2) * (Math.pow((targetLen / 2), 3))); wombSize += ft.volume; + // wombSize += ft.genetics.geneticQuirks.polyhydramnios === 2 ? ft.volume * 1.5 : ft.volume; // oldVol = ((4 / 3) * (Math.PI) * (phi / 2) * (Math.pow((oldLen / 2), 3))); // for debug @@ -366,6 +367,7 @@ globalThis.WombGetVolume = function(actor) { // most legacy code from pregJS.tw targetData = getCurData(actor, ft.age); wombSize += targetData.size * targetData.rate; + // wombSize += ft.genetics.geneticQuirks.polyhydramnios === 2 ? targetData.size * targetData.rate * 1.5 : targetData.size * targetData.rate; }); if (wombSize < 0) { // catch for strange cases, to avoid messing with outside code. @@ -384,6 +386,7 @@ globalThis.WombGetVolume = function(actor) { // most legacy code from pregJS.tw targetData = getCurData(actor, ft.age); wombSize += targetData.size; + // wombSize += ft.genetics.geneticQuirks.polyhydramnios === 2 ? targetData.size * 1.5 : targetData.size; }); if (wombSize < 0) { // catch for strange cases, to avoid messing with outside code. diff --git a/src/npc/interaction/fSlaveFeed.tw b/src/npc/interaction/fSlaveFeed.tw index adbb312613d5d2ac506089f35edf094cb3a66f04..296eaebd404d9418e7c7cf036699fc73240d8908 100644 --- a/src/npc/interaction/fSlaveFeed.tw +++ b/src/npc/interaction/fSlaveFeed.tw @@ -764,17 +764,17 @@ Next, you see to <<= getSlave($AS).slaveName>>. <<elseif (getSlave($AS).devotion <= 50) || ($milkTap.devotion <= 50)>> <<if canDoVaginal(getSlave($AS))>> - You order <<= getSlave($AS).slaveName>> to lift $his ass so you can penetrate $his <<if getSlave($AS).vagina == 0>>virgin <</if>>pussy <<if $PC.dick == 0>>with a strap-on <</if>> while $he sucks $milkTap.slaveName's cock. $He submissively obeys. With every thrust into the moaning slave, you push milkTap.slaveName's dick deeper down $his throat. + You order <<= getSlave($AS).slaveName>> to lift $his ass so you can penetrate $his <<if getSlave($AS).vagina == 0>>virgin <</if>>pussy <<if $PC.dick == 0>>with a strap-on <</if>> while $he sucks $milkTap.slaveName's cock. $He submissively obeys. With every thrust into the moaning slave, you push $milkTap.slaveName's dick deeper down $his throat. <<set getSlave($AS).counter.vaginal++, $vaginalTotal++>> <<elseif canDoAnal(getSlave($AS))>> - You order <<= getSlave($AS).slaveName>> to lift $his ass so you can penetrate $his <<if getSlave($AS).anus == 0>>virgin <</if>>ass <<if $PC.dick == 0>>with a strap-on <</if>> while $he sucks $milkTap.slaveName's cock. $He submissively obeys. With every thrust into the moaning slave, you push milkTap.slaveName's dick deeper down $his throat. + You order <<= getSlave($AS).slaveName>> to lift $his ass so you can penetrate $his <<if getSlave($AS).anus == 0>>virgin <</if>>ass <<if $PC.dick == 0>>with a strap-on <</if>> while $he sucks $milkTap.slaveName's cock. $He submissively obeys. With every thrust into the moaning slave, you push $milkTap.slaveName's dick deeper down $his throat. <<set getSlave($AS).counter.anal++, $analTotal++>> <<elseif $PC.dick != 0 && getSlave($AS).butt > 4>> - You order <<= getSlave($AS).slaveName>> to lift $his ass so you can rub your dick between $his huge butt cheeks while $he sucks $milkTap.slaveName's cock. $He submissively obeys. With every thrust against the moaning slave, you push milkTap.slaveName's dick deeper down $his throat. + You order <<= getSlave($AS).slaveName>> to lift $his ass so you can rub your dick between $his huge butt cheeks while $he sucks $milkTap.slaveName's cock. $He submissively obeys. With every thrust against the moaning slave, you push $milkTap.slaveName's dick deeper down $his throat. <<elseif $PC.dick != 0 && hasBothLegs(getSlave($AS))>> - You order <<= getSlave($AS).slaveName>> to lift $his ass so you can fuck $his <<if getSlave($AS).weight > 95>>soft <</if>>thighs while $he sucks $milkTap.slaveName's cock. $He submissively obeys. With every thrust against the moaning slave, you push milkTap.slaveName's dick deeper down $his throat. + You order <<= getSlave($AS).slaveName>> to lift $his ass so you can fuck $his <<if getSlave($AS).weight > 95>>soft <</if>>thighs while $he sucks $milkTap.slaveName's cock. $He submissively obeys. With every thrust against the moaning slave, you push $milkTap.slaveName's dick deeper down $his throat. <<else>> - You order <<= getSlave($AS).slaveName>> to position $himself so you can rub your <<if $PC.dick == 0>>clit<<else>>dick<</if>> against $him while $he sucks $milkTap.slaveName's cock, since $he lacks any better way to please you. $He submissively obeys. With every thrust against the moaning slave, you push milkTap.slaveName's dick deeper down $his throat. + You order <<= getSlave($AS).slaveName>> to position $himself so you can rub your <<if $PC.dick == 0>>clit<<else>>dick<</if>> against $him while $he sucks $milkTap.slaveName's cock, since $he lacks any better way to please you. $He submissively obeys. With every thrust against the moaning slave, you push $milkTap.slaveName's dick deeper down $his throat. <</if>> You wrap an arm around <<= getSlave($AS).slaveName>>'s middle so you may feel $his stomach swell with ejaculate and place your other hand to $milkTap.slaveName's balls, knowing just how much _he2 gets backed up. <<if getSlave($AS).inflation == 3>>You cum multiple times as you feel $his belly slowly round with cum, transform into a jiggling mass, and finally grow taut under your molesting fingers<<elseif getSlave($AS).inflation == 2>>You cum several times as you feel $his belly slowly round with cum, finally transforming into a jiggling mass, under your molesting fingers<<else>>You cum as you feel $his belly slowly round with cum under your molesting fingers<</if>>. When you release $him from under your weight, $he drops to the ground panting. Both slaves enjoyed their union, though $milkTap.slaveName even more so after that many orgasms. <<if canDoVaginal(getSlave($AS)) && (getSlave($AS).vagina == 0)>> diff --git a/src/uncategorized/peConcubineInterview.tw b/src/uncategorized/peConcubineInterview.tw index 7fdeee631db78aee17597bb68dc8569e4dd6fedf..8b0d44dd9f275d5b35a9462d7c4cc9852555a139 100644 --- a/src/uncategorized/peConcubineInterview.tw +++ b/src/uncategorized/peConcubineInterview.tw @@ -129,7 +129,7 @@ You receive an official communication from a popular talk show e-hosted in one o <<elseif $activeSlave.bellyImplant >= 1500>> "It'<<s>> fake. Pretty hard to tell though, i<<s>>n't it?" <<elseif $activeSlave.bellyPreg >= 1500>> - Of cour<<s>>e + "Of cour<<s>>e <<if $activeSlave.pregType > 1>> they are!" <<else>> @@ -145,7 +145,7 @@ You receive an official communication from a popular talk show e-hosted in one o <<elseif $activeSlave.bellyImplant > -1>> "It'<<s>> fake. Pretty hard to tell though, i<<s>>n't it?" <<else>> - Of cour<<s>>e + "Of cour<<s>>e <<if $activeSlave.pregType > 1>> they are!" <<else>> diff --git a/src/uncategorized/slaveInteract.tw b/src/uncategorized/slaveInteract.tw index c1d1aa8e48f9632de2edbece14e758016977d2b5..aea8b167fc824af6937dd5e2a7ee5102faea00a7 100644 --- a/src/uncategorized/slaveInteract.tw +++ b/src/uncategorized/slaveInteract.tw @@ -1,353 +1,5 @@ :: Slave Interact [nobr jump-from-safe] <<set $nextButton = "Confirm changes", $nextLink = "Main">> -<<set _SL = $slaves.length, _CL = $canines.length, _HL = $hooved.length, _FL = $felines.length>> -<<run App.Utils.setLocalPronouns(getSlave($AS))>> -<<run Enunciate(getSlave($AS))>> -<style> -.active { - background-color: grey; -} -</style> -<<run App.UI.tabBar.handlePreSelectedTab($tabChoice.SlaveInteract)>> - - -<<if !assignmentVisible(getSlave($AS))>> - <<switch getSlave($AS).assignment>> - <<case "work in the brothel" "be the Madam">> - <<set $nextLink = "Brothel">> - <<case "be confined in the arcade">> - <<set $nextLink = "Arcade">> - <<case "serve in the club" "be the DJ">> - <<set $nextLink = "Club">> - <<case "work in the dairy" "be the Milkmaid">> - <<set $nextLink = "Dairy">> - <<case "work as a farmhand" "be the Farmer">> - <<set $nextLink = "Farmyard">> - <<case "rest in the spa" "be the Attendant">> - <<set $nextLink = "Spa">> - <<case "work as a nanny" "be the Matron">> - <<set $nextLink = "Nursery">> - <<case "learn in the schoolroom" "be the Schoolteacher">> - <<set $nextLink = "Schoolroom">> - <<case "work as a servant" "be the Stewardess">> - <<set $nextLink = "Servants' Quarters">> - <<case "serve in the master suite" "be your Concubine">> - <<set $nextLink = "Master Suite">> - <<case "be confined in the cellblock" "be the Wardeness">> - <<set $nextLink = "Cellblock">> - <<case "get treatment in the clinic" "be the Nurse">> - <<set $nextLink = "Clinic">> - <<case "live with your Head Girl">> - <<set $nextLink = "Head Girl Suite">> - <<case "be your agent" "live with your agent">> - <<set $nextLink = "Neighbor Interact">> - <</switch>> -<</if>> - -<<set $encyclopedia = either("Costs Summary", "Disease in the Free Cities", "Drugs and Their Effects", "From Rebellious to Devoted", "Gender", "Independent Slaves", "Modern Anal", "Nymphomania", "Slave Couture")>> -<<if getSlave($AS).dick > 0>> - <<set $encyclopedia = "Gender">> -<</if>> - -<<includeDOM App.UI.SlaveInteract.navigation(getSlave($AS))>> - -<div class="tab-bar"> - <button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Description'), jQuery('#LSD').empty().append(App.Desc.longSlave(getSlave(V.AS), {noArt: true}))" id="tab Description">Description</button> - <button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Modify')" id="tab Modify">Modify</button> - <button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Work')" id="tab Work">Work</button> - <button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Appearance'), App.UI.Wardrobe.refreshAll(getSlave(V.AS))" id="tab Appearance">Appearance</button> - <button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'PhysicalRegimen')" id="tab PhysicalRegimen">Physical Regimen</button> - <button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Rules')" id="tab Rules">Rules</button> - <button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Financial')" id="tab Financial">Financial</button> - <button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'Customize'), App.UI.SlaveInteract.custom(getSlave(V.AS))" id="tab Customize">Customize</button> - <button class="tab-links" onclick="App.UI.tabBar.openTab(event, 'family-tab'), renderFamilyTree(V.slaves, V.AS)" id="tab family-tab">Family</button> -</div> - -<div id="art-frame"> - <<if $seeImages == 1>> - <<if $imageChoice == 1>> - <div class="imageRef lrgVector"><div class="mask"> </div><<= SlaveArt(getSlave($AS), 3, 0)>></div> - <<else>> - <div class="imageRef lrgRender"><div class="mask"> </div><<= SlaveArt(getSlave($AS), 3, 0)>></div> - <</if>> - <</if>> -</div> - -<div id="Description" class="tab-content"> - <div class="content"> - <<if $seeDetails == 1>> - <div style="font-style:italic"> - <<link "Description Options">> - <<replace #hideOptionPages>> - <<link "(hide)">> - <<replace #hideOptionPages>> - <</replace>> - <<replace #optionPages>> - /* Hide */ - <</replace>> - <</link>> - <</replace>> - <<replace #optionPages>> - <<include "Description Options">> - <</replace>> - <</link>> - <span id="hideOptionPages"></span> - <p id="optionPages"></p> - </div> - <span id="LSD"></span> - <<else>> - <div style="font-style:italic"> - [[Show descriptions|Slave Interact][$seeDetails = 1]] - </div> - <</if>> - </div> -</div> - -<div id="Modify" class="tab-content"> - <div class="content"> - <p id="modifySection"></p> - <script> - jQuery('#modifySection').empty().append(App.UI.SlaveInteract.modify(getSlave(V.AS))) - </script> - </div> -</div> - - -<div id="Work" class="tab-content"> - <div class="content"> - <p id="work"></p> - <script> - App.UI.SlaveInteract.work(getSlave(V.AS)) - </script> - </div> -</div> - -<div id="Appearance" class="tab-content"> - <div class="content"> - <p> - <span id="clothes"></span> - /*<script>App.UI.Wardrobe.clothes(getSlave(V.AS))</script>*/ - - <<if getSlave($AS).fuckdoll == 0>> - <span id="collar"></span> - /*<script>App.UI.Wardrobe.collar(getSlave(V.AS))</script>*/ - - <span id="faceAccessory"></span> - - <span id="mouthAccessory"></span> - - <span id="armAccessory"></span> - /*<script>App.UI.Wardrobe.armAccessory(getSlave(V.AS))</script>*/ - - <<if hasAnyLegs(getSlave($AS))>> - <span id="shoes"></span> - /*<script>App.UI.Wardrobe.shoes(getSlave(V.AS))</script>*/ - - <span id="legAccessory"></span> - /*<script>App.UI.Wardrobe.legAccessory(getSlave(V.AS))</script>*/ - <</if>> - - <span id="bellyAccessory"></span> - /*<script>App.UI.Wardrobe.bellyAccessory(getSlave(V.AS))</script>*/ - - <span id="buttplug"></span> - /*<script>App.UI.Wardrobe.buttplug(getSlave(V.AS))</script>*/ - - <<if isItemAccessible.entry("tail", "buttplugAttachment") && getSlave($AS).buttplug != "none">> - <span id="buttplugAttachment"></span> - /*<script>App.UI.Wardrobe.buttplugAttachment(getSlave(V.AS))</script>*/ - <</if>> - - <<if getSlave($AS).vagina > -1>> - <span id="vaginalAccessory"></span> - /*<script>App.UI.Wardrobe.vaginalAccessory(getSlave(V.AS))</script>*/ - <span id="vaginalAttachment"></span> - /*<script>App.UI.Wardrobe.vaginalAttachment(getSlave(V.AS))</script>*/ - <</if>> - - <<if getSlave($AS).dick > 0>> - <span id="dickAccessory"></span> - /*<script>App.UI.Wardrobe.dickAccessory(getSlave(V.AS))</script>*/ - <</if>> - - <span id="chastity"></span> - /*<script>App.UI.Wardrobe.chastity(getSlave(V.AS))</script>*/ - - <h3>Shopping</h3> - <span id="shopping"></span> - <script>App.UI.Wardrobe.shopping(getSlave(V.AS))</script> - - <</if>> /* CLOSES FUCKDOLL CHECK */ - </p> - </div> -</div> - -<div id="PhysicalRegimen" class="tab-content"> - <div class="content"> - <p> - <span id="drugs"></span> - <script>App.UI.SlaveInteract.drugs(getSlave(V.AS))</script> - - <span id="curatives"></span> - <script>App.UI.SlaveInteract.curatives(getSlave(V.AS))</script> - - <span id="aphrodisiacs"></span> - <script>App.UI.SlaveInteract.aphrodisiacs(getSlave(V.AS))</script> - - <span id="fertility-block"></span> - <script>App.UI.SlaveInteract.fertility(getSlave(V.AS))</script> - - <span id="incubator"></span> - <script>App.UI.SlaveInteract.incubator(getSlave(V.AS))</script> - - <span id="nursery"></span> - <script>App.UI.SlaveInteract.nursery(getSlave(V.AS))</script> - - <<if $propOutcome == 1 && $arcologies[0].FSRestart != "unset">> - <<if getSlave($AS).breedingMark == 0 && getSlave($AS).fuckdoll == 0 && getSlave($AS).eggType == "human" && isFertile(getSlave($AS)) && getSlave($AS).preg == 0>> - <br> - [[Breeder Eligibility Exam|BreedingTest]] - <</if>> - <</if>> - - <span id="bloating"></span> - <script>App.UI.SlaveInteract.bloating(getSlave(V.AS))</script> - - <span id="hormones"></span> - <script>App.UI.SlaveInteract.hormones(getSlave(V.AS))</script> - - <span id="diet"></span> - <script>App.UI.SlaveInteract.diet(getSlave(V.AS))</script> - - <span id="diet-base"></span> - <script>App.UI.SlaveInteract.dietBase(getSlave(V.AS))</script> - - <span id="snacks"></span> - <script>App.UI.SlaveInteract.snacks(getSlave(V.AS))</script> - </p> - </div> -</div> - -<div id="Rules" class="tab-content"> - <div class="content"> - <span id="rules"></span> - <script>App.UI.SlaveInteract.rules(getSlave(V.AS))</script> - </div> -</div> - -<div id="Financial" class="tab-content"> - <div class="content"> - - <<if $studio == 1>> - <h3>Media</h3> - <<if getSlave($AS).porn.prestige == 3>> - //$He is so prestigious in the realm of <<= getSlave($AS).porn.fameType>> porn that $his fame is self-sustaining.// - <<elseif getSlave($AS).porn.feed == 0>> - The media hub is not releasing highlights of $his sex life. [[Release|Slave Interact][getSlave($AS).porn.feed = 1]] - <<else>> - The media hub is releasing highlights of $his sex life <<if getSlave($AS).porn.spending < 500>>to those who can find it<<elseif getSlave($AS).porn.spending < 2500>>on several websites<<elseif getSlave($AS).porn.spending > 5000>>through your old distributor<<else>>on many websites<</if>>. - <<if getSlave($AS).porn.spending == 0>> - [[Halt|Slave Interact][getSlave($AS).porn.feed = 0, getSlave($AS).porn.focus = "none"]] | - [[Publicize|Slave Interact][getSlave($AS).porn.spending += 1000]] - //Will cost <<print cashFormat(1000)>> weekly.// - <<else>> - <<textbox "_newPornSpending" $slaves[$slaveIndices[$AS]].porn.spending>> weekly is spent to publicize them. [[Save changes|Slave Interact][getSlave($AS).porn.spending = Number(_newPornSpending) || 0]] | - [[Halt|Slave Interact][getSlave($AS).porn.feed = 0, getSlave($AS).porn.spending = 0, getSlave($AS).porn.focus = "none", $PCSlutContacts = 1]] | - <<if getSlave($AS).porn.spending < 5000>> - [[Increase|Slave Interact][getSlave($AS).porn.spending += 1000]] | - <</if>> - [[Decrease|Slave Interact][getSlave($AS).porn.spending -= 1000]] - <<if getSlave($AS).porn.spending > 5000>><<set _warn = 1>><</if>> - <<set getSlave($AS).porn.spending = Number(getSlave($AS).porn.spending) || 0>> - <<set getSlave($AS).porn.spending = Math.clamp(Math.ceil(getSlave($AS).porn.spending/1000)*1000, 0, 5000)>> - <<if _warn>><br>//Spending more than <<print cashFormat(5000)>> weekly will have no effect.//<</if>> - <<if $PC.career == "escort">> - <br> - You retain some contacts from your past life in the industry that may be willing to cut you some discounts should you return to it. - <<if $PCSlutContacts != 2>> - You are not baring your body for all to see. - [[Star in porn for a discount|Slave Interact][$PCSlutContacts = 2]] - <<else>> - You are starring in hardcore porn once more. - [[Stop doing porn for a discount|Slave Interact][$PCSlutContacts = 1]] - <</if>> - <</if>> - <</if>> - - <<if $studioFeed == 1>> - <br> - <<if getSlave($AS).porn.viewerCount < 100>> - $He lacks the fame in porn needed to discern what $his feed is getting tagged as. - <<else>> - <<if getSlave($AS).porn.prestige > 0>> - $He is known for <<= getSlave($AS).porn.fameType>> porn<<if getSlave($AS).porn.prestige > 1>> and viewers have grown to expect it from $him<</if>>. - <</if>> - <<if getSlave($AS).porn.focus == "none">> - You are allowing $his viewers to guide the direction of $his content. - <<else>> - You are focusing attention on the <<= getSlave($AS).porn.focus>> aspect of $his content. - <</if>> - <<includeDOM App.Porn.genreChoiceLinks("Slave Interact", getSlave($AS))>> - <</if>> - <</if>> - <</if>> - <</if>> - - <h3>Financial</h3> - <p> - <<includeDOM slaveExpenses(getSlave(V.AS))>> - </p> - - <p> - <<if ($slaveCostFactor > 1)>> - <span class="yellow">The slave market is bullish; the price of slaves is high.</span> - <<elseif ($slaveCostFactor < 1)>> - <span class="yellow">The slave market is bearish; the price of slaves is low.</span> - <</if>> - - <<if (_SL > 1)>> - <<if getSlave($AS).origin == "You bought $him from a body dump, completely broken." && ($week-getSlave($AS).weekAcquired <= 8)>> - //A discarded slave must be kept for at least two months to ensure health before being sold.// | - <<elseif getSlave($AS).accent > 3>> - //$His lack of language and basic life skills is a red sign to most slave appraisers. $He must not act like a child to be sold without raising suspicion.// | - <<else>> - <<link "Sell $him" "Sell Slave">><<run cashX(-500, "personalBusiness", getSlave($AS))>><</link>> //Listing $him for sale will cost <<print cashFormat(500)>>// | - <<if ($seeAge != 0) && (getSlave($AS).indenture < 1)>> - <<link "Retire $him" "SE retirement">><<set $retiree = getSlave($AS).ID, $retired = 1>><</link>> | - <</if>> - <</if>> - <<link "Discard $him" "Discard Confirm">><</link>> - <<if $seeExtreme == 1 && $arcologies[0].FSPaternalist == "unset">> - | <<link "Threaten $his life" "KillSlave">><</link>> - <</if>> - <<else>> - //You cannot sell or discard your last slave.// - <</if>> - - | <<link "Export this slave" "Export Slave">><</link>> - <<if $cheatMode>> - | <<link "Import a slave" "Import Slave">><</link>> - <</if>> - </p> - </div> -</div> - -<div id="Customize" class="tab-content"> - <div class="content"> - <span id="custom"></span> - <script>App.UI.SlaveInteract.custom(getSlave(V.AS))</script> - - /*<<include "Add custom descriptors">>*/ - </div> -</div> - -<div id="family-tab" class="tab-content"> - <div class="content"> - <p id="family"> - <div id="family-tree"></div> - <span id="family-tree-link"></span> - </p> - </div> -</div> +<<includeDOM App.UI.SlaveInteract.mainPage(getSlave(V.AS))>> diff --git a/src/uncategorized/subordinateTargeting.tw b/src/uncategorized/subordinateTargeting.tw index 047be1879fffb4333043042016dab404d771a19f..edbf8d558fbe58d75c9c7ea0ba59ac106e50fcdf 100644 --- a/src/uncategorized/subordinateTargeting.tw +++ b/src/uncategorized/subordinateTargeting.tw @@ -1,6 +1,6 @@ :: Subordinate Targeting [nobr] -<<set $nextButton = "Back", $nextLink = "AS Dump">> +<<set $nextButton = "Back", $nextLink = "Slave Interact">> <<run App.Utils.setLocalPronouns(getSlave($AS))>>