diff --git a/src/002-config/fc-version.js b/src/002-config/fc-version.js index 95c56fcc0df620841bf4063ade116cdcc98f4d10..c708b0e83f7310be88e2450530cc6a2eca0b2123 100644 --- a/src/002-config/fc-version.js +++ b/src/002-config/fc-version.js @@ -2,5 +2,5 @@ App.Version = { base: "0.10.7.1", // The vanilla version the mod is based off of, this should never be changed. pmod: "3.5.4", commitHash: null, - release: 1076 + release: 1077 }; diff --git a/src/cheats/PCCheatMenuCheatDatatypeCleanup.tw b/src/cheats/PCCheatMenuCheatDatatypeCleanup.tw index 5f78ca87af81bba2e840704827e8dc9ee8fc1027..005c0e3a00652c292e405f25d89be27537382be0 100644 --- a/src/cheats/PCCheatMenuCheatDatatypeCleanup.tw +++ b/src/cheats/PCCheatMenuCheatDatatypeCleanup.tw @@ -71,6 +71,7 @@ You perform the dark rituals, pray to the dark gods, and sell your soul for the power to reshape your body and life at will. What a cheater! <<set $PC = clone($tempSlave)>> +<<run ibc.recalculate_id(-1)>> <<run PCDatatypeCleanup()>> <<set $upgradeMultiplierArcology = upgradeMultiplier('engineering')>> <<set $upgradeMultiplierMedicine = upgradeMultiplier('medicine')>> diff --git a/src/cheats/mod_EditChildCheatDatatypeCleanupNew.tw b/src/cheats/mod_EditChildCheatDatatypeCleanupNew.tw index 9ac0b8c1f7773a1ede8b558f13872d319296675a..283f230b8ca21b397bc7728936812e07caf97b93 100644 --- a/src/cheats/mod_EditChildCheatDatatypeCleanupNew.tw +++ b/src/cheats/mod_EditChildCheatDatatypeCleanupNew.tw @@ -327,3 +327,4 @@ You perform the dark rituals, pray to the dark gods, and sell your soul for the <<if def _escn>> <<set $cribs[_escn] = clone($activeSlave)>> <</if>> +<<run ibc.recalculate_coeff_id($activeSlave.ID)>> diff --git a/src/cheats/mod_EditSlaveCheat.tw b/src/cheats/mod_EditSlaveCheat.tw index 3ece6b32dae265ec7fbb3d01c04316340cab7bc0..0b39e745e74003940fcdae98070a18c0ff4e0a59 100644 --- a/src/cheats/mod_EditSlaveCheat.tw +++ b/src/cheats/mod_EditSlaveCheat.tw @@ -2,7 +2,6 @@ <<set $nextButton = "Continue">> <<set $nextLink = "MOD_Edit Slave Cheat Datatype Cleanup">> -<<set $oldName = $activeSlave.slaveName, $oldSurname = $activeSlave.slaveSurname>> <<set $tempSlave = clone($activeSlave)>> <<setLocalPronouns $tempSlave>> diff --git a/src/cheats/mod_EditSlaveCheatDatatypeCleanup.tw b/src/cheats/mod_EditSlaveCheatDatatypeCleanup.tw index 259d748bfbaa74c177b5e2c72ed4ca88aa5e50b6..015bbf3689f12cfe7aa5def560e7729c99d46c73 100644 --- a/src/cheats/mod_EditSlaveCheatDatatypeCleanup.tw +++ b/src/cheats/mod_EditSlaveCheatDatatypeCleanup.tw @@ -71,3 +71,4 @@ You perform the dark rituals, pray to the dark gods, and sell your soul for the <<if def _escdc>> <<set $slaves[_escdc] = $activeSlave>> <</if>> +<<run ibc.recalculate_coeff_id($activeSlave.ID)>> diff --git a/src/cheats/mod_EditSlaveCheatDatatypeCleanupNew.tw b/src/cheats/mod_EditSlaveCheatDatatypeCleanupNew.tw index 3dd6e0e84971868e55ea3238e7bfc1ec30e46916..043d863a43e53d02bd68d7404ded8b01fa599212 100644 --- a/src/cheats/mod_EditSlaveCheatDatatypeCleanupNew.tw +++ b/src/cheats/mod_EditSlaveCheatDatatypeCleanupNew.tw @@ -230,3 +230,4 @@ You perform the dark rituals, pray to the dark gods, and sell your soul for the <<if def _escn>> <<set $slaves[_escn] = clone($activeSlave)>> <</if>> +<<run ibc.recalculate_coeff_id($activeSlave.ID)>> diff --git a/src/data/backwardsCompatibility/backwardsCompatibility.js b/src/data/backwardsCompatibility/backwardsCompatibility.js index 1f363899aad581df334ee92a38945035cb410b59..e595875d8c85665ffc837754889a2a6187195cef 100644 --- a/src/data/backwardsCompatibility/backwardsCompatibility.js +++ b/src/data/backwardsCompatibility/backwardsCompatibility.js @@ -1258,6 +1258,7 @@ App.Update.slaveRecords = function(node) { child.spermY = normalRandInt(50, 5); } App.Facilities.Nursery.InfantDatatypeCleanup(child); + child.inbreedingCoeff = ibc.coeff(child); } else { App.Update.Slave(child); App.Entity.Utils.SlaveDataSchemeCleanup(child, true); @@ -1280,6 +1281,17 @@ App.Update.slaveRecords = function(node) { }; App.Update.genePoolRecords = function(node) { + Object.values(V.missingTable).forEach(s => { + if (!jsDef(s.mother)) + s.mother = 0; + if (!jsDef(s.father)) + s.father = 0; + if (!jsDef(s.inbreedingCoeff)) + s.inbreedingCoeff = 0; + }); + + let ib_coeff = ibc.coeff_slaves(V.genePool); + V.genePool.forEach(g => {g.inbreedingCoeff = ib_coeff[g.ID]}); V.slaveIndices = slaves2indices(); // we're going to need to compare to active slaves, if they exist for (let bci = 0; bci < V.genePool.length; bci++) { diff --git a/src/data/backwardsCompatibility/updateSlaveObject.js b/src/data/backwardsCompatibility/updateSlaveObject.js index aecfcbe7fa6955dd6bcd935feeccb640287555e0..af4d2a0f912cce2c041bb8905211d3c6ec82020f 100644 --- a/src/data/backwardsCompatibility/updateSlaveObject.js +++ b/src/data/backwardsCompatibility/updateSlaveObject.js @@ -1026,4 +1026,14 @@ App.Update.Slave = function(slave, genepool = false) { } } } + + if (!jsDef(slave.inbreedingCoeff)) { + slave.inbreedingCoeff = ibc.coeff(slave); + slave.womb.forEach(f => { + // Use null as the ID, since fetuses are missing it + f.genetics.inbreedingCoeff = ibc.coeff( + {ID: null, mother: f.genetics.mother, father: f.genetics.father} + ); + }); + } }; diff --git a/src/data/newGamePlus.js b/src/data/newGamePlus.js index f5a569ea612662e0a39f428dcde935087e67530a..bc771401033f017391fc9c69d2c3dc11f1b9476f 100644 --- a/src/data/newGamePlus.js +++ b/src/data/newGamePlus.js @@ -69,18 +69,77 @@ App.Data.NewGamePlus = (function() { const ngUpdateMissingTable = function(missingTable) { const newTable = {}; + let needed = []; (V.slaves || []) .forEach(s => ([s.pregSource + NGPOffset, s.mother + NGPOffset, s.father + NGPOffset] .filter(i => (i in missingTable)) .forEach(i => { - newTable[i - NGPOffset] = missingTable[i]; - newTable[i - NGPOffset].ID -= NGPOffset; + if (needed.indexOf(i) === -1) + needed.push(i); }))); + (V.slaves || []).forEach(s => (s.womb + .forEach(f => ([f.fatherID, f.genetics.father, f.genetics.mother] + .filter(i => (i in missingTable)) + .forEach(i => { + if (needed.indexOf(i) === -1) + needed.push(i); + }))))); + + while (needed.length > 0) { + let i = needed.shift(); + let s = missingTable[i]; + newTable[i - NGPOffset] = s; + s.ID -= NGPOffset; + if (s.mother in missingTable) { + s.mother -= NGPOffset; + if (!(s.mother in newTable) && needed.indexOf(s.mother + NGPOffset) === -1) + needed.push(s.mother + NGPOffset); + } + if (s.father in missingTable) { + s.father -= NGPOffset; + if (!(s.father in newTable) && needed.indexOf(s.father + NGPOffset) === -1) + needed.push(s.father + NGPOffset); + } + } return newTable; }; + if (typeof V.missingTable !== undefined) { + let oldMissingParentID = Math.min(-10000, ...Object.keys(V.missingTable)) - 1; + V.slaves.filter(s => (s.assignment !== Job.IMPORTED)).forEach(s => { + V.missingTable[oldMissingParentID] = { + slaveName: s.slaveName, + slaveSurname: s.slaveSurname, + fullName: SlaveFullName(s), + dick: s.dick, + vagina: s.vagina, + ID: oldMissingParentID, + mother: s.mother, + father: s.father, + inbreedingCoeff: s.inbreedingCoeff + }; + Object.values(V.missingTable).forEach(so => { + if (so.mother === s.ID) + so.mother = oldMissingParentID; + if (so.father === s.ID) + so.father = oldMissingParentID; + }); + V.slaves.concat([V.PC]).forEach(so => { + if (so.mother === s.ID) + so.mother = oldMissingParentID; + if (so.father === s.ID) + so.father = oldMissingParentID; + if (so.assignment === Job.IMPORTED || so.ID === -1) { + WombChangeID(so, s.ID, oldMissingParentID); + WombChangeGeneID(so, s.ID, oldMissingParentID); + } + }); + oldMissingParentID--; + }); + } + V.slaves.deleteWith((s) => s.assignment !== Job.IMPORTED); for (let slave of V.slaves) { @@ -117,11 +176,7 @@ App.Data.NewGamePlus = (function() { slave.relationshipTarget = slaveOrZero(slave.relationshipTarget); } V.genePool = ngUpdateGenePool(V.genePool); - if (typeof V.missingTable === undefined || V.showMissingSlaves === false) { - V.missingTable = {}; - } else { - V.missingTable = ngUpdateMissingTable(V.missingTable); - } + V.missingTable = ngUpdateMissingTable(V.missingTable); let validRelationship = (s) => (s.relationshipTarget !== 0 && getSlave(s.relationshipTarget).relationshipTarget === s.ID); for (let slave of V.slaves) { if ((slave.relationship < 0 && V.freshPC === 1) || (slave.relationship > 0 && !validRelationship(slave))) { diff --git a/src/descriptions/familySummaries.js b/src/descriptions/familySummaries.js index 5db6e4def0c6fbc5cd77dd2e2f9e8758cd4d9c45..f962d0a076090a3469a5eaaa5bc7c7ab0ccff19d 100644 --- a/src/descriptions/familySummaries.js +++ b/src/descriptions/familySummaries.js @@ -490,6 +490,20 @@ App.Desc.family = (function() { r.push(`${He} has ${numberWithPlural(slave.sisters, "sister")} and ${numberWithPlural(slave.daughters, "daughter")}.`); } + if (V.inbreeding && slave.inbreedingCoeff > 0) { + r.push(`${He} is`); + if (slave.inbreedingCoeff >= 0.5) + r.push("extremely"); + else if (slave.inbreedingCoeff >= 0.25) + r.push("very"); + else if (slave.inbreedingCoeff >= 0.125); + else if (slave.inbreedingCoeff >= 0.0625) + r.push("somewhat"); + else + r.push("slightly"); + r.push(`inbred, with a CoI of ${slave.inbreedingCoeff}.`); + } + return r.join(" "); } @@ -675,6 +689,20 @@ App.Desc.family = (function() { r.push(`<br>You have ${numberWithPlural(V.PC.sisters, "sister")} and ${numberWithPlural(V.PC.daughters, "daughter")}.`); } + if (V.inbreeding && V.PC.inbreedingCoeff > 0) { + r.push(`You are`); + if (V.PC.inbreedingCoeff >= 0.5) + r.push("extremely"); + else if (V.PC.inbreedingCoeff >= 0.25) + r.push("very"); + else if (V.PC.inbreedingCoeff >= 0.125); // No adjective in this case + else if (V.PC.inbreedingCoeff >= 0.0625) + r.push("somewhat"); + else + r.push("slightly"); + r.push(`inbred, with a CoI of ${V.PC.inbreedingCoeff}.`); + } + return r.join(" "); } diff --git a/src/endWeek/saServeYourOtherSlaves.js b/src/endWeek/saServeYourOtherSlaves.js index ef38d9d3e78cae9f55b4d469c8d952e11a3e2f35..46d73d5fa14b874532dbbffcb8e72a77c91be374 100644 --- a/src/endWeek/saServeYourOtherSlaves.js +++ b/src/endWeek/saServeYourOtherSlaves.js @@ -116,7 +116,7 @@ App.SlaveAssignment.serveYourOtherSlaves = (function() { r.push(`is left as a sperm dispenser for fertile slaves to ride or milk at their discretion.`); } } else if (slave.career === "a breeding bull") { - r.push(`sees it as ${his} duty to impregnate everyone in ${his} path. A role ${he} <span class="hotpink">appreciates</span> you <span class="mediumaquamarine">untrusting ${him} with.</span>`); + r.push(`sees it as ${his} duty to impregnate everyone in ${his} path. A role ${he} <span class="hotpink">appreciates</span> you <span class="mediumaquamarine">entrusting ${him} with.</span>`); slave.devotion += 1; slave.trust += 1; if (slave.fetishKnown === 1) { @@ -864,7 +864,7 @@ App.SlaveAssignment.serveYourOtherSlaves = (function() { r.push(`${domName}, it turns out, <span class="lightcoral">really likes cum,</span> and ${subName} has balls, so`); domSlave.fetishKnown = 1; } - r.push(`Since ${domName} loves cum, and ${subName} has balls, ${domName} has ${his2} own private semen dispenser. ${domName} sometimes gets tired of having to work hard for cum, so ${he2} spends the week`); + r.push(`${domName} has ${his2} own private semen dispenser. ${domName} sometimes gets tired of having to work hard for cum, so ${he2} spends the week`); if (hasAnyArms(domSlave)) { r.push(`stimulating poor ${subName}'s`); } else { diff --git a/src/endWeek/saWorkTheFarm.js b/src/endWeek/saWorkTheFarm.js index dac4a52c36cf272898ff8916b618777694942bab..a06295b7d42b9f1d5446f91068281ad89ac61b80 100644 --- a/src/endWeek/saWorkTheFarm.js +++ b/src/endWeek/saWorkTheFarm.js @@ -11,10 +11,10 @@ App.SlaveAssignment.workTheFarm = function(slave) { { he, him, his, He, His } = getPronouns(slave), incomeStats = getSlaveStatisticData(slave, V.facility.farmyard), - slaveApproves = () => sexualQuirks.includes(slave.sexualQuirk) || behavorialQuirks.includes(slave.behavioralQuirk) || fetishes.includes(slave.fetish), + slaveApproves = () => sexualQuirks.includes(slave.sexualQuirk) || behavioralQuirks.includes(slave.behavioralQuirk) || fetishes.includes(slave.fetish), sexualQuirks = ["perverted", "unflinching"], - behavorialQuirks = ["sinful"], + behavioralQuirks = ["sinful"], fetishes = ["humiliation", "masochist"], foodAmount = Math.trunc(App.Facilities.Farmyard.foodAmount(slave)); diff --git a/src/events/RESS/comfortableSeat.js b/src/events/RESS/comfortableSeat.js index 628ecfe0cb5ecaecc37f9500385d31bad3319cb7..30b7b5be276103467e6d24287187dcd2e8e2626e 100644 --- a/src/events/RESS/comfortableSeat.js +++ b/src/events/RESS/comfortableSeat.js @@ -30,7 +30,7 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba const {s, say, title: Master} = getEnunciation(eventSlave); const desc = SlaveTitle(eventSlave); const belly = bellyAdjective(eventSlave); - const dickSize = ["tiny", "", "big"][Math.ceil(Math.clamp(eventSlave.dick, 1, 5) / 2) - 1]; // ranges are "tiny" <= 2 < "" <= 4 < "big" + const dickSize = eventSlave.dick > 4 ? "big" : (eventSlave.dick > 2 ? "" : "tiny"); /** @type {App.Entity.PlayerState} */ let PC = V.PC; @@ -151,10 +151,10 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba t.push(`turns around and carefully perches ${himself} on ${PC.dick !== 0 ? "your cock" : "the phallus"},`); if (canDoVaginal(eventSlave) && eventSlave.vagina > 0) { t.push(`letting ${his} weight slide it inside ${his} wet pussy.`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else if (canDoAnal(eventSlave) && eventSlave.anus > 0) { t.push(`letting ${his} weight push it up ${his} asshole.`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } else { t.push(`putting it between ${his} thighs.`); } @@ -168,10 +168,10 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba t.push(`turns around and sits on ${PC.dick !== 0 ? "your cock" : "the phallus"}, leaning back against you and making sure all the other slaves who pass by can see`); if (canDoVaginal(eventSlave) && eventSlave.vagina > 0) { t.push(`where it penetrates ${his} cunt.`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else if (canDoAnal(eventSlave) && eventSlave.anus > 0) { t.push(`where it's lodged up ${his} butt.`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } else { t.push(`where it's rubbing ${him} intimately between ${his} thighs.`); } @@ -180,7 +180,7 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba case "buttslut": if (canDoAnal(eventSlave) && eventSlave.anus > 0) { t.push(`turns around and shivers with pleasure as ${he} hilts ${his} anal sphincter around the base of ${PC.dick !== 0 ? "your cock" : "the phallus"}. ${He} bounces on it happily, reaming ${his} own ass,`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } else { t.push(`turns around and shivers with pleasure as ${he} feels ${PC.dick !== 0 ? "your cock" : "the phallus"} slip between ${his} buttcheeks. ${He} rubs against it, happy to share ${his} butt with you,`); } @@ -216,7 +216,7 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba } t.push(`${He} rides you hungrily,`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); if (canImpreg(eventSlave, PC)) { knockMeUp(eventSlave, 40, 0, -1); } @@ -228,10 +228,10 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba t.push(`turns around and sits right down on ${PC.dick !== 0 ? "your cock" : "the phallus"}, eagerly`); if (canDoVaginal(eventSlave) && eventSlave.vagina > 0) { t.push(`taking it into ${his} cunt.`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else if (canDoAnal(eventSlave) && eventSlave.anus > 0) { t.push(`getting it shoved up ${his} butt.`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } else { t.push(`squeezing it between ${his} thighs.`); } @@ -241,10 +241,10 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba t.push(`turns around and hesitantly sits on ${PC.dick !== 0 ? "your cock" : "the phallus"}, letting`); if (canDoVaginal(eventSlave) && eventSlave.vagina > 0) { t.push(`it slide into ${his} cunt.`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else if (canDoAnal(eventSlave) && eventSlave.anus > 0) { t.push(`it slide up ${his} butt.`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } else { t.push(`it slide between ${his} thighs.`); } @@ -254,10 +254,10 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba t.push(`turns around and carefully perches ${himself} on ${PC.dick !== 0 ? "your cock" : "the phallus"},`); if (canDoVaginal(eventSlave) && eventSlave.vagina > 0) { t.push(`letting ${his} weight slide it inside ${his} wet pussy at an uncomfortable angle.`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else if (canDoAnal(eventSlave) && eventSlave.anus > 0) { t.push(`letting ${his} weight push it up ${his} asshole at an uncomfortable angle.`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } else { t.push(`putting it between ${his} thighs at an uncomfortable angle.`); } @@ -269,10 +269,10 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba t.push(`${eventSlave.fetishKnown === 1 ? `${He} can't really think of how to accommodate the situation to ${his} own preferred approach to sex` : `${He} isn't well versed in how ${his} own sexual needs might fit into the situation`}, so ${he} just services you like a good ${girl}. ${He} turns around and sits on ${PC.dick !== 0 ? "your cock" : "the phallus"},`); if (canDoVaginal(eventSlave) && eventSlave.vagina > 0) { t.push(`squatting to bounce ${his} cunt up and down on it.`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else if (canDoAnal(eventSlave) && eventSlave.anus > 0) { t.push(`squatting to bounce ${his} butthole up and down on it.`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } else { t.push(`putting it between ${his} thighs for some intercrural sex, since ${his} ${eventSlave.vagina > -1 ? "holes aren't" : "hole isn't"} appropriate.`); } @@ -304,10 +304,10 @@ App.Events.RESSComfortableSeat = class RESSComfortableSeat extends App.Events.Ba t.push(`Deciding that ${he} shouldn't use ${his} ${hasBothArms(eventSlave) ? "hands" : "hand"} to guide it, ${he} lowers ${himself} slowly,`); if (canDoVaginal(eventSlave) && eventSlave.vagina > 0) { t.push(`breathing a little harder as ${he} feels its head spread ${his} pussylips and then slide inside ${him}.`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else if (canDoAnal(eventSlave) && eventSlave.anus > 0) { t.push(`letting out a breath and relaxing as ${he} feels its head press past ${his} sphincter and then all the way up ${his} butt.`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } else { t.push(`getting it situated between ${his} thighs, since that's the best option ${he} has available.`); } diff --git a/src/events/RESS/devotedAnalVirgin.js b/src/events/RESS/devotedAnalVirgin.js index f3e983c1212ad55daa058970dceaae9a528a44dd..f9a354087fef606b341f9244bd503d7271601a28 100644 --- a/src/events/RESS/devotedAnalVirgin.js +++ b/src/events/RESS/devotedAnalVirgin.js @@ -93,11 +93,11 @@ App.Events.RESSDevotedAnalVirgin = class RESSDevotedAnalVirgin extends App.Event t.push(`lavishing attention on ${his} nipples to ensure that ${he} has fun, too.`); } t.push(`${He} leaves your office feeling <span class="hotpink">very close to ${his} ${WrittenMaster(eventSlave)} indeed,</span> and seems to have forgotten ${his} unfucked butthole, for now.`); - - eventSlave.devotion += 4; if (eventSlave.vagina > 0 && canDoVaginal(eventSlave)) { - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } + + eventSlave.devotion += 4; return t; } diff --git a/src/events/RESS/devotedWaist.js b/src/events/RESS/devotedWaist.js index 442acee4c650e32687de8544f7a900bd32c30cdb..0665172859d59da1ec849d8b4e943120e941d48c 100644 --- a/src/events/RESS/devotedWaist.js +++ b/src/events/RESS/devotedWaist.js @@ -102,18 +102,18 @@ App.Events.RESSDevotedWaist = class RESSDevotedWaist extends App.Events.BaseEven t.push(`This can be applied during sex many ways. First, ${he} sits on the bathroom counter and bends ${himself} almost double for`); if (canDoAnal(eventSlave)) { t.push(`anal. Your control over the pace is perfected by your grip around ${his} tiny middle.`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } else { t.push(`vaginal. Your control over the pace is perfected by your grip around ${his} tiny middle.`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } t.push(`Finally, ${he} goes down on ${hasAllLimbs(eventSlave) ? "all fours" : "the floor"} for a hard`); if (canDoVaginal(eventSlave)) { t.push(`pounding, doggy style, losing ${himself} in the intense penetration as you use your hold around ${him} to give it to ${him} even harder.`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else { t.push(`buttfuck, doggy style, losing ${himself} in the intense anal as you use your hold around ${him} to give it to ${him} even harder.`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } t.push(`By the end ${he}'s tired but <span class="mediumaquamarine">confident in ${his} sexual uniqueness.</span>`); } @@ -145,9 +145,9 @@ App.Events.RESSDevotedWaist = class RESSDevotedWaist extends App.Events.BaseEven if (canDoAnal(eventSlave) || canDoVaginal(eventSlave)) { t.push(`${eventSlave.slaveName}'s gown allows you to take ${him} in a ${eventSlave.belly >= 5000 ? "tight" : "close"} lotus position on the cleared table, face to face.`); if (canDoVaginal(eventSlave)) { - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else { - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } } else { t.push(`you and ${eventSlave.slaveName} enjoy the ${canSee(eventSlave) ? "sights" : "atmosphere"} while fooling around. While you'd love to use ${him}, ${his} chastity keeps you at bay.`); diff --git a/src/events/RESS/frighteningDick.js b/src/events/RESS/frighteningDick.js index 08dbb8360bd7a62be335a8e93afa315cd3f58639..d8e44b8aa08da94bae98d58900ddb6937e503aa7 100644 --- a/src/events/RESS/frighteningDick.js +++ b/src/events/RESS/frighteningDick.js @@ -127,10 +127,10 @@ App.Events.RESSFrighteningDick = class RESSFrighteningDick extends App.Events.Ba t.push(`You tell ${him} not to worry, because you're still pretty wet from the last slave you fucked, so this shouldn't hurt too much. Then you ram your cock`); if (eventSlave.vagina > 0) { t.push(`inside ${him}.`); - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else { t.push(`up ${his} spasming ass.`); - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } t.push(`${He} whines and bucks, but ${he}'s entirely at your mercy. ${He} doesn't like dicks, and to go by ${his} facial expression as you piston in and out of ${him}, this experience isn't going to make ${him} reconsider. When you fill ${him} with cum, pull out, and let ${him} retreat to clean ${himself} up, ${he}'s relieved to go.`); diff --git a/src/events/RESS/obedientAddict.js b/src/events/RESS/obedientAddict.js index 2af196656457f45cdf56afb537ede5eb1be00480..a29fd53a586abd4b2075e0bace36f303ff37ff76 100644 --- a/src/events/RESS/obedientAddict.js +++ b/src/events/RESS/obedientAddict.js @@ -100,13 +100,13 @@ App.Events.RESSObedientAddict = class RESSObedientAddict extends App.Events.Base t.push(`${He} indicates through ${his} weeping that ${he} can't climax without the drugs.`); } t.push(`You pass ${him} the pill, and ${he} continues to weep inconsolably, apologizing all the while, until the drug takes away ${his} ability to care about anything but getting fucked. When you finish and extract ${PC.dick === 0 ? `yourself from between ${his} legs` : `your cock from ${his} well-used hole`}, though, you think you can detect a deep sadness in ${his} eyes that it cannot reach.`); - - eventSlave.devotion += 4; if (canDoVaginal(eventSlave)) { - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else { - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } + + eventSlave.devotion += 4; return t; } diff --git a/src/events/RESS/obedientGirlish.js b/src/events/RESS/obedientGirlish.js index 67e148be597c71fc3e2c33961528bdb82907c648..5900257f1235057431b562b56ebbc8d16dea5471 100644 --- a/src/events/RESS/obedientGirlish.js +++ b/src/events/RESS/obedientGirlish.js @@ -106,12 +106,12 @@ App.Events.RESSObedientGirlish = class RESSObedientGirlish extends App.Events.Ba } else { t.push(`${he}'s wet and ready and moans happily as you enter ${him}.`); } - t.push(`There's no hesitation or fear at all on ${his} face when ${he} ${canSee(eventSlave) ? "sees" : "notices"} you're returning ${him} to your penthouse; <span class="mediumaquamarine">${his} trust in you has increased.</span>`); if (canDoVaginal(eventSlave)) { - VCheck.Vaginal(1, eventSlave); + t.push(VCheck.Vaginal(1, eventSlave)); } else { - VCheck.Anal(1, eventSlave); + t.push(VCheck.Anal(1, eventSlave)); } + t.push(`There's no hesitation or fear at all on ${his} face when ${he} ${canSee(eventSlave) ? "sees" : "notices"} you're returning ${him} to your penthouse; <span class="mediumaquamarine">${his} trust in you has increased.</span>`); eventSlave.trust += 4; return t; @@ -142,8 +142,8 @@ App.Events.RESSObedientGirlish = class RESSObedientGirlish extends App.Events.Ba t.push(`lie face-down on the couch${PC.dick === 0 ? " while you don a strap-on" : ""}.`); } t.push(`${He} does doubtfully, only realizing what you intend when ${he} feels ${PC.dick === 0 ? "the strap-on" : "your dickhead"} forcing its way between ${his} narrow buttcheeks. ${He} whimpers and moans ${eventSlave.belly < 300000 ? "into the couch" : ""} as you roughly sodomize ${him}. It's true, ${he}'s pretty androgynous from this angle, especially while ${he} takes it up the butthole. <span class="hotpink">${He} has become more submissive to you,</span> but there's <span class="gold">some fear there, too.</span>`); + t.push(VCheck.Anal(1, eventSlave)); - VCheck.Anal(1, eventSlave); eventSlave.trust -= 2; eventSlave.devotion += 4; return t; diff --git a/src/events/RESS/obedientShemale.js b/src/events/RESS/obedientShemale.js index 54dc9773fb94f60f445836424168575265e8e909..eb7e880c5c498cf7a87b223d93ffe9e6235b4f6b 100644 --- a/src/events/RESS/obedientShemale.js +++ b/src/events/RESS/obedientShemale.js @@ -28,7 +28,7 @@ App.Events.RESSObedientShemale = class RESSObedientShemale extends App.Events.Ba He, he, His, his, him, himself, girl } = getPronouns(eventSlave); const {title: Master} = getEnunciation(eventSlave); - const anusDesc = ["tight", "loose", "gaping"][Math.ceil(Math.clamp(eventSlave.anus, 1, 3)) - 1]; + const anusDesc = eventSlave.anus > 2 ? "gaping" : (eventSlave.anus > 1 ? "loose" : "tight"); /** @type {App.Entity.PlayerState} */ let PC = V.PC; @@ -76,9 +76,9 @@ App.Events.RESSObedientShemale = class RESSObedientShemale extends App.Events.Ba t.push("shakes with release"); } t.push(`after just a few strokes of your ${PC.dick === 0 ? "strap-on" : "cock"} up ${his} butt. ${His} ${anusDesc} ass spasms and tightens with ${his} climax${PC.dick !== 0 ? ", a wonderful sensation" : ""}. You aren't finished with ${him}, but ${he} rubs ${himself} languidly and enjoys the hard anal reaming more than ${he} ever has previously. ${His} devotion to you <span class="hotpink">has increased.</span>`); + t.push(VCheck.Anal(1, eventSlave)); eventSlave.devotion += 4; - VCheck.Anal(1, eventSlave); return t; } @@ -86,9 +86,9 @@ App.Events.RESSObedientShemale = class RESSObedientShemale extends App.Events.Ba t = []; t.push(`${He} obeys your orders to keep ${his} ${hasBothArms(eventSlave) ? "hands" : "hand"} off ${his} dick, but can't hide ${his} disappointment and frustration. You keep a close watch on ${him}, and buttfuck ${him} every chance you get, teaching ${him} the finer points of taking a ${PC.dick === 0 ? "strap-on" : "dick"} up the butt. You focus entirely on your pleasure, teaching ${him} how to use ${his} ${anusDesc} anal ring to extract orgasms from cocks. This experience was hard for ${him} but has increased ${his} anal skill.`); + t.push(VCheck.Anal(9, eventSlave)); SkillIncrease.Anal(eventSlave, 10); - VCheck.Anal(9, eventSlave); return t; } @@ -106,7 +106,7 @@ App.Events.RESSObedientShemale = class RESSObedientShemale extends App.Events.Ba t.push(`Despite being used as an anal slut for a whole week, ${he} was not significantly affected.`); } - VCheck.Anal(9, eventSlave); + t.push(VCheck.Anal(9, eventSlave)); return t; } } diff --git a/src/facilities/farmyard/shows/saFarmyardShows.js b/src/facilities/farmyard/shows/saFarmyardShows.js index 7efaf5cb0bd6789d29a64535b1c22fb6f909fdba..f871fd325b800bd9ec6580ce1237443050279a30 100644 --- a/src/facilities/farmyard/shows/saFarmyardShows.js +++ b/src/facilities/farmyard/shows/saFarmyardShows.js @@ -362,7 +362,7 @@ App.Facilities.Farmyard.putOnShows = function(slave) { } else if (slave.energy > 20) { r.push(`The fact that ${his} sex drive is so poor affects ${his} performance.`); } else { - r.push(`The fact that ${his} sex drive is nonexistant really hinders ${his} ability to put on a decent show.`); + r.push(`The fact that ${his} sex drive is nonexistent really hinders ${his} ability to put on a decent show.`); } // TODO: add more to the fetishes and flaws / quirks diff --git a/src/facilities/nursery/customizeChild.tw b/src/facilities/nursery/customizeChild.tw index e8d5fbab17fc1e5e417497f681ed109c78dacf68..243dec682954c23a60aad9dc166508eff67a68c3 100644 --- a/src/facilities/nursery/customizeChild.tw +++ b/src/facilities/nursery/customizeChild.tw @@ -1,7 +1,9 @@ :: Customize Child [nobr] -<<set $nextButton = "Continue", $nextLink = "Rename Child">> -<<set $oldName = $activeChild.slaveName, $oldSurname = $activeChild.slaveSurname>> +<<set $nextButton = "Continue">> +<<set _oldName = $activeChild.slaveName, _oldSurname = $activeChild.slaveSurname>> + +<p id="rename"></p> You may enter custom descriptors for the child's hair color, hair style, tattoos, or anything else here. After typing, press enter to commit your change. These custom descriptors will appear in descriptions of the child, but will have no gameplay effect. Changing them is free. <br><br> @@ -62,35 +64,61 @@ You may enter custom descriptors for the child's hair color, hair style, tattoos <<if ((($activeChild.devotion >= -50) || ($activeChild.trust < -20)) && ($activeChild.birthName != $activeChild.slaveName)) || (($activeChild.devotion > 20) || ($activeChild.trust < -20))>> Change $his given name<<if $activeChild.birthName != $activeChild.slaveName>> ($his birth name was $activeChild.birthName)<</if>>: - <<textbox "$activeChild.slaveName" $activeChild.slaveName "Rename Child">> - <<link "Restore $his birth name" "Rename Child">> + <<includeDom App.UI.DOM.makeTextBox( + $activeChild.slaveName, + v => { + $activeChild.slaveName = v; + App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname}); + }, + false + )>> + <<link "Restore $his birth name">> <<set $activeChild.slaveName = $activeChild.birthName>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <<if $arcologies[0].FSPastoralist != "unset">> <<if $activeChild.lactation > 0>> - | <<link "Give $him a random cow given name" "Rename Child">> + | <<link "Give $him a random cow given name">> <<set $activeChild.slaveName = setup.cowSlaveNames.random()>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <</if>> <</if>> <<if $arcologies[0].FSChattelReligionist != "unset">> - | <<link "Give $him a random devotional given name" "Rename Child">> + | <<link "Give $him a random devotional given name">> <<set $activeChild.slaveName = setup.chattelReligionistSlaveNames.random()>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <</if>> <br><br> Change $his surname<<if $activeChild.birthSurname != $activeChild.slaveSurname>> ($his birth surname was $activeChild.birthSurname)<</if>>: <<if $activeChild.slaveSurname>> - <<textbox "$activeChild.slaveSurname" $activeChild.slaveSurname "Rename Child">> + <<includeDom App.UI.DOM.makeTextBox( + $activeChild.slaveSurname, + v => { + $activeChild.slaveSurname = v; + App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname}); + }, + false + )>> <<else>> - <<textbox "$activeChild.slaveSurname" "" "Rename Child">> + <<includeDom App.UI.DOM.makeTextBox( + "", + v => { + $activeChild.slaveSurname = v; + App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname}); + }, + false + )>> <</if>> - <<link "Restore $his birth surname" "Rename Child">> + <<link "Restore $his birth surname">> <<set $activeChild.slaveSurname = $activeChild.birthSurname>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <<if $activeChild.slaveSurname>> - | <<link "Take $his surname away" "Rename Child">> + | <<link "Take $his surname away">> <<set $activeChild.slaveSurname = 0>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <</if>> <<if $activeChild.relationship >= 5>> @@ -98,8 +126,9 @@ You may enter custom descriptors for the child's hair color, hair style, tattoos <<if $activeChild.relationshipTarget == $slaves[_i].ID>> <<if $slaves[_i].slaveSurname>> <<if $activeChild.slaveSurname != $slaves[_i].slaveSurname>> - | <<link "Give $him $his wife's surname" "Rename Child">> + | <<link "Give $him $his wife's surname">> <<set $activeChild.slaveSurname = $slaves[_i].slaveSurname>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <<break>> <</if>> @@ -110,33 +139,43 @@ You may enter custom descriptors for the child's hair color, hair style, tattoos <<if $activeChild.relationship == -3>> <<if $PC.slaveSurname>> <<if $activeChild.slaveSurname != $PC.slaveSurname>> - | <<link "Give $him your surname" "Rename Child">> + | <<link "Give $him your surname">> <<set $activeChild.slaveSurname = $PC.slaveSurname>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <</if>> <</if>> <</if>> <<if $arcologies[0].FSRomanRevivalist != "unset">> - | <<link "Give $him a random full Roman name" "Rename Child">> - <<set $activeChild.slaveName = setup.romanSlaveNames.random(), $activeChild.slaveSurname = setup.romanSlaveSurnames.random()>> + | <<link "Give $him a random full Roman name">> + <<set $activeChild.slaveName = setup.romanSlaveNames.random()>> + <<set $activeChild.slaveSurname = setup.romanSlaveSurnames.random()>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <<elseif $arcologies[0].FSAztecRevivalist != "unset">> - | <<link "Give $him a random full Aztec name" "Rename Child">> - <<set $activeChild.slaveName = setup.aztecSlaveNames.random(), $activeChild.slaveSurname = 0>> + | <<link "Give $him a random full Aztec name">> + <<set $activeChild.slaveName = setup.aztecSlaveNames.random()>> + <<set $activeChild.slaveSurname = 0>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <<elseif $arcologies[0].FSEgyptianRevivalist != "unset">> - | <<link "Give $him a random full ancient Egyptian name" "Rename Child">> - <<set $activeChild.slaveName = setup.ancientEgyptianSlaveNames.random(), $activeChild.slaveSurname = 0>> + | <<link "Give $him a random full ancient Egyptian name">> + <<set $activeChild.slaveName = setup.ancientEgyptianSlaveNames.random()>> + <<set $activeChild.slaveSurname = 0>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <<elseif $arcologies[0].FSEdoRevivalist != "unset">> - | <<link "Give $him a random full feudal Japanese name" "Rename Child">> - <<set $activeChild.slaveName = setup.edoSlaveNames.random(), $activeChild.slaveSurname = setup.edoSlaveSurnames.random()>> + | <<link "Give $him a random full feudal Japanese name">> + <<set $activeChild.slaveName = setup.edoSlaveNames.random()>> + <<set $activeChild.slaveSurname = setup.edoSlaveSurnames.random()>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> <</link>> <</if>> <<if $arcologies[0].FSDegradationist > -1>> - | <<link "Give $him a degrading full name" "Rename Child">> - <<run DegradingName($activeChild)>> - <</link>> + | <<link "Give $him a degrading full name">> + <<run DegradingName($activeChild)>> + <<run App.UI.SlaveInteract.rename($activeChild, {oldName:_oldName, oldSurname:_oldSurname})>> + <</link>> <</if>> <<else>> //You must break $his will further before you can successfully force a new name on $him.// diff --git a/src/facilities/nursery/customizeInfant.tw b/src/facilities/nursery/customizeInfant.tw index 6969f6b8aedc0cf7b049b779f3c582cbb31dd857..c4687bfe6128d2180f0281bb1080c60d895896df 100644 --- a/src/facilities/nursery/customizeInfant.tw +++ b/src/facilities/nursery/customizeInfant.tw @@ -1,7 +1,6 @@ :: Customize Infant [nobr] -<<set $nextButton = "Continue", $nextLink = "Rename Child">> -<<set $oldName = $activeChild.slaveName, $oldSurname = $activeChild.slaveSurname>> +<<set $nextButton = "Continue">> /* TODO: all of this */ You may enter custom descriptors for your child's hair color, hair style, tattoos, or anything else here. After typing, press enter to commit your change. These custom descriptors will appear in descriptions of your child, but will have no gameplay effect. Changing them is free. diff --git a/src/facilities/nursery/renameChild.tw b/src/facilities/nursery/renameChild.tw deleted file mode 100644 index f3536031727f4f4a8749dab19f4fe407e98a4454..0000000000000000000000000000000000000000 --- a/src/facilities/nursery/renameChild.tw +++ /dev/null @@ -1,142 +0,0 @@ -:: Rename Child [nobr] - -<<set $nextButton = "Back", $nextLink = "Slave Interact">> - -<<if $activeChild.slaveName === $oldName && $activeChild.slaveSurname === $oldSurname>> - <<goto "Slave Interact">> -<<else>> -/* First time renaming reaction */ -<<if $activeChild.slaveName === "" || ndef $activeChild.slaveName>> - $oldName needs to be called something on the records, so $oldName $he stays. - <<set $activeChild.slaveName = $oldName>> -<<elseif $activeChild.fetish == "mindbroken">> - $activeChild.slaveName doesn't even recognize that $he's been renamed. It simply does not register. -<<elseif ($oldName != $activeChild.birthName && $oldSurname != $activeChild.birthSurname) && ($activeChild.slaveName == $activeChild.birthName || $activeChild.slaveSurname == $activeChild.birthSurname)>> - $activeChild.slaveName - <<if $activeChild.devotion > 50>> - cheerfully accepts $his old name back. - <<elseif $activeChild.devotion >= -20>> - obediently accepts $his old name back. - <<elseif $activeChild.devotion >= -50>> - happily accepts $his original name. - <<elseif $activeChild.trust > 20>> - scoffs at the notion that $he was ever anything other than <<= SlaveFullBirthName($activeChild)>>, @@.orangered;weakening your control over $him.@@ - <<set $activeChild.trust += 5>> - <<else>> - cautiously accepts the return of $his name. - <</if>> -<<elseif $oldName == $activeChild.birthName || $oldSurname == $activeChild.birthSurname>> - $activeChild.slaveName - <<if $activeChild.devotion > 50>> - accepts $his new name cheerfully. This attachment to you @@.hotpink; increases $his devotion.@@ - <<set $activeChild.devotion += 4>> - <<elseif $activeChild.devotion >= -20>> - obediently accepts $his new name. This surrender to you @@.hotpink; increases $his obedience.@@ - <<set $activeChild.devotion += 4>> - <<elseif $activeChild.devotion >= -50>> - reluctantly accepts $his new name. - <<else>> - angrily tries to resist $his new name, insisting that $his name is <<= SlaveFullBirthName($activeChild)>>. This resistance @@.mediumorchid; increases $his rebelliousness.@@ - <<set $activeChild.devotion -= 5>> - <</if>> -<<else>> - Since $activeChild.slaveName has already had a new name <<if $activeChild.devotion > 20>>given to<<else>>forced on<</if>> $him before, the mere fact of having it changed again doesn't really affect $him. -<</if>> - -<<set _insultingName = 0>> -<<if $oldName != $activeChild.slaveName && typeof $activeChild.slaveName == "string">> - <<set _toSearch = $activeChild.slaveName.toLowerCase()>> - <<for $i = 0; $i < setup.badWords.length; $i++>> - <<if _toSearch.indexOf(setup.badWords[$i]) != -1>> - <<set _insultingName = 1>> - <<break>> - <</if>> - <</for>> -<</if>> -<<if !_insultingName>> - <<if $oldSurname != $activeChild.slaveSurname && typeof $activeChild.slaveSurname == "string">> - <<set _toSearch = $activeChild.slaveSurname.toLowerCase()>> - <<for $i = 0; $i < setup.badWords.length; $i++>> - <<if _toSearch.indexOf(setup.badWords[$i]) != -1>> - <<set _insultingName = 1>> - <<break>> - <</if>> - <</for>> - <</if>> -<</if>> -<<if _insultingName == 1>> - <<if $activeChild.fetish == "mindbroken">> - $His new name would be insulting to a normal $girl, but $he dully accepts that it is an accurate description and goes about $his duties. - <<elseif $activeChild.devotion < -50>> - Being given such a degrading name @@.mediumorchid;further increases $his hatred@@ of you. - <<set $activeChild.devotion -= 5>> - <<elseif $activeChild.devotion <= 50>> - Being given such a degrading name @@.gold;terrifies $him,@@ since $he thinks it's fair warning for what $he'll suffer in the future. - <<set $activeChild.trust -= 5>> - <</if>> -<</if>> - -/* Wife's surname reaction */ -<<if $oldSurname != $activeChild.slaveSurname>> - <<if $activeChild.relationship >= 5>> - <<set _i = $slaveIndices[$activeChild.relationshipTarget]>> - <<if ndef _i>>@@.red;Error, relationshipTarget not found.@@<</if>> - <<if $slaves[_i].slaveSurname>> - <<if $activeChild.slaveSurname == $slaves[_i].slaveSurname>> - $He's touched that $he now shares a surname with $his wife $slaves[_i].slaveName $slaves[_i].slaveSurname, and is @@.mediumaquamarine;more confident than ever@@ that you intend to keep them together in marital bliss. - <<set $activeChild.trust += 5>> - <<elseif $oldSurname == $slaves[_i].slaveSurname>> - $He's concerned that $he no longer shares a surname with $his wife $slaves[_i].slaveName $slaves[_i].slaveSurname, and is @@.gold;very worried@@ that you might be considering splitting them up. - <<set $activeChild.trust -= 5>> - <</if>> - <</if>> - <</if>> -<</if>> - -/* PC's surname reaction */ -<<if $oldSurname != $activeChild.slaveSurname>> - <<if $activeChild.relationship == -3>> - <<if $PC.slaveSurname>> - <<if $activeChild.fetish == "mindbroken">> - Names are meaningless to $him and it is unlikely $he'll remember it. - <<elseif $activeChild.devotion+$activeChild.trust >= 175>> - <<if $activeChild.slaveSurname == $PC.slaveSurname>> - <<if hasAnyArms($activeChild)>> - When you tell $him that $he's to be known as $activeChild.slaveName $activeChild.slaveSurname now, $he starts to cry. $He tries to get $himself under control and thank you as best $he can, wiping at the tears running down $his $activeChild.skin cheeks, but $he can't seem to stop weeping as $he thanks you over and over. $He's a sex slave, your property, and it's understandable that some doubts about the permanence of $his place as your slave wife. This has @@.mediumaquamarine;helped reassure $him,@@ and explains the strength of $his emotional reaction. The next time you make love to $him, $he @@.hotpink;presses $himself as close to you as $he can,@@ eager to drink in as much of your presence as $he can get. - <<else>> - $He's @@.hotpink;deeply touched@@ that $he now shares a surname with you, and has @@.mediumaquamarine;an additional source of confidence@@ that $he'll remain your amputee slave wife. - <</if>> - <<set $activeChild.devotion += 5, $activeChild.trust += 5>> - <<elseif $oldSurname == $PC.slaveSurname>> - $He's devastated that you'd rename $him something other than your name. $He's @@.gold;terrified@@ that you intend to discard $him as your slave wife, and @@.mediumorchid;saddened@@ that you would take away something that was precious to $him. - <<set $activeChild.devotion -= 5, $activeChild.trust -= 5>> - <</if>> - <<elseif $activeChild.devotion < -20 && $activeChild.trust > 20>> - <<if $activeChild.slaveSurname == $PC.slaveSurname>> - When you tell $him that $he's to be known as $activeChild.slaveName $activeChild.slaveSurname now, $he shows no reaction. You already took everything from $him, what's a name at this point? - <<elseif $oldSurname == $PC.slaveSurname>> - $He doesn't care about losing your surname at first, but it quickly sets in that $he may have @@.gold;pushed $his position too far.@@ - <<set $activeChild.trust -= 20>> - <</if>> - <<elseif $activeChild.devotion < -20>> - <<if $activeChild.slaveSurname == $PC.slaveSurname>> - When you tell $him that $he's to be known as $activeChild.slaveName $activeChild.slaveSurname now, $he pleads with you not to steal $his name. It matters little to you, and $he is forced to @@.hotpink;accept your will.@@ - <<set $activeChild.devotion += 5>> - <<elseif $oldSurname == $PC.slaveSurname>> - $He's @@.mediumorchid;happy@@ to no longer have to share a name with $his tormentor, but the bliss doesn't last long as @@.gold;dread@@ quickly sets in about what this may mean. - <<set $activeChild.devotion += 5, $activeChild.trust -= 10>> - <</if>> - <<else>> - <<if $activeChild.slaveSurname == $PC.slaveSurname>> - When you tell $him that $he's to be known as $activeChild.slaveName $activeChild.slaveSurname now, $he nods with approval feeling @@.mediumaquamarine;that $he may hold at least some value in your eyes.@@ - <<set $activeChild.trust += 5>> - <<elseif $oldSurname == $PC.slaveSurname>> - $He accepts that you'd rename $him something other than your name. $He's @@.gold;a little scared@@ that you intend to discard $him as your slave wife, or worse, but realizes this was not only a possibility, but likely. - <<set $activeChild.trust -= 5>> - <</if>> - <</if>> - <</if>> - <</if>> -<</if>> - -<</if>> /* close new name check */ diff --git a/src/facilities/nursery/widgets/children/ChildState.js b/src/facilities/nursery/widgets/children/ChildState.js index 8de31f2d3e8fb185dbe124bb6123328325e7dd3b..4adb08d4e2c425c7988eda3e9315ba5bc86acd24 100644 --- a/src/facilities/nursery/widgets/children/ChildState.js +++ b/src/facilities/nursery/widgets/children/ChildState.js @@ -1931,5 +1931,7 @@ App.Facilities.Nursery.ChildState = class ChildState { this.lastWeeksRepIncome = 0; /** Not currently used, will work similarly to the cash variables above */ this.lastWeeksRepExpenses = 0; + /** Slave's inbreeding coefficient */ + this.inbreedingCoeff = 0; } }; diff --git a/src/facilities/nursery/widgets/infants/InfantState.js b/src/facilities/nursery/widgets/infants/InfantState.js index f50c3506b54d851f0bbd744d250c0b8ab9f8644b..bad32d731988231611f9575cd12549d622658b95 100644 --- a/src/facilities/nursery/widgets/infants/InfantState.js +++ b/src/facilities/nursery/widgets/infants/InfantState.js @@ -187,5 +187,7 @@ App.Facilities.Nursery.InfantState = class InfantState { this.spermY = 50; /** how many weeks until the child is ready for release */ this.growTime = 156; + /** Slave's inbreeding coefficient */ + this.inbreedingCoeff = 0; } }; diff --git a/src/gui/Encyclopedia/encyclopedia.tw b/src/gui/Encyclopedia/encyclopedia.tw index 8140c9442d83218be401d606ebcb797e8e93eb15..61134d4fdcf1cfbf9c3ccfb1d257594439bc8ae6 100644 --- a/src/gui/Encyclopedia/encyclopedia.tw +++ b/src/gui/Encyclopedia/encyclopedia.tw @@ -3179,6 +3179,13 @@ MODS What would a slaveowner be without the ability to customize their slaves' bodies? The Free Cities offer a variety of ways to achieve this for an arcology owner. Choose a more particular entry below: <br> +<<case "Inbreeding">> + At the intersection of incest and pregnancy lies inbreeding. As seen in royal families throughout history, high levels of inbreeding can result in severe issues, often manifesting as facial deformities or reduced intellectual capacity. + + <br><br>One metric for quantifying inbreeding is the coefficient of inbreeding (CoI), which is the probability that both copies of a person's genes come from the same common ancestor. For example, without any previous inbreeding a child from self-fertilization has a CoI of 0.5, a child of two full siblings has a CoI of 0.25, and a child of two first cousins has a CoI of 0.0625. + + <br><br>Enterprising breeders trying to breed specific traits should be mindful of the inbreeding coefficients of their stock: the higher the coefficient, the higher the chance that children will be slow or deformed. + <<default>> Error: bad title. <</switch>> diff --git a/src/gui/Encyclopedia/encyclopediaRelatedLinks.tw b/src/gui/Encyclopedia/encyclopediaRelatedLinks.tw index 977e489706c77724ea61c26500adbdee70b913f6..7fddb42e1033992d8e5f3ea2d6e8e22c61271a87 100644 --- a/src/gui/Encyclopedia/encyclopediaRelatedLinks.tw +++ b/src/gui/Encyclopedia/encyclopediaRelatedLinks.tw @@ -244,7 +244,7 @@ SLAVE RELATIONSHIPS /********** PREGNANCY **********/ -<<case "Artificial Insemination" "Breeders Dietary Blend" "Childbirth and C-Secs" "Cloning" "Fertility Mix" "Gestation Drugs and Labor Suppressants" "Hyper-Pregnancy" "Ova Transplantation" "Player Pregnancy" "Pregnancy" "Pregnancy Generator" "Slave Fertility" "Super Fertility Drugs" "Surrogacy">> +<<case "Artificial Insemination" "Breeders Dietary Blend" "Childbirth and C-Secs" "Cloning" "Fertility Mix" "Gestation Drugs and Labor Suppressants" "Hyper-Pregnancy" "Ova Transplantation" "Player Pregnancy" "Pregnancy" "Pregnancy Generator" "Slave Fertility" "Super Fertility Drugs" "Surrogacy" "Inbreeding">> <<= App.Encyclopedia.Dialog.linkSC("Pregnancy", "Pregnancy")>> | <<= App.Encyclopedia.Dialog.linkSC("Slave Fertility", "Slave Fertility")>> | <<= App.Encyclopedia.Dialog.linkSC("Player Pregnancy", "Player Pregnancy")>> @@ -261,6 +261,7 @@ PREGNANCY | <<= App.Encyclopedia.Dialog.linkSC("Ova Transplantation", "Ova Transplantation")>> | <<= App.Encyclopedia.Dialog.linkSC("Eugenics Breeding Proposal", "Eugenics Breeding Proposal")>> | <<= App.Encyclopedia.Dialog.linkSC("Repopulationist Breeding School", "Repopulationist Breeding School")>> + | <<= App.Encyclopedia.Dialog.linkSC("Inbreeding", "Inbreeding")>> /********** INFLATION diff --git a/src/interaction/rename.js b/src/interaction/rename.js new file mode 100644 index 0000000000000000000000000000000000000000..c852ef4feb9d553cb105f6a7a60f7e76823d2799 --- /dev/null +++ b/src/interaction/rename.js @@ -0,0 +1,152 @@ +/** + * @param {App.Entity.SlaveState} slave + * @param {object} params + * @param {string} [params.oldName] Their name before you renamed them by calling this function + * @param {string} [params.oldSurname] Their surname before you renamed them by calling this function + */ +App.UI.SlaveInteract.rename = function(slave, {oldName = "", oldSurname = ""} = {}) { + const r = []; + const {He, he, His, his, him, girl, himself, wife} = getPronouns(slave); + if (slave.slaveName === oldName && slave.slaveSurname === oldSurname) { + return; + } else { + /* First time renaming reaction */ + if (slave.slaveName === "" || !(slave.hasOwnProperty("slaveName"))) { + r.push(`${oldName} needs to be called something on the records, so ${oldName} ${he} stays.`); + slave.slaveName = oldName; + } else if (slave.fetish === "mindbroken") { + r.push(`${slave.slaveName} doesn't even recognize that ${he}'s been renamed. It simply does not register.`); + } else if ((oldName !== slave.birthName && slave.slaveName === slave.birthName) || (oldSurname !== slave.birthSurname && slave.slaveSurname === slave.birthSurname)) { + r.push(`${slave.slaveName}`); + if (slave.devotion > 50) { + r.push(`cheerfully accepts ${his} old name back.`); + } else if (slave.devotion >= -20) { + r.push(`obediently accepts ${his} old name back.`); + } else if (slave.devotion >= -50) { + r.push(`happily accepts ${his} original name.`); + } else if (slave.trust > 20) { + r.push(`scoffs at the notion that ${he} was ever anything other than ${SlaveFullBirthName(slave)}, <span class="orangered">weakening your control over ${him}.</span>`); + slave.trust += 5; + } else { + r.push(`cautiously accepts the return of ${his} name.`); + } + } else if ((oldName === slave.birthName && slave.slaveName !== slave.birthName) || (oldSurname === slave.birthSurname && slave.slaveSurname !== slave.birthSurname)) { + r.push(`${slave.slaveName}`); + if (slave.devotion > 50) { + r.push(`accepts ${his} new name cheerfully. This attachment to you <span class="devotion inc"> increases ${his} devotion.</span>`); + slave.devotion += 4; + } else if (slave.devotion >= -20) { + r.push(`obediently accepts ${his} new name. This surrender to you <span class="devotion inc"> increases ${his} obedience.</span>`); + slave.devotion += 4; + } else if (slave.devotion >= -50) { + r.push(`reluctantly accepts ${his} new name.`); + } else { + r.push(`angrily tries to resist ${his} new name, insisting that ${his} name is ${SlaveFullBirthName(slave)}. This resistance <span class="devotion dec"> increases ${his} rebelliousness.</span>`); + slave.devotion -= 5; + } + } else { + r.push(`Since ${slave.slaveName} has already had a new name`); + if (slave.devotion > 20) { + r.push(`given to`); + } else { + r.push(`forced on`); + } + r.push(`${him} before, the mere fact of having it changed again doesn't really affect ${him}.`); + } + + let insultingName = false; + let toSearch; + if (oldName !== slave.slaveName && typeof slave.slaveName === "string") { + toSearch = slave.slaveName.toLowerCase(); + insultingName = setup.badWords.some((s) => toSearch.includes(s)); + } + if (!insultingName) { + if (oldSurname !== slave.slaveSurname && typeof slave.slaveSurname === "string") { + toSearch = slave.slaveSurname.toLowerCase(); + insultingName = setup.badWords.some((s) => toSearch.includes(s)); + } + } + if (insultingName) { + if (slave.fetish === "mindbroken") { + r.push(`${His} new name would be insulting to a normal ${girl}, but ${he} dully accepts that it is an accurate description and goes about ${his} duties.`); + } else if (slave.devotion < -50) { + r.push(`Being given such a degrading name <span class="devotion dec">further increases ${his} hatred</span> of you.`); + slave.devotion -= 5; + } else if (slave.devotion <= 50) { + r.push(`Being given such a degrading name <span class="trust dec">terrifies ${him},</span> since ${he} thinks it's fair warning for what ${he}'ll suffer in the future.`); + slave.trust -= 5; + } + } + + /* Wife's surname reaction */ + if (oldSurname !== slave.slaveSurname) { + if (slave.relationship >= 5) { + const slaveWife = getSlave(slave.relationshipTarget); + if (!slaveWife) { + r.push(`<span class="red">Error, relationshipTarget not found.</span>`); + } else { + if (slaveWife.slaveSurname) { + const {wife2} = getPronouns(slaveWife).appendSuffix('2'); + if (slave.slaveSurname === slaveWife.slaveSurname) { + r.push(`${He}'s touched that ${he} now shares a surname with ${his} ${wife2} ${slaveWife.slaveName} ${slaveWife.slaveSurname}, and is <span class="trust inc">more confident than ever</span> that you intend to keep them together in marital bliss.`); + slave.trust += 5; + } else if (oldSurname === slaveWife.slaveSurname) { + r.push(`${He}'s concerned that ${he} no longer shares a surname with ${his} ${wife2} ${slaveWife.slaveName} ${slaveWife.slaveSurname}, and is <span class="trust dec">very worried</span> that you might be considering splitting them up.`); + slave.trust -= 5; + } + } + } + } + } + + /* PC's surname reaction */ + if (oldSurname !== slave.slaveSurname) { + if (slave.relationship === -3) { + if (V.PC.slaveSurname) { + if (slave.fetish === "mindbroken") { + r.push(`Names are meaningless to ${him} and it is unlikely ${he}'ll remember it.`); + } else if (slave.devotion + slave.trust >= 175) { + if (slave.slaveSurname === V.PC.slaveSurname) { + r.push(`When you tell ${him} that ${he}'s to be known as ${slave.slaveName} ${slave.slaveSurname} now, ${he} starts to cry. ${He} tries to get ${himself} under control and thank you as best ${he} can,`); + if (hasAnyArms(slave)) { + r.push(`wiping at the tears running down ${his} ${slave.skin} cheeks,`); + } + r.push(`but ${he} can't seem to stop weeping as ${he} thanks you over and over. ${He}'s a sex slave, your property, and it's understandable that some doubts about the permanence of ${his} place as your slave ${wife}. This has <span class="trust inc">helped reassure ${him},</span> and explains the strength of ${his} emotional reaction. The next time you make love to ${him}, ${he} <span class="devotion inc">presses ${himself} as close to you as ${he} can,</span> eager to drink in as much of your presence as ${he} can get.`); + slave.devotion += 5; + slave.trust += 5; + } else if (oldSurname === V.PC.slaveSurname) { + r.push(`${He}'s devastated that you'd rename ${him} something other than your name. ${He}'s <span class="trust dec">terrified</span> that you intend to discard ${him} as your slave ${V.wife}, and <span class="devotion dec">saddened</span> that you would take away something that was precious to ${him}.`); + slave.devotion -= 5; + slave.trust -= 5; + } + } else if (slave.devotion < -20 && slave.trust > 20) { + if (slave.slaveSurname === V.PC.slaveSurname) { + r.push(`When you tell ${him} that ${he}'s to be known as ${slave.slaveName} ${slave.slaveSurname} now, ${he} shows no reaction. You already took everything from ${him}, what's a name at this point?`); + } else if (oldSurname === V.PC.slaveSurname) { + r.push(`${He} doesn't care about losing your surname at first, but it quickly sets in that ${he} may have <span class="trust dec">pushed ${his} position too far.</span>`); + slave.trust -= 20; + } + } else if (slave.devotion < -20) { + if (slave.slaveSurname === V.PC.slaveSurname) { + r.push(`When you tell ${him} that ${he}'s to be known as ${slave.slaveName} ${slave.slaveSurname} now, ${he} pleads with you not to steal ${his} name. It matters little to you, and ${he} is forced to <span class="devotion inc">accept your will.</span>`); + slave.devotion += 5; + } else if (oldSurname === V.PC.slaveSurname) { + r.push(`${He}'s <span class="devotion dec">happy</span> to no longer have to share a name with ${his} tormentor, but the bliss doesn't last long as <span class="trust dec">dread</span> quickly sets in about what this may mean.`); + slave.devotion += 5; + slave.trust -= 10; + } + } else { + if (slave.slaveSurname === V.PC.slaveSurname) { + r.push(`When you tell ${him} that ${he}'s to be known as ${slave.slaveName} ${slave.slaveSurname} now, ${he} nods with approval feeling <span class="trust inc">that ${he} may hold at least some value in your eyes.</span>`); + slave.trust += 5; + } else if (oldSurname === V.PC.slaveSurname) { + r.push(`${He} accepts that you'd rename ${him} something other than your name. ${He}'s <span class="trust dec">a little scared</span> that you intend to discard ${him} as your slave ${V.wife}, or worse, but realizes this was not only a possibility, but likely.`); + slave.trust -= 5; + } + } + } + } + } + } + return jQuery("#rename").empty().append(r.join(" ")); +}; diff --git a/src/interaction/slaveInteract.js b/src/interaction/slaveInteract.js index 71cbccd05a848523b39eb7ce8bea823696ffa6df..8d7ed15a39a17e516150009abfaace5c0aa81970 100644 --- a/src/interaction/slaveInteract.js +++ b/src/interaction/slaveInteract.js @@ -2486,14 +2486,19 @@ App.UI.SlaveInteract.custom = (function() { } function intro(slave) { - V.oldName = slave.slaveName; - V.oldSurname = slave.slaveSurname; - let intro = document.createElement('p'); - intro.className = "scene-intro"; - intro.append(`You may enter custom descriptors for your slave's hair color, hair style, tattoos, or anything else here. After typing, press `); - intro.appendChild(App.UI.DOM.makeElement("kbd", "enter")); - intro.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.`); - return intro; + 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) { @@ -2612,6 +2617,8 @@ App.UI.SlaveInteract.custom = (function() { return slaveFullNameNode; function slaveName() { + const oldName = slave.slaveName; + const oldSurname = slave.slaveSurname; // Slave Name let slaveNameNode = document.createElement('p'); label = document.createElement('div'); @@ -2629,9 +2636,10 @@ App.UI.SlaveInteract.custom = (function() { slave.slaveName, v => { slave.slaveName = v; + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename"); + ); label.appendChild(textbox); slaveNameNode.appendChild(label); @@ -2640,9 +2648,9 @@ App.UI.SlaveInteract.custom = (function() { ` Restore ${his} birth name`, () => { slave.slaveName = slave.birthName; + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); if (V.arcologies[0].FSPastoralist !== "unset") { @@ -2652,9 +2660,9 @@ App.UI.SlaveInteract.custom = (function() { `Give ${him} a random cow given name`, () => { slave.slaveName = setup.cowSlaveNames.random(); + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); } } @@ -2665,9 +2673,9 @@ App.UI.SlaveInteract.custom = (function() { `Give ${him} a random stipper given name`, () => { slave.slaveName = setup.bimboSlaveNames.random(); + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); } } @@ -2677,9 +2685,9 @@ App.UI.SlaveInteract.custom = (function() { `Give ${him} a random devotional given name`, () => { slave.slaveName = setup.chattelReligionistSlaveNames.random(); + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); } slaveNameNode.appendChild(result); @@ -2688,6 +2696,8 @@ App.UI.SlaveInteract.custom = (function() { 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'); @@ -2704,9 +2714,9 @@ App.UI.SlaveInteract.custom = (function() { slave.slaveSurname, v => { slave.slaveSurname = textbox.value; + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" ); label.appendChild(textbox); @@ -2716,9 +2726,9 @@ App.UI.SlaveInteract.custom = (function() { ` Restore ${his} birth surname`, () => { slave.slaveSurname = slave.birthSurname; + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); if (slave.slaveSurname) { @@ -2727,9 +2737,9 @@ App.UI.SlaveInteract.custom = (function() { `Take ${his} surname away`, () => { slave.slaveSurname = 0; + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); } if (slave.relationship >= 5) { @@ -2743,9 +2753,9 @@ App.UI.SlaveInteract.custom = (function() { `Give ${him} ${his} ${wifePronouns.wife}'s surname`, () => { slave.slaveSurname = V.slaves[_i].slaveSurname; + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); break; } @@ -2761,9 +2771,9 @@ App.UI.SlaveInteract.custom = (function() { `Give ${him} your surname`, () => { slave.slaveSurname = V.PC.slaveSurname; + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); } } @@ -2775,9 +2785,9 @@ App.UI.SlaveInteract.custom = (function() { () => { slave.slaveName = setup.romanSlaveNames.random(); slave.slaveSurname = setup.romanSlaveSurnames.random(); + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); } else if (V.arcologies[0].FSAztecRevivalist !== "unset") { result.append(` | `); @@ -2786,9 +2796,9 @@ App.UI.SlaveInteract.custom = (function() { () => { slave.slaveName = setup.aztecSlaveNames.random(); slave.slaveSurname = 0; + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); } else if (V.arcologies[0].FSEgyptianRevivalist !== "unset") { result.append(` | `); @@ -2797,9 +2807,9 @@ App.UI.SlaveInteract.custom = (function() { () => { slave.slaveName = setup.ancientEgyptianSlaveNames.random(); slave.slaveSurname = 0; + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); } else if (V.arcologies[0].FSEdoRevivalist !== "unset") { result.append(` | `); @@ -2808,9 +2818,9 @@ App.UI.SlaveInteract.custom = (function() { () => { slave.slaveName = setup.edoSlaveNames.random(); slave.slaveSurname = setup.edoSlaveSurnames.random(); + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); } if (V.arcologies[0].FSDegradationist > -1) { @@ -2819,14 +2829,18 @@ App.UI.SlaveInteract.custom = (function() { `Give ${him} a degrading full name`, () => { DegradingName(slave); + updateName(slave, {oldName:oldName, oldSurname:oldSurname}); }, false, - "Rename" )); } 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}); + } } function hair(slave) { diff --git a/src/js/SlaveState.js b/src/js/SlaveState.js index 92f35f702d2f61f60101b8c11ff2fd131ffaa698..7a8469dc6fe4b89ee1e84105d53958106b3995ab 100644 --- a/src/js/SlaveState.js +++ b/src/js/SlaveState.js @@ -2507,6 +2507,8 @@ App.Entity.SlaveState = class SlaveState { this.whoreClass = 0; /** Maximum class for whore to target */ this.effectiveWhoreClass = 0; + /** Slave's inbreeding coefficient */ + this.inbreedingCoeff = 0; } /** Creates an object suitable for setting nested attributes as it would be a SlaveState diff --git a/src/js/ibcJS.js b/src/js/ibcJS.js new file mode 100644 index 0000000000000000000000000000000000000000..d1e916f4d49a9fa50ca9343b1ad5b359142887a7 --- /dev/null +++ b/src/js/ibcJS.js @@ -0,0 +1,494 @@ +globalThis.ibc = (() => { + // These IDs are considered to be unknown parents + let or_null = (s) => specificCharacterID(s) ? s : null; + + // Find some sort of state for a slave. Checks first the gene pool, then V.slaves, then the + // missing table + let find_gp = (id) => (slaveStateById(id) || V.genePool.find((s) => s.ID == id) || ((id in V.missingTable) ? V.missingTable[id] : null) || null); + + // Create a node for the given ID + let create_node = (id) => ({ + id: id, // Node ID + mother: null, + father: null, + nodecodes: [], // NodeCodes + nodecodes_str: [], // String version of the NodeCodes, for comparison + _coeff: null, // Cached CoI + child_count: 0 // Number of children of the node, for computing NodeCodes + }); + + // Determine the length of the shared prefix between the two NodeCode parameters + let prefix_len = (nca, ncb) => { + let i = 0; + for (i=0; i<Math.min(nca.length, ncb.length); i++) { + if (nca[i] !== ncb[i]) + break; + } + return i; + }; + + // Determine the set of longest common prefixes for a node pair + let prefixes = (a, b) => { + let found = []; + let found_s = []; + a.nodecodes.forEach(nca => { + let match = false; + b.nodecodes.forEach(ncb => { + let l = prefix_len(nca, ncb); + if (l === 0 && match) + return; + + if (l > 0) { + match = true; + let pfx = nca.slice(0,l); + let pfx_s = pfx.join(';'); + + if (!found_s.includes(pfx_s)) { + found_s.push(pfx_s); + found.push(pfx); + } + } + }); + }); + + return found; + }; + + // Search up the tree to find a given NodeCode, starting at `n` + let find_nc = (nc, n) => { + if (n.nodecodes_str.includes(nc.join(';'))) { + return n; + } + + let ret = null; + if (n.mother !== null) + ret = find_nc(nc, n.mother); + if (n.father !== null && ret === null) + ret = find_nc(nc, n.father); + + return ret; + }; + + // Determine the set of common ancestors between a node pair + let common = (a, b) => { + let pfx = prefixes(a, b); + let pfx_s = pfx.map(s => s.join(';')); + let anc = []; + + while (pfx.length > 0) { + let p = pfx.pop(0); + pfx_s.pop(0); + let ret = find_nc(p, a); + + ret.nodecodes.forEach(nc => { + let i = pfx_s.indexOf(nc.join(';')); + if (i === -1) + return; + + pfx.pop(i); + pfx_s.pop(i); + }); + + if (anc.findIndex(s => (s[0] == ret)) === -1) + anc.push([ret, p]); + } + + return anc; + }; + + // Determine the set of NodeCodes on `n` with prefix `x` + let mps = (n, x) => { + let x_s = x.join(';'); + return n.nodecodes.filter(nc => (nc.slice(0, x.length).join(';') === x_s)); + }; + + // Compute the set of all paths to the parents of `n` with prefix `x` + let pp = (mother, father, x) => { + let m = mps(mother, x); + let f = mps(father, x); + + let prod = []; + m.forEach(i => { + f.forEach(j => { + prod.push([i, j]); + }); + }); + + return prod; + }; + + let kinship = (mother, father) => { + let _coeff = 0; + if (mother === null || father === null) + _coeff = 0; + else if (mother == father) + _coeff = 0.5 * (1 + coeff(mother)); + else { + let cf = 0; + let cmn = common(mother, father); + + cmn.forEach(el => { + let c = el[0]; + let p = el[1]; + let p_s = p.join(';'); + + let paths = pp(mother, father, p); + let paths_s = paths.map(p => [p[0].join(';'), p[1].join(';')].join(',')); + + cmn.forEach(el2 => { + let co = el2[0]; + if (co == c) + return; + let found = []; + let m_pp = []; + let f_pp = []; + + co.nodecodes.forEach(nc => { + if (nc.slice(0, p.length).join(';') != p_s) + return; + + m_pp = m_pp.concat(mps(mother, nc)); + f_pp = f_pp.concat(mps(father, nc)); + }); + + m_pp.forEach(mp => { + f_pp.forEach(fp => { + let mf_s = [mp.join(';'), fp.join(';')].join(','); + let i = paths_s.indexOf(mf_s); + if (i === -1) + return; + paths_s.pop(i); + paths.pop(i); + }); + }); + }); + paths.forEach(p => { + let pfx = prefix_len(p[0], p[1]); + + cf += 0.5**(p[0].length + p[1].length+1 - 2*pfx) * (1 + coeff(c)); + }); + }); + + _coeff = cf; + } + + return _coeff; + }; + + // Determine the coefficient of inbreeding of a node `n` + let coeff = n => { + if (n._coeff === null) + n._coeff = kinship(n.mother, n.father); + return n._coeff; + }; + + // Populate the NodeCodes. + // + // Each node has a set of NodeCodes, which represent the set of paths from it to its ancestors. + // NodeCodes here are represented by arrays of integers. + // + // NodeCodes are constructed recursively in this fashion: + // + // - Assign each of the founders (nodes with both parents === null) an unique ID, starting from + // 0 and incrementing each time (the order doesn't matter); a founder's set of NodeCodes has + // exactly one NodeCode, which is [ID] (an array containing only their ID) + // + // - For each other node, let M be its child number w.r.t. its mother and N its child number + // w.r.t. its father, i.e. the number of children that the respective parent has had before + // this one (the order is not important to the algorithm, it's arbitrary here for + // convenience). Its set of NodeCodes is the set of all its mother's NodeCodes with M appended + // and all of its father's NodeCodes with N appended. For example, if its mother has the + // NodeCodes [[2]] and M = 3 and its father has the NodeCodes [[0,1], [3,1]] and N = 1 then + // the set of NodeCodes for this node would be + // + // [[2, 3], [0, 1, 1], [3, 1, 1]] + // + // We do this iteratively here, looping over the set of all nodes until each has been assigned + // a NodeCode. This requires looping through a number of times equal to the number of + // generations, since as soon as both parents have NodeCodes their children's NodeCodes may be + // computed. + let make_nc = nodes => { + // Generate founder NodeCodes + let total = Object.keys(nodes).length; + let seen = []; + let curid = 0; + Object.values(nodes).forEach(n => { + if (n.mother !== null || n.father !== null) + return; + n.nodecodes.push([curid]); + curid += 1; + seen.push(n.id); + }); + + // Generate the rest of the NodeCodes + while (seen.length != total) { + Object.keys(nodes).forEach(s=> { + let n = nodes[s]; + if (seen.includes(+s)) // We've already done this + return; + else if ((n.mother !== null && n.mother.nodecodes.length === 0) || (n.father !== null && n.father.nodecodes.length === 0)) // Too soon, we haven't done its parents + return; + + seen.push(n.id); + // Compute the NodeCodes from its parents + [n.mother, n.father].forEach((a, i) => { + if (a === null || (n.mother === n.father && i == 1)) // Ignore missing parents/repeated + return; + + a.nodecodes.forEach(nc => { + // Copy the NodeCode, push the child number, then add it + let nnc = nc.slice(); + nnc.push(a.child_count); + n.nodecodes.push(nnc); + }); + a.child_count += 1; + }); + + // NodeCodes must be sorted; this suffices + n.nodecodes.sort() + }); + } + + // Cache the string NodeCodes + Object.values(nodes).forEach(n => { + n.nodecodes_str = n.nodecodes.map(nc => nc.join(';')); + }); + }; + + // Make nodes for an array of slaves + let nodes_slaves = (slaves, ignore_coeffs=false) => { + let nodes = {}; + + // Recursively create the nodes we need, moving upwards from the given slave + let create_node_rec = s => { + // Certain parents (e.g. 0, societal elite) are not considered to be related, despite + // having the same ID; convert them to null + let m = or_null(s.mother); + let f = or_null(s.father); + + // Ensure that parent nodes are created + [m, f].forEach(p => { + if (p !== null && !(p in nodes)) { // Not created, we have to do something + if (p === -1) { + create_node_rec(SugarCube.State.variables.PC); + } else { + // Search for a slave state, genePool entry, or missingTable entry + let gp = find_gp(p); + if (gp !== null) { + // If we find one, we might have ancestry information: recurse + create_node_rec(gp); + } else { + // Otherwise, just create a plain node + nodes[p] = create_node(p); + } + } + } + }); + + if (!(s.ID in nodes)) // Create this node if necessary + nodes[s.ID] = create_node(s.ID); + // We created its parents earlier, so set them to the actual nodes + nodes[s.ID].mother = (m === null) ? m : nodes[m]; + nodes[s.ID].father = (f === null) ? f : nodes[f]; + + // Try to use a cached CoI for performance + let sg = find_gp(s.ID); + if (!ignore_coeffs && sg !== null && "inbreedingCoeff" in sg && sg.inbreedingCoeff !== -1) { + nodes[s.ID]._coeff = sg.inbreedingCoeff; + } + }; + + // Populate the nodes + slaves.forEach(s=> create_node_rec(s)); + + // Populate NodeCodes + make_nc(nodes); + + return nodes; + } + + // Determine the coefficients of inbreeding of an array of slaves. Returns a mapping of their + // ID to their coefficient of inbreeding + let coeff_slaves = (slaves, ignore_coeffs=false) => { + let ret = {}; + // First, pull as many existing CoI off the slaves + slaves.forEach(s => { + let sg = find_gp(s.ID); + if (!ignore_coeffs && sg !== null && "inbreedingCoeff" in sg && sg.inbreedingCoeff !== -1) { + ret[s.ID] = sg.inbreedingCoeff; + } + }); + + // Now do any we haven't done already + slaves = slaves.filter(s => (!(s.ID in ret))); + if (slaves.length > 0) { + let nodes = nodes_slaves(slaves, ignore_coeffs); + + // Compute coefficients + slaves.forEach(s => { + ret[s.ID] = coeff(nodes[s.ID]); + }); + } + + return ret; + }; + + // Determine the kinship between two slaves `a` and `b` + let kinship_slaves = (a, b, ignore_coeffs=false) => { + if (a === 0 || b === 0) + return 0; + + return kinship_one_many(a, [b], ignore_coeffs)[b.ID]; + }; + + // Determine the coefficient of inbreeding of a single slave + let coeff_slave = (slave, ignore_coeffs=false) => { + if (!ignore_coeffs && "inbreedingCoeff" in slave && slave.inbreedingCoeff !== -1) + return slave.inbreedingCoeff; + + let gp = find_gp(slave.ID); + if (!ignore_coeffs && gp !== null && "inbreedingCoeff" in gp && gp.inbreedingCoeff !== -1) + return gp.inbreedingCoeff; + + return coeff_slaves([slave], ignore_coeffs)[slave.ID]; + }; + + // Determine the kinship between one and many slaves. Returns an mapping from the ID of each of + // the slaves in `others` to its kinship with slave `a` + let kinship_one_many = (a, others, ignore_coeffs=false) => { + if (a === 0) { + let ks = {}; + others.forEach(s => { + if (s === 0) + ks[s] = 0; + else + ks[s.ID] = 0; + }); + return ks; + } + + let nodes = nodes_slaves(others.concat([a]), ignore_coeffs); + + let ks = {}; + others.forEach(s => { + if (s === -3) { + // Fake a slave object for the player's old master + s = {ID: -3, mother: 0, father: 0, inbreedingCoeff: 0}; + } + + if (s === 0) + ks[s] = 0; + else + ks[s.ID] = kinship(nodes[a.ID], nodes[s.ID]); + }); + + return ks; + }; + + // Recalculate the inbreeding coefficient for all slaves dependent on the passed IDs (e.g. the + // slaves themselves and all of their children). This will replace the inbreeding coefficients + // wherever they exist with the computed values, ignoring all cached values. + // + // This should be called if parents are changed. + let recalculate_coeff_ids = (ids) => { + // These are all the slave-like objects, i.e. they have ID, mother, and father. There will + // be multiple elements with the same ID: we want this, since we have to replace all + // occurrences of the COI for the affected slaves + let all_slave_like = V.slaves.concat(V.genePool).concat(V.cribs).concat(V.tanks).concat(Object.values(V.missingTable)); + if (V.boomerangSlave !== 0) + all_slave_like.push(V.boomerangSlave); + if (V.traitor !== 0) + all_slave_like.push(V.traitor); + if (V.activeSlave !== 0) + all_slave_like.push(V.activeSlave); + all_slave_like.push(V.PC); + // Add a fake entry for the PC's old master + all_slave_like.push({ID: -3, mother: 0, father: 0, inbreedingCoeff: 0}); + + // Gather the genetics of all current fetuses + let all_fetuses = V.slaves.filter(s => s.preg > 0).map(s => s.womb.map(i => i.genetics)).reduce((res, cur) => res.concat(cur), []); + + // Recursively find all of the given ID's children, born and unborn + let find_children_rec = (id, cur_slaves, cur_fetuses, cur_fetus_parents) => { + // Add fetuses + all_fetuses.filter(f => (f.father === id || f.mother === id)).forEach(f => { + // We may have to manually add the parents later + let actual_f = or_null(f.father); + let actual_m = or_null(f.mother); + if (actual_f !== null) + cur_fetus_parents.add(actual_f); + if (actual_m !== null) + cur_fetus_parents.add(actual_m); + + cur_fetuses.add(f); + }); + + // Recursively add slaves + all_slave_like.filter(s => (s.father === id || s.mother === id)).forEach(s => { + if (!cur_slaves.has(s.ID)) { + cur_slaves.add(s.ID); + find_children_rec(s.ID, cur_slaves, cur_fetuses, cur_fetus_parents); + } + }); + }; + + // We only need slave IDs, since we have to update all of their entries (including GP) + let needed_slave_ids = new Set(); + // Since each fetus has a unique record, a set still suffices + let needed_fetuses = new Set(); + let needed_parent_ids = new Set(); + + // Find all the children of the IDs we need to do + ids.forEach(id => { + needed_slave_ids.add(id); + find_children_rec(id, needed_slave_ids, needed_fetuses, needed_parent_ids); + }); + + // Now we assemble the tree from the slaves + let needed_slaves = []; + needed_slave_ids.forEach(id => { + if (typeof id !== "undefined") + needed_slaves.push(all_slave_like.find(s => s.ID === id)); + }); + needed_parent_ids.forEach(id => { + if (typeof id !== "undefined" && !needed_slave_ids.has(id)) + needed_slaves.push(all_slave_like.find(s => s.ID == id)); + }); + let nodes = nodes_slaves(needed_slaves, true); + + // Now calculate the inbreeding coefficients (they're cached in the tree once calculated) + all_slave_like.filter(s => needed_slave_ids.has(s.ID)).forEach(s => { + s.inbreedingCoeff = coeff(nodes[s.ID]); + }); + + // Finally, handle all of the kinship for the fetuses + let kinship_cache = new Map(); // Manually cache it + needed_fetuses.forEach(f => { + if (or_null(f.mother) === null || or_null(f.father) === null) { + f.inbreedingCoeff = 0; + return; + } + + // Use a string of the form "parent;parent" to store the cache value; since kinship is + // commutative, the minumum parent ID will be first + let kinship_str = Math.min(f.mother, f.father) + ';' + Math.max(f.mother, f.father); + if (!kinship_cache.has(kinship_str)) + kinship_cache.set(kinship_str, kinship(nodes[f.mother], nodes[f.father])); + + f.inbreedingCoeff = kinship_cache.get(kinship_str); + }); + }; + + let recalculate_coeff_id = (id) => { + return recalculate_coeff_ids([id]); + }; + + return { + coeff: coeff_slave, + coeff_slaves, + kinship: kinship_slaves, + kinship_one_many, + recalculate_coeff_ids, + recalculate_coeff_id + }; +})(); diff --git a/src/js/removeActiveSlave.js b/src/js/removeActiveSlave.js index 95ea18e2bda23cc26107f1a28c8f14fe641dbe28..eb32e2872f8dede7976205ae5c0deca11ca5f9c8 100644 --- a/src/js/removeActiveSlave.js +++ b/src/js/removeActiveSlave.js @@ -197,6 +197,10 @@ globalThis.removeActiveSlave = function() { V.genePool.deleteAt(_geneIndex); } } + Object.values(V.missingTable).forEach(s => { + if (s.mother === V.activeSlave.ID || s.father === V.activeSlave.ID) + missing = true; + }); if (missing) { V.missingTable[V.missingParentID] = { slaveName: V.activeSlave.slaveName, @@ -204,7 +208,10 @@ globalThis.removeActiveSlave = function() { fullName: SlaveFullName(V.activeSlave), dick: V.activeSlave.dick, vagina: V.activeSlave.vagina, - ID: V.missingParentID + ID: V.missingParentID, + mother: V.activeSlave.mother, + father: V.activeSlave.father, + inbreedingCoeff: V.activeSlave.inbreedingCoeff }; if (V.traitor.ID === V.activeSlave.ID) { /* To link developing fetuses to their parent */ @@ -212,6 +219,12 @@ globalThis.removeActiveSlave = function() { } else if (V.boomerangSlave.ID === V.activeSlave.ID) { V.boomerangSlave.missingParentTag = V.missingParentID; } + Object.values(V.missingTable).forEach(s => { + if (s.mother === V.activeSlave.ID) + s.mother = V.missingParentID; + if (s.father === V.activeSlave.ID) + s.father = V.missingParentID; + }); V.missingParentID--; } @@ -310,6 +323,10 @@ globalThis.removeNonNGPSlave = function(removedSlave) { V.genePool.deleteAt(_geneIndex); } } + Object.values(V.missingTable).forEach(s => { + if (s.mother == removedSlave.ID || s.father == removedSlave.ID) + missing = true; + }); if (missing) { V.missingTable[V.missingParentID] = { slaveName: removedSlave.slaveName, @@ -317,8 +334,17 @@ globalThis.removeNonNGPSlave = function(removedSlave) { fullName: SlaveFullName(removedSlave), dick: removedSlave.dick, vagina: removedSlave.vagina, - ID: V.missingParentID + ID: V.missingParentID, + mother: removedSlave.mother, + father: removedSlave.father, + inbreedingCoeff: removedSlave.inbreedingCoeff }; + Object.values(V.missingTable).forEach(s => { + if (s.mother === removedSlave.ID) + s.mother = V.missingParentID; + if (s.father === removedSlave.ID) + s.father = V.missingParentID; + }); V.missingParentID--; } diff --git a/src/js/wombJS.js b/src/js/wombJS.js index e560f361fc5fd2203a9f1c90ca2f05c82b345c3d..2cdf98b6a0ff14da877cc76498f9ba6f798a83f0 100644 --- a/src/js/wombJS.js +++ b/src/js/wombJS.js @@ -94,6 +94,14 @@ globalThis.WombInit = function(actor) { WombImpregnate(actor, bLeft, actor.pregSource, i + 1); // setting up leftover of fetuses. } } + + actor.womb.forEach(f => { + if (!jsDef(f.genetics.inbreedingCoeff)) { + f.genetics.inbreedingCoeff = ibc.coeff( + {ID: null, mother: f.genetics.mother, father: f.genetics.father} + ); + } + }); }; globalThis.WombImpregnate = function(actor, fCount, fatherID, age, surrogate) { diff --git a/src/npc/acquisition.tw b/src/npc/acquisition.tw index ebb7ec3198702510af01eb6f78bb89c73570b508..59d74203b7f14caa28fdeefecbd4318be3e3abd2 100644 --- a/src/npc/acquisition.tw +++ b/src/npc/acquisition.tw @@ -178,6 +178,23 @@ <<set $missingParentID-->> <</if>> <</for>> +<<set _coeffSlaves = []>> +<<set _genePoolMap = {}>> +<<for _i = 0; _i < $genePool.length; _i++>> + <<set _genePoolMap[$genePool[_i].ID] = $genePool[_i]>> +<</for>> +<<for _i = 0; _i < $slaves.length; _i++>> + <<if $slaves[_i].newGamePlus == 0>> + <<set $slaves[_i].inbreedingCoeff = -1>> + <<set _genePoolMap[$slaves[_i].ID].inbreedingCoeff = -1>> + <<run _coeffSlaves.push($slaves[_i])>> + <</if>> +<</for>> +<<set _ibcoeffs = ibc.coeff_slaves(_coeffSlaves)>> +<<for _i = 0; _i < _coeffSlaves.length; _i++>> + <<set _coeffSlaves[_i].inbreedingCoeff = _ibcoeffs[_coeffSlaves[_i].ID]>> + <<set _genePoolMap[_coeffSlaves[_i].ID].inbreedingCoeff = _ibcoeffs[_coeffSlaves[_i].ID]>> +<</for>> <<if $plot == 1 && $neighboringArcologies > 0>> <<set _bestProsperity = 0, _bestProsperityIndex = 1>> <<for _acq = 1; _acq < $arcologies.length; _acq++>> diff --git a/src/npc/generate/generateGenetics.js b/src/npc/generate/generateGenetics.js index 431f2c1aac1cc0e9f49dc93f1a293f5f57910a68..8e119e198680560dd547a20b25a3da46e4c205ec 100644 --- a/src/npc/generate/generateGenetics.js +++ b/src/npc/generate/generateGenetics.js @@ -97,12 +97,13 @@ globalThis.generateGenetics = (function() { genes.motherName = setMotherName(activeMother); genes.father = setFatherID(actor2); genes.fatherName = setFatherName(father, activeFather, actor2); + genes.inbreedingCoeff = ibc.kinship(mother, father); genes.nationality = setNationality(father, mother); genes.geneticQuirks = setGeneticQuirks(activeFather, activeMother, genes.gender); genes.skin = setSkin(father, mother, actor2); genes.race = setRace(father, mother, actor2); - genes.intelligence = setIntelligence(father, mother, activeMother, actor2); - genes.face = setFace(father, mother, activeMother, actor2, genes.geneticQuirks); + genes.intelligence = setIntelligence(father, mother, activeMother, actor2, genes.inbreedingCoeff); + genes.face = setFace(father, mother, activeMother, actor2, genes.geneticQuirks, genes.inbreedingCoeff); genes.faceShape = setFaceShape(father, mother, genes.geneticQuirks); genes.eyeColor = setEyeColor(father, mother, actor2); if (genes.geneticQuirks.heterochromia === 2) { @@ -592,7 +593,7 @@ globalThis.generateGenetics = (function() { } // intelligence - function setIntelligence(father, mother, activeMother, actor2) { + function setIntelligence(father, mother, activeMother, actor2, inbreedingCoeff) { let smarts; if (mother.ID === -1) { if (actor2 === -6) { @@ -616,29 +617,15 @@ globalThis.generateGenetics = (function() { smarts = mother.intelligence; } if (V.inbreeding === 1) { - if (mother.ID !== -1) { - if (father !== 0 && father.ID === -1 && activeMother.breedingMark !== 1) { - if (smarts >= -95 && jsRandom(1, 100) < 40) { - smarts -= jsRandom(1, 10); - if (smarts >= -95 && jsRandom(1, 100) < 20) { - smarts -= jsRandom(1, 5); - } - } - } else { - if (smarts >= -95 && jsRandom(1, 100) < 50) { - smarts -= jsRandom(1, 15); - if (smarts >= -95 && jsRandom(1, 100) < 30) { - smarts -= jsRandom(1, 15); - } - } - } + if (jsRandom(1, 100) < inbreedingCoeff*200) { + smarts -= Math.abs(normalRandInt(5*inbreedingCoeff, 30*inbreedingCoeff, -100*inbreedingCoeff, 100*inbreedingCoeff)); } } return Math.clamp(smarts, -100, 100); } // face - function setFace(father, mother, activeMother, actor2, genes) { + function setFace(father, mother, activeMother, actor2, genes, inbreedingCoeff) { let face; if (genes.pFace > 0 && genes.uFace > 0) { face = 0; @@ -668,19 +655,8 @@ globalThis.generateGenetics = (function() { face = mother.face; } if (V.inbreeding === 1 && genes.pFace === 0 && genes.uFace === 0) { - if (mother.ID !== -1) { - if (father !== 0 && father.ID === -1 && activeMother.breedingMark !== 1) { - if (face > -100 && jsRandom(1, 100) > 60) { - face -= jsRandom(2, 20); - } - } else { - if (face > -100 && jsRandom(1, 100) < 50) { - face -= jsRandom(1, 15); - if (face >= -95 && jsRandom(1, 100) < 30) { - face -= jsRandom(5, 20); - } - } - } + if (jsRandom(1, 100) < inbreedingCoeff*200) { + face -= Math.abs(normalRandInt(5*inbreedingCoeff, 35*inbreedingCoeff, -100*inbreedingCoeff, 100*inbreedingCoeff)); } } return Math.clamp(face, -100, 100); @@ -1367,6 +1343,8 @@ globalThis.generateChild = function (mother, ovum, incubator=false) { child.navelPiercing = 0; } + child.inbreedingCoeff = genes.inbreedingCoeff; + generatePronouns(child); return child; diff --git a/src/npc/interaction/passage/fSlaveImpreg.tw b/src/npc/interaction/passage/fSlaveImpreg.tw index efd9b39178182e8794ae0d2890019ccb074e2283..e81aeecbf96434e8e1bc6c62cf0954fde2b27012 100644 --- a/src/npc/interaction/passage/fSlaveImpreg.tw +++ b/src/npc/interaction/passage/fSlaveImpreg.tw @@ -10,6 +10,7 @@ <h3>Select an eligible slave to serve as the semen donatrix</h3> <<set _eligibles = $slaves.filter((s) => (s.ID != getSlave($AS).ID) && canImpreg(getSlave($AS), s) && canPenetrate(s))>> +<<set _kinship = ibc.kinship_one_many(getSlave($AS), _eligibles)>> <<for _i = 0; _i < _eligibles.length; _i++>> <<set _name = SlaveFullName(_eligibles[_i])>> <div> @@ -23,6 +24,21 @@ @@.lightgreen;<<= capFirstChar(_relTerm)>>@@ <</if>> <</if>> /* closes extended family mode */ + <<if $inbreeding && _kinship[_eligibles[_i].ID] > 0>> + <<set _thisKinship = _kinship[_eligibles[_i].ID]>> + <<if _thisKinship >= 0.5>> + (Extreme + <<elseif _thisKinship >= 0.25>> + (Major + <<elseif _thisKinship >= 0.125>> + (Some + <<elseif _thisKinship >= 0.0625>> + (Minor + <<else>> + (Slight + <</if>> + inbreeding, CoI of <<print _thisKinship>>) + <</if>> </div> <</for>> <<if (_eligibles.length === 0)>> diff --git a/src/npc/interaction/rename.tw b/src/npc/interaction/rename.tw deleted file mode 100644 index f6a7679c4d8216239c2f5cb1d2c272a11c20923c..0000000000000000000000000000000000000000 --- a/src/npc/interaction/rename.tw +++ /dev/null @@ -1,140 +0,0 @@ -:: Rename [nobr] - -<<set $nextButton = "Back", $nextLink = "Slave Interact">> -<<set $AS = $activeSlave.ID>> - -<<if getSlave($AS).slaveName === $oldName && getSlave($AS).slaveSurname === $oldSurname>> - <<goto "Slave Interact">> -<<else>> -/* First time renaming reaction */ -<<if getSlave($AS).slaveName === "" || ndef getSlave($AS).slaveName>> - $oldName needs to be called something on the records, so $oldName $he stays. - <<set getSlave($AS).slaveName = $oldName>> -<<elseif getSlave($AS).fetish == "mindbroken">> - <<= getSlave($AS).slaveName>> doesn't even recognize that $he's been renamed. It simply does not register. -<<elseif ($oldName != getSlave($AS).birthName && getSlave($AS).slaveName == getSlave($AS).birthName) || ($oldSurname != getSlave($AS).birthSurname && getSlave($AS).slaveSurname == getSlave($AS).birthSurname)>> - <<= getSlave($AS).slaveName>> - <<if getSlave($AS).devotion > 50>> - cheerfully accepts $his old name back. - <<elseif getSlave($AS).devotion >= -20>> - obediently accepts $his old name back. - <<elseif getSlave($AS).devotion >= -50>> - happily accepts $his original name. - <<elseif getSlave($AS).trust > 20>> - scoffs at the notion that $he was ever anything other than <<= SlaveFullBirthName(getSlave($AS))>>, @@.orangered;weakening your control over $him.@@ - <<set getSlave($AS).trust += 5>> - <<else>> - cautiously accepts the return of $his name. - <</if>> -<<elseif ($oldName == getSlave($AS).birthName && getSlave($AS).slaveName != getSlave($AS).birthName) || ($oldSurname == getSlave($AS).birthSurname && getSlave($AS).slaveSurname != getSlave($AS).birthSurname)>> - <<= getSlave($AS).slaveName>> - <<if getSlave($AS).devotion > 50>> - accepts $his new name cheerfully. This attachment to you @@.hotpink; increases $his devotion.@@ - <<set getSlave($AS).devotion += 4>> - <<elseif getSlave($AS).devotion >= -20>> - obediently accepts $his new name. This surrender to you @@.hotpink; increases $his obedience.@@ - <<set getSlave($AS).devotion += 4>> - <<elseif getSlave($AS).devotion >= -50>> - reluctantly accepts $his new name. - <<else>> - angrily tries to resist $his new name, insisting that $his name is <<= SlaveFullBirthName(getSlave($AS))>>. This resistance @@.mediumorchid; increases $his rebelliousness.@@ - <<set getSlave($AS).devotion -= 5>> - <</if>> -<<else>> - Since <<= getSlave($AS).slaveName>> has already had a new name <<if getSlave($AS).devotion > 20>>given to<<else>>forced on<</if>> $him before, the mere fact of having it changed again doesn't really affect $him. -<</if>> - -<<set _insultingName = 0>> -<<if $oldName != getSlave($AS).slaveName && typeof getSlave($AS).slaveName == "string">> - <<set _toSearch = getSlave($AS).slaveName.toLowerCase()>> - <<for $i = 0; $i < setup.badWords.length; $i++>> - <<if _toSearch.indexOf(setup.badWords[$i]) != -1>> - <<set _insultingName = 1>> - <<break>> - <</if>> - <</for>> -<</if>> -<<if !_insultingName>> - <<if $oldSurname != getSlave($AS).slaveSurname && typeof getSlave($AS).slaveSurname == "string">> - <<set _toSearch = getSlave($AS).slaveSurname.toLowerCase()>> - <<for $i = 0; $i < setup.badWords.length; $i++>> - <<if _toSearch.indexOf(setup.badWords[$i]) != -1>> - <<set _insultingName = 1>> - <<break>> - <</if>> - <</for>> - <</if>> -<</if>> -<<if _insultingName == 1>> - <<if getSlave($AS).fetish == "mindbroken">> - $His new name would be insulting to a normal $girl, but $he dully accepts that it is an accurate description and goes about $his duties. - <<elseif getSlave($AS).devotion < -50>> - Being given such a degrading name @@.mediumorchid;further increases $his hatred@@ of you. - <<set getSlave($AS).devotion -= 5>> - <<elseif getSlave($AS).devotion <= 50>> - Being given such a degrading name @@.gold;terrifies $him,@@ since $he thinks it's fair warning for what $he'll suffer in the future. - <<set getSlave($AS).trust -= 5>> - <</if>> -<</if>> - -/* Wife's surname reaction */ -<<if $oldSurname != getSlave($AS).slaveSurname>> - <<if getSlave($AS).relationship >= 5>> - <<set _i = $slaveIndices[getSlave($AS).relationshipTarget]>> - <<if ndef _i>>@@.red;Error, relationshipTarget not found.@@<</if>> - <<if $slaves[_i].slaveSurname>> - <<setLocalPronouns $slaves[_i] 2>> - <<if getSlave($AS).slaveSurname == $slaves[_i].slaveSurname>> - $He's touched that $he now shares a surname with $his _wife2 $slaves[_i].slaveName $slaves[_i].slaveSurname, and is @@.mediumaquamarine;more confident than ever@@ that you intend to keep them together in marital bliss. - <<set getSlave($AS).trust += 5>> - <<elseif $oldSurname == $slaves[_i].slaveSurname>> - $He's concerned that $he no longer shares a surname with $his _wife2 $slaves[_i].slaveName $slaves[_i].slaveSurname, and is @@.gold;very worried@@ that you might be considering splitting them up. - <<set getSlave($AS).trust -= 5>> - <</if>> - <</if>> - <</if>> -<</if>> - -/* PC's surname reaction */ -<<if $oldSurname != getSlave($AS).slaveSurname>> - <<if getSlave($AS).relationship == -3>> - <<if $PC.slaveSurname>> - <<if getSlave($AS).fetish == "mindbroken">> - Names are meaningless to $him and it is unlikely $he'll remember it. - <<elseif getSlave($AS).devotion+getSlave($AS).trust >= 175>> - <<if getSlave($AS).slaveSurname == $PC.slaveSurname>> - When you tell $him that $he's to be known as <<= getSlave($AS).slaveName>> <<= getSlave($AS).slaveSurname>> now, $he starts to cry. $He tries to get $himself under control and thank you as best $he can, <<if hasAnyArms(getSlave($AS))>>wiping at the tears running down $his <<= getSlave($AS).skin>> cheeks, <</if>>but $he can't seem to stop weeping as $he thanks you over and over. $He's a sex slave, your property, and it's understandable that some doubts about the permanence of $his place as your slave $wife. This has @@.mediumaquamarine;helped reassure $him,@@ and explains the strength of $his emotional reaction. The next time you make love to $him, $he @@.hotpink;presses $himself as close to you as $he can,@@ eager to drink in as much of your presence as $he can get. - <<set getSlave($AS).devotion += 5, getSlave($AS).trust += 5>> - <<elseif $oldSurname == $PC.slaveSurname>> - $He's devastated that you'd rename $him something other than your name. $He's @@.gold;terrified@@ that you intend to discard $him as your slave $wife, and @@.mediumorchid;saddened@@ that you would take away something that was precious to $him. - <<set getSlave($AS).devotion -= 5, getSlave($AS).trust -= 5>> - <</if>> - <<elseif getSlave($AS).devotion < -20 && getSlave($AS).trust > 20>> - <<if getSlave($AS).slaveSurname == $PC.slaveSurname>> - When you tell $him that $he's to be known as <<= getSlave($AS).slaveName>> <<= getSlave($AS).slaveSurname>> now, $he shows no reaction. You already took everything from $him, what's a name at this point? - <<elseif $oldSurname == $PC.slaveSurname>> - $He doesn't care about losing your surname at first, but it quickly sets in that $he may have @@.gold;pushed $his position too far.@@ - <<set getSlave($AS).trust -= 20>> - <</if>> - <<elseif getSlave($AS).devotion < -20>> - <<if getSlave($AS).slaveSurname == $PC.slaveSurname>> - When you tell $him that $he's to be known as <<= getSlave($AS).slaveName>> <<= getSlave($AS).slaveSurname>> now, $he pleads with you not to steal $his name. It matters little to you, and $he is forced to @@.hotpink;accept your will.@@ - <<set getSlave($AS).devotion += 5>> - <<elseif $oldSurname == $PC.slaveSurname>> - $He's @@.mediumorchid;happy@@ to no longer have to share a name with $his tormentor, but the bliss doesn't last long as @@.gold;dread@@ quickly sets in about what this may mean. - <<set getSlave($AS).devotion += 5, getSlave($AS).trust -= 10>> - <</if>> - <<else>> - <<if getSlave($AS).slaveSurname == $PC.slaveSurname>> - When you tell $him that $he's to be known as <<= getSlave($AS).slaveName>> <<= getSlave($AS).slaveSurname>> now, $he nods with approval feeling @@.mediumaquamarine;that $he may hold at least some value in your eyes.@@ - <<set getSlave($AS).trust += 5>> - <<elseif $oldSurname == $PC.slaveSurname>> - $He accepts that you'd rename $him something other than your name. $He's @@.gold;a little scared@@ that you intend to discard $him as your slave $wife, or worse, but realizes this was not only a possibility, but likely. - <<set getSlave($AS).trust -= 5>> - <</if>> - <</if>> - <</if>> - <</if>> -<</if>> - -<</if>> /* close new name check */ diff --git a/src/player/js/PlayerState.js b/src/player/js/PlayerState.js index 4efbdaf320adf2e8d164496d3c6f4216be6eab5f..fe3b61163ee21ecd9c20c22885b90b8f8fec363c 100644 --- a/src/player/js/PlayerState.js +++ b/src/player/js/PlayerState.js @@ -1991,6 +1991,8 @@ App.Entity.PlayerState = class PlayerState { * * 0: no; 1: yes */ this.staminaPills = 0; + /** Player's coefficient of inbreeding */ + this.inbreedingCoeff = 0; } /** Creates an object suitable for setting nested attributes as it would be a SlaveState diff --git a/src/pregmod/widgets/bodyswapWidgets.tw b/src/pregmod/widgets/bodyswapWidgets.tw index ee9c226b664eca66be129389643e7659a3df1411..4a1ed4eeac6e86a66b17cdfda37e3e0ba63d4cd4 100644 --- a/src/pregmod/widgets/bodyswapWidgets.tw +++ b/src/pregmod/widgets/bodyswapWidgets.tw @@ -164,6 +164,7 @@ <<set $args[0].albinismOverride = $args[1].albinismOverride>> <<set $args[0].clone = $args[1].clone>> <<set $args[0].cloneID = $args[1].cloneID>> +<<set $args[0].inbreedingCoeff = $args[1].inbreedingCoeff>> <<set $args[0].canRecruit = 0>> diff --git a/src/uncategorized/nextWeek.tw b/src/uncategorized/nextWeek.tw index 25f8249827c013185df19ac7747724b752bc9624..262c4c606437daec3162e5aa103526bf9be78fbc 100644 --- a/src/uncategorized/nextWeek.tw +++ b/src/uncategorized/nextWeek.tw @@ -348,7 +348,7 @@ <<set $beforeGingering = null>> /% Strings Memory varies. %/ -<<set $buyer = "", $desc = "", $event = "", $goto = "", $malefactor = "", $oldName = "", $oldSurname = "">> +<<set $buyer = "", $desc = "", $event = "", $goto = "", $malefactor = "">> /% Done with zeroing out, what should be for the most part Temps %/ <<if $autosave != 0>>