diff --git a/css/interaction/prosthetics.css b/css/interaction/prosthetics.css index 0b6a4b4b2dec88df4948f78efe87e67b5327fd0b..810787f6f5e77abead785bf4ec4dfa854ff181e9 100644 --- a/css/interaction/prosthetics.css +++ b/css/interaction/prosthetics.css @@ -1,11 +1,11 @@ div.limb-selector { display: grid; - grid-template-columns: 200px 100px 100px 100px 100px; + grid-template-columns: 200px 100px 100px 100px 100px 100px; } div.limb-selector div.full { grid-column-start: 1; - grid-column-end: 6; + grid-column-end: 7; text-align: center; } diff --git a/js/random.js b/js/random.js index 8ab8e1d61ea85182398316e6f9927fec8840c5e2..10569f08e4029693bfd48c510c68be8d573cabc7 100644 --- a/js/random.js +++ b/js/random.js @@ -1,8 +1,8 @@ /** * generate two independent Gaussian numbers using Box-Muller transform. * mean and deviation specify the desired mean and standard deviation. - * @param {number} [mean] - * @param {number} [deviation] + * @param {number} [mean=0] + * @param {number} [deviation=1] * @returns {number[]} */ function gaussianPair(mean = 0, deviation = 1) { @@ -47,10 +47,10 @@ App.Utils.Math.limitedSkewedGaussian = function(max, min, skew) { * Generate a random integer with a normal distribution between min and max (both inclusive). * Default parameters result in truncating the standard normal distribution between -3 and +3. * Not specifying min/max results in rerolling val approximately 0.3% of the time. - * @param {number} [mean] - * @param {number} [deviation] - * @param {number} [min] - * @param {number} [max] + * @param {number} [mean=0] + * @param {number} [deviation=1] + * @param {number} [min=mean-3*deviation] + * @param {number} [max=mean+3*deviation] * @returns {number} */ function normalRandInt(mean = 0, deviation = 1, min = mean - 3 * deviation, max = mean + 3 * deviation) { @@ -66,7 +66,7 @@ function normalRandInt(mean = 0, deviation = 1, min = mean - 3 * deviation, max * If count is defined, chooses that many random numbers between min and max and returns the average. This is an approximation of a normal distribution. * @param {number} min * @param {number} max - * @param {number} [count] + * @param {number} [count=1] * @returns {number} */ function jsRandom(min, max, count = 1) { diff --git a/src/events/RESS/review/birthdaySex.js b/src/events/RESS/review/birthdaySex.js index 73ffa808b68f8ff1243c05ba6bbc911cb3a7ce0d..02e8e3f521264c1021b09df40650f89495647c18 100644 --- a/src/events/RESS/review/birthdaySex.js +++ b/src/events/RESS/review/birthdaySex.js @@ -55,7 +55,9 @@ App.Events.RESSBirthdaySex = class RESSBirthdaySex extends App.Events.BaseEvent ); seX(eventSlave, vaginal ? "vaginal" : "anal", V.PC); - knockMeUp(eventSlave, 1, vaginal ? 0 : 1, -1); + if (canImpreg(eventSlave, V.PC)) { + knockMeUp(eventSlave, 1, vaginal ? 0 : 1, -1); + } eventSlave.devotion += 10; App.Events.addParagraph(frag, r); @@ -80,7 +82,9 @@ App.Events.RESSBirthdaySex = class RESSBirthdaySex extends App.Events.BaseEvent } seX(eventSlave, vaginal ? "vaginal" : "anal", V.PC); - knockMeUp(eventSlave, 1, vaginal ? 0 : 1, -1); + if (canImpreg(eventSlave, V.PC)) { + knockMeUp(eventSlave, 1, vaginal ? 0 : 1, -1); + } eventSlave.trust -= 10; if (isVirgin) { eventSlave.devotion -= 10; diff --git a/src/npc/descriptions/limbs.js b/src/npc/descriptions/limbs.js index e35ec86d77acd0f2d91d6babdfd350a15218edef..4eb79fa4095e84bb653d914b2ec8b0b624401b8a 100644 --- a/src/npc/descriptions/limbs.js +++ b/src/npc/descriptions/limbs.js @@ -59,6 +59,9 @@ App.Medicine.Limbs.selector = function(slave, oldLimbs) { App.UI.DOM.appendNewElement("div", limbSelector, "Right Arm"); App.UI.DOM.appendNewElement("div", limbSelector, "Left Leg"); App.UI.DOM.appendNewElement("div", limbSelector, "Right Leg"); + App.UI.DOM.appendNewElement("div", limbSelector, "All"); + + const radiosAll = []; limbSelector.append(row("None", 0)); App.Data.prostheticLimbs.forEach((limb, key) => { @@ -67,7 +70,8 @@ App.Medicine.Limbs.selector = function(slave, oldLimbs) { limbSelector.append(row(capFirstChar(limb.short), key)); } else { App.UI.DOM.appendNewElement("div", limbSelector, - `You need to upgrade ${his} prosthetic interface to attach ${limb.short} limbs.`, ["full", "detail"]); + `You need to upgrade ${his} prosthetic interface to attach ${limb.short} limbs.`, ["full", + "detail"]); } } }); @@ -91,30 +95,6 @@ App.Medicine.Limbs.selector = function(slave, oldLimbs) { return [getLeftArmID(slave), getRightArmID(slave), getLeftLegID(slave), getRightLegID(slave)]; } - /** - * @param {number} limb - * @param {number} id - * @returns {HTMLDivElement} - */ - function radio(limb, id) { - const div = document.createElement("div"); - - if (newState[limb] !== 1) { - const radio = document.createElement("input"); - radio.type = "radio"; - radio.name = "limb" + limb; - if (newState[limb] === id) { - radio.checked = true; - } - radio.onclick = () => { - newState[limb] = id; - }; - div.append(radio); - } - - return div; - } - /** * @param {string} title * @param {number} id @@ -125,10 +105,47 @@ App.Medicine.Limbs.selector = function(slave, oldLimbs) { App.UI.DOM.appendNewElement("div", f, title); + const radios = []; for (let i = 0; i < newState.length; i++) { - f.append(radio(i, id)); + const div = document.createElement("div"); + + if (newState[i] !== 1) { + const radio = document.createElement("input"); + radios.push(radio); + radio.type = "radio"; + radio.name = "limb" + i; + if (newState[i] === id) { + radio.checked = true; + } + radio.onclick = () => { + newState[i] = id; + radiosAll.forEach(r => r.checked = false); + }; + div.append(radio); + } + + f.append(div); } + const div = document.createElement("div"); + + const radio = document.createElement("input"); + radiosAll.push(radio); + radio.type = "radio"; + radio.name = "limb_all"; + radio.checked = newState.reduce((acc, cur) => acc && (cur === 1 || cur === id), true); + radio.onclick = () => { + for (let i = 0; i < newState.length; i++) { + if (newState[i] !== 1) { + newState[i] = id; + } + radios.forEach(r => r.checked = true); + } + }; + div.append(radio); + + f.append(div); + return f; } diff --git a/src/npc/generate/generateMarketSlave.js b/src/npc/generate/generateMarketSlave.js index 349d9b2efc64fc89214a38ffa2194dcb3113e8f5..22843621dcdc6816f9a3d9b8d657607f998f8f56 100644 --- a/src/npc/generate/generateMarketSlave.js +++ b/src/npc/generate/generateMarketSlave.js @@ -465,7 +465,7 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1 } case "neighbor": { const neighborID = (typeof V.arcologies[numArcology] === 'object') ? numArcology : 1; - const neighbor = V.arcologies[neighborID]; + const neighbor = /** @type {FC.ArcologyState} */V.arcologies[neighborID]; const opinion = Math.clamp(Math.trunc(App.Neighbor.opinion(V.arcologies[0], neighbor) / 20), -10, 10); /** @@ -495,7 +495,18 @@ globalThis.generateMarketSlave = function(market = "kidnappers", numArcology = 1 slave.origin += "."; slave.devotion = -20 + Math.trunc(neighbor.prosperity / 10) + jsRandom(0, 10); slave.trust = -20 + Math.trunc(neighbor.prosperity / 10) + jsRandom(0, 10); - setHealth(slave, -50 + Math.trunc(neighbor.prosperity / 25) + jsRandom(0, 5), Math.max(15 - neighbor.prosperity / 20 + normalRandInt(0, 2), 0), Math.max(15 - neighbor.prosperity / 20 + normalRandInt(0, 2), 0), undefined, Math.max(jsRandom(10, 40) - neighbor.prosperity / 15, 10)); + let healthTarget = 0; + if (neighbor.FSPaternalist !== "unset") { + healthTarget = 20; + } else if (neighbor.FSDegradationist !== "unset") { + healthTarget = -20; + } + healthTarget += Math.trunc((neighbor.prosperity - 100) / 10) + jsRandom(0, 10); + setHealth(slave, healthTarget, // min: -50, max: -33 + Math.max(15 - neighbor.prosperity / 20 + normalRandInt(0, 2), 0), // min: 0, max: 21 + Math.max(15 - neighbor.prosperity / 20 + normalRandInt(0, 2), 0), // min: 0, max: 21 + undefined, + Math.max(jsRandom(10, 40) - neighbor.prosperity / 15, 10)); // min: 10, max: 40 if (jsRandom(1, 100) < neighbor.prosperity / 10 + 50) { slave.health.illness = 0; } diff --git a/src/npc/surgery/cloningWorkaround.js b/src/npc/surgery/cloningWorkaround.js index 04780cf1848a8215186d7b6d1a3cc1505cfb65f7..2231b3cbe93e80fa0b972f04b055713fe576040c 100644 --- a/src/npc/surgery/cloningWorkaround.js +++ b/src/npc/surgery/cloningWorkaround.js @@ -35,11 +35,12 @@ App.UI.cloningWorkaround = function() { } )); for (const slave of V.slaves) { + const div = App.UI.DOM.appendNewElement("div", node, App.UI.DOM.referenceSlaveWithPreview(slave, SlaveFullName(slave))); if (donatrix !== "undecided" && donatrix.ID === slave.ID) { - App.UI.DOM.appendNewElement("div", node, SlaveFullName(slave), "note"); + div.classList.add("note"); } else { - App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link( - SlaveFullName(slave), + div.append(" ", App.UI.DOM.link( + "Select", () => { V.donatrix = slave; App.UI.reload(); @@ -52,18 +53,20 @@ App.UI.cloningWorkaround = function() { for (const slave of V.slaves) { if (canBeReceptrix(slave)) { - const name = SlaveFullName(slave); + const div = App.UI.DOM.appendNewElement("div", node, App.UI.DOM.referenceSlaveWithPreview(slave, SlaveFullName(slave))); if (receptrix !== "undecided" && receptrix.ID === slave.ID) { - App.UI.DOM.appendNewElement("div", node, name, "note"); + div.classList.add("note"); } else { - App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link( - name, + div.append(" ", App.UI.DOM.link( + "Select", () => { V.receptrix = slave; App.UI.reload(); - }, [], "", - (slave.pregType >= 4) ? `Using a slave carrying multiples is inadvisable` : `` + } )); + if (slave.pregType >= 4) { + App.UI.DOM.appendNewElement("span", div, `Using a slave carrying multiples is inadvisable`, ["note"]); + } } eligibility = 1; } diff --git a/src/npc/surgery/ovaTransplantWorkaround.js b/src/npc/surgery/ovaTransplantWorkaround.js index 26d1d7f063f621f8585b9b40a8980e98cc1ea1b4..3bca0240b073fc030132ced491761903714c0db7 100644 --- a/src/npc/surgery/ovaTransplantWorkaround.js +++ b/src/npc/surgery/ovaTransplantWorkaround.js @@ -8,16 +8,23 @@ App.UI.ovaTransplantWorkaround = function() { App.UI.DOM.appendNewElement("h2", node, "Select a slave to serve as the host"); for (const slave of V.slaves) { - if ((V.donatrix.ID !== slave.ID && slave.ovaries > 0 || slave.mpreg > 0) && isSlaveAvailable(slave) && slave.preg >= 0 && slave.preg < slave.pregData.normalBirth / 10 && slave.pregWeek >= 0 && slave.pubertyXX === 1 && slave.pregType < 12 && slave.bellyImplant === -1 && slave.broodmother === 0 && slave.inflation <= 2 && slave.physicalAge < 70) { - App.UI.DOM.appendNewElement("div", node, App.UI.DOM.link( - SlaveFullName(slave), + if ((V.donatrix.ID !== slave.ID && slave.ovaries > 0 || slave.mpreg > 0) && + isSlaveAvailable(slave) && slave.preg >= 0 && slave.preg < slave.pregData.normalBirth / 10 && + slave.pregWeek >= 0 && slave.pubertyXX === 1 && slave.pregType < 12 && slave.bellyImplant === -1 && + slave.broodmother === 0 && slave.inflation <= 2 && slave.physicalAge < 70 + ) { + const div = App.UI.DOM.appendNewElement("div", node, App.UI.DOM.referenceSlaveWithPreview(slave, SlaveFullName(slave))); + div.append(" ", App.UI.DOM.passageLink( + "Select", "Surrogacy", () => { V.receptrix = slave; cashX(forceNeg(V.surgeryCost * 2), "slaveSurgery"); V.surgeryType = "transplant"; - }, [], "Surrogacy", - (slave.pregType >= 4) ? `Using a slave carrying multiples is inadvisable` : `` + } )); + if (slave.pregType >= 4) { + App.UI.DOM.appendNewElement("span", div, `Using a slave carrying multiples is inadvisable`, ["note"]); + } eligibility = 1; } }