diff --git a/src/004-base/facility.js b/src/004-base/facility.js index 779bdfa2d955f9e4a43822c144f58ffc60344cbb..26f7eff13e2c4f0abe06f8015468de96db7b70f4 100644 --- a/src/004-base/facility.js +++ b/src/004-base/facility.js @@ -454,7 +454,7 @@ App.Entity.Facilities.Facility = class { if (jobArray.length === 1) { return jobArray[0].employees(); } - return V.slaves.filter(s => jobArray.some(j => j.isEmployed(s))); + return [].concat(...jobArray.map(j => j.employees())); } /** @@ -462,9 +462,9 @@ App.Entity.Facilities.Facility = class { * @returns {Set<number>} */ employeesIDs() { - const jobArray = Object.values(this._jobs); + const jobArray = this.jobs; if (jobArray.length === 1) { - return this.job().employeesIDs(); + return jobArray[0].employeesIDs(); } const res = new Set(); for (const j of jobArray) { diff --git a/src/endWeek/brothelReport.js b/src/endWeek/brothelReport.js index 852fd941bb951196dc1f70af88d2920755e11b7e..a2bc80d7005478afb69c74f6a1cb97fd79bea695 100644 --- a/src/endWeek/brothelReport.js +++ b/src/endWeek/brothelReport.js @@ -348,7 +348,7 @@ App.EndWeek.brothelReport = function() { App.SlaveAssignment.standardSlaveReport(slave, false) ], "div", - "indented" + "indent" ); } else { // discard return values silently diff --git a/src/endWeek/economics/neighborsDevelopment.js b/src/endWeek/economics/neighborsDevelopment.js index 8cd90356276c24740afa0b13f93f9ce2ad469307..7a6d2a912b656f46c361f206dc3864a0310d6049 100644 --- a/src/endWeek/economics/neighborsDevelopment.js +++ b/src/endWeek/economics/neighborsDevelopment.js @@ -2581,7 +2581,7 @@ App.EndWeek.neighborsDevelopment = function() { r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Gender Radicalism,</span> since ${he}'s a walking, swinging argument for dickgirls.`); arc.FSGenderRadicalist = 5; return; - } else if (validFSes.includes("FSGenderFundamentalist") && leader.pregKnown === 1 || leader.bellyPreg > 1500) { + } else if (validFSes.includes("FSGenderFundamentalist") && (leader.pregKnown === 1 || leader.bellyPreg > 1500)) { r.push(`Your agent <span class="pink">${leader.slaveName}</span> successfully pushes it to <span class="yellow">adopt Gender Fundamentalism,</span> since its citizens find leadership by a pregnant ${woman} fascinating.`); arc.FSGenderFundamentalist = 5; return; diff --git a/src/endWeek/reports/arcadeReport.js b/src/endWeek/reports/arcadeReport.js index 10c07796e885162a81ccaec9785ee7b5e2e37199..4f0320b1402584589ef1aa5c7c250bacff1ab348 100644 --- a/src/endWeek/reports/arcadeReport.js +++ b/src/endWeek/reports/arcadeReport.js @@ -98,7 +98,7 @@ App.EndWeek.arcadeReport = function() { App.SlaveAssignment.workAGloryHole(slave), ], "div", - "indented" + "indent" ); } else { // discard return values silently @@ -127,7 +127,9 @@ App.EndWeek.arcadeReport = function() { } else if (slave.lactation > 0 || slave.balls > 0) { milkResults = App.SlaveAssignment.getMilked(slave, 1.0); if (V.showEWD !== 0) { + r = []; r.push(App.UI.DOM.makeElement("div", `${He} ${milkResults.text}`, "indent")); + App.Events.addNode(el, r, "div", "indent"); } milkProfits += milkResults.cash; growth = 0; @@ -173,7 +175,6 @@ App.EndWeek.arcadeReport = function() { if (slave.inflation > 0) { deflate(slave); } - App.Events.addNode(el, r, "div", "indent"); if (V.showEWD !== 0) { el.append(App.SlaveAssignment.standardSlaveReport(slave, false)); } else { diff --git a/src/endWeek/reports/clubReport.js b/src/endWeek/reports/clubReport.js index 43fc5b9da180c6d17bb599b76ede4c7301ad8cc5..a17b960a166ea0e8f978b4f13c6a895ef17941b4 100644 --- a/src/endWeek/reports/clubReport.js +++ b/src/endWeek/reports/clubReport.js @@ -214,7 +214,7 @@ App.EndWeek.clubReport = function() { App.SlaveAssignment.standardSlaveReport(slave, false) ], "div", - "indented" + "indent" ); } else { // discard return values silently @@ -224,7 +224,7 @@ App.EndWeek.clubReport = function() { } } - App.Events.addNode(el, [App.Ads.report("club")], "p", "indented"); + App.Events.addNode(el, [App.Ads.report("club")], "p", "indent"); // Record statistics gathering const b = V.facility.club; @@ -250,7 +250,7 @@ App.EndWeek.clubReport = function() { `${capFirstChar(V.clubName)}'s customers enjoy <span class="green">having sex in ${V.clubDecoration} surroundings.</span>` ], "p", - "indented" + "indent" ); } diff --git a/src/endWeek/reports/penthouseReport.js b/src/endWeek/reports/penthouseReport.js index 4fe45ac6892c36bd6d571bc595ddad5758b5b1ef..bfc2e5e8d508abdba50cec15fbf92cd94ecc820d 100644 --- a/src/endWeek/reports/penthouseReport.js +++ b/src/endWeek/reports/penthouseReport.js @@ -182,7 +182,7 @@ App.EndWeek.penthouseReport = function() { } } - r.push(`<div class="indent">${App.SlaveAssignment.devotion(slave)}</span>`); + r.push(`<div class="indent">${App.SlaveAssignment.devotion(slave)}</div>`); App.Events.addNode(el, r); return el; } diff --git a/src/endWeek/saLiveWithHG.js b/src/endWeek/saLiveWithHG.js index 694ee34223f28ea95f562142e6c8f9fad3f87846..2e6b5d27777e4581746bed545b083eac9a068071 100644 --- a/src/endWeek/saLiveWithHG.js +++ b/src/endWeek/saLiveWithHG.js @@ -1628,7 +1628,7 @@ App.SlaveAssignment.liveWithHG = (function() { const content = App.UI.DOM.makeElement("div", '', "indent"); $(content).append( ...App.Events.spaceSentences(App.SlaveAssignment.individualSlaveReport(slave)), - `<div class="indent">${App.SlaveAssignment.devotion(slave)}</span>`); + `<div class="indent">${App.SlaveAssignment.devotion(slave)}</div>`); r.push(content); } } diff --git a/src/endWeek/saRelationships.js b/src/endWeek/saRelationships.js index 4f5b92ae7c5d273f2c5a67bc36d713eb5e35ede6..2fa47bd4136b865d927f72b97694b5c5429a68ae 100644 --- a/src/endWeek/saRelationships.js +++ b/src/endWeek/saRelationships.js @@ -1177,34 +1177,154 @@ App.SlaveAssignment.relationships = (function() { * */ function familyFeelings(slave) { + /** @param {Map<string, Array<App.Entity.SlaveState>>} map + * @param {App.Entity.SlaveState} relative */ + function addToRelativeMap(map, relative) { + const term = relativeTerm(slave, relative); + if (!map.has(term)) { + map.set(term, [relative]); + } else { + map.get(term).push(relative); + } + } + + /** @param {Map<string, Array<App.Entity.SlaveState>>} map + * @returns {Array<string>} */ + function relativeMapToGroupArray(map) { + let groups = []; + for (const [type, people] of map) { + if (people.length > 1) { + groups.push(`${his} ${type}s ${arrayToSentence(people.map(s => s.slaveName))}`); + } else { + groups.push(`${his} ${type} ${people[0].slaveName}`); + } + } + return groups; + } + + /** @param {Map<string, Array<App.Entity.SlaveState>>} map + * @returns {App.Entity.SlaveState} */ + function singleRelativeInMap(map) { + if (map.size !== 1) { + return null; + } + /** @type {App.Entity.SlaveState[]} */ + const slavesOfType = map.values().next().value; + if (slavesOfType.length !== 1) { + return null; + } + return slavesOfType[0]; + } + + /** @param {Map<string, Array<App.Entity.SlaveState>>} map + * @returns {number} */ + function relativeMapTotalSize(map) { + let size = 0; + for (const people of map.values()) { + size += people.length; + } + return size; + } + + const overwhelmed = 5; if (slave.trust <= 95) { - let relatives = V.slaves.filter((s) => areRelated(slave, s)); // Is it possible to move this into the loop? - for (const relative of relatives) { - const {he2, him2} = getPronouns(relative).appendSuffix("2"); - if (slave.trust < -20) { + let relatives = V.slaves.filter((s) => areRelated(slave, s)); + if (slave.trust < -20) { + /** @type {Array<App.Entity.SlaveState>} */ + const worriedAboutChildren = []; + /** @type {Map<string, Array<App.Entity.SlaveState>>} */ + const worriedAboutRelatives = new Map(); + for (const relative of relatives) { if (slave.rivalryTarget !== relative.ID) { if (isParentP(relative, slave)) { - r.push(`${slave.slaveName} is <span class="trust dec">agonizingly aware</span> that ${his} child ${relative.slaveName} is also your slave and might suffer if either of them angers you, and <span class="devotion inc">does ${his} best</span> to protect ${him2}.`); - slave.trust -= 2; - slave.devotion += 6; + worriedAboutChildren.push(relative); + if (worriedAboutChildren.length <= overwhelmed) { + slave.trust -= 2; + slave.devotion += 6; + } } else { - r.push(`${slave.slaveName} is <span class="trust dec">painfully conscious</span> that ${his} ${relativeTerm(slave, relative)} ${relative.slaveName} is also your slave and might suffer if either of them displeases you, and <span class="devotion inc">tries to obey</span> as best ${he} can.`); - slave.trust -= 1; - slave.devotion += 3; + addToRelativeMap(worriedAboutRelatives, relative); + if (relativeMapTotalSize(worriedAboutRelatives) <= overwhelmed) { + slave.trust -= 1; + slave.devotion += 3; + } } } - } else { - r.push(`${slave.slaveName} knows that ${his} ${relativeTerm(slave, relative)} ${relative.slaveName}`); + } + if (worriedAboutChildren.length > 1) { + r.push(`${slave.slaveName} is <span class="trust dec">agonizingly aware</span> that ${his} children ${arrayToSentence(worriedAboutChildren.map(s => s.slaveName))} are also your slaves and might suffer if any of them angers you, and <span class="devotion inc">does ${his} best</span> to protect them.`); + } else if (worriedAboutChildren.length > 0) { + const {him2} = getPronouns(worriedAboutChildren[0]).appendSuffix("2"); + r.push(`${slave.slaveName} is <span class="trust dec">agonizingly aware</span> that ${his} child ${worriedAboutChildren[0].slaveName} is also your slave and might suffer if either of them angers you, and <span class="devotion inc">does ${his} best</span> to protect ${him2}.`); + } + if (worriedAboutChildren.length > overwhelmed) { + r.push(`${He} has so many children to worry about that ${he} is overwhelmed with fear and <span class="trust inc">forced to trust you.</span>`); + } + let singleRelative = singleRelativeInMap(worriedAboutRelatives); + if (singleRelative) { + r.push(`${slave.slaveName} is <span class="trust dec">painfully conscious</span> that ${his} ${relativeTerm(slave, singleRelative)} ${singleRelative.slaveName} is also your slave and might suffer if either of them displeases you, and <span class="devotion inc">tries to obey</span> as best ${he} can.`); + } else if (worriedAboutRelatives.size > 0) { + const groups = relativeMapToGroupArray(worriedAboutRelatives); + r.push(`${slave.slaveName} is <span class="trust dec">painfully conscious</span> that ${arrayToSentence(groups)} are also your slaves and might suffer if any of them displeases you, and <span class="devotion inc">tries to obey</span> as best ${he} can.`); + } + if (relativeMapTotalSize(worriedAboutRelatives) > overwhelmed) { + r.push(`${He} has so many relatives to worry about that ${he} is overwhelmed with fear and <span class="trust inc">forced to trust you.</span>`); + } + } else { + /** @type {Map<string, Array<App.Entity.SlaveState>>} */ + const devotedRelatives = new Map(); + /** @type {Map<string, Array<App.Entity.SlaveState>>} */ + const obedientRelatives = new Map(); + /** @type {Map<string, Array<App.Entity.SlaveState>>} */ + const hatefulRelatives = new Map(); + for (const relative of relatives) { if (relative.devotion > 50) { - r.push(`loves being your sex slave, and is <span class="devotion inc">happy</span> for ${him2}.`); - slave.devotion += 4; + addToRelativeMap(devotedRelatives, relative); + if (relativeMapTotalSize(devotedRelatives) <= overwhelmed) { + slave.devotion += 4; + } } else if (relative.devotion > 20 || relative.trust < -20) { - r.push(`is an obedient sex slave, and hopes ${he2}'ll avoid punishment.`); + addToRelativeMap(obedientRelatives, relative); } else { - r.push(`hates being a sex slave, and is <span class="trust dec">afraid</span> for ${him2}.`); - slave.trust -= 1; + addToRelativeMap(hatefulRelatives, relative); + if (relativeMapTotalSize(hatefulRelatives) <= overwhelmed) { + slave.trust -= 1; + } } } + let singleRelative = singleRelativeInMap(devotedRelatives); + if (singleRelative) { + const {him2} = getPronouns(singleRelative).appendSuffix('2'); + r.push(`${slave.slaveName} knows that ${his} ${relativeTerm(slave, singleRelative)} ${singleRelative.slaveName} loves being your sex slave, and is <span class="devotion inc">happy</span> for ${him2}.`); + } else if (devotedRelatives.size > 0) { + const groups = relativeMapToGroupArray(devotedRelatives); + r.push(`${slave.slaveName} knows that ${arrayToSentence(groups)} all love being your sex slaves, and is <span class="devotion inc">happy</span> for them.`); + } + if (relativeMapTotalSize(devotedRelatives) > overwhelmed) { + r.push(`${He} has so many relatives that love being your slaves that ${he} is sometimes overwhelmed with joy and <span class="devotion dec">neglects ${his} duties.</span>`); + } + singleRelative = singleRelativeInMap(obedientRelatives); + if (singleRelative) { + const {he2} = getPronouns(singleRelative).appendSuffix('2'); + r.push(`${slave.slaveName} knows that ${his} ${relativeTerm(slave, singleRelative)} ${singleRelative.slaveName} is an obedient sex slave, and hopes ${he2}'ll avoid punishment.`); + } else if (obedientRelatives.size > 0) { + const groups = relativeMapToGroupArray(obedientRelatives); + r.push(`${slave.slaveName} knows that ${arrayToSentence(groups)} are obedient sex slaves, and hopes they'll avoid punishment.`); + } + if (relativeMapTotalSize(obedientRelatives) > overwhelmed) { + r.push(`${He} has so many obedient relatives that ${he} sometimes forgets about some of them.`); + } + singleRelative = singleRelativeInMap(hatefulRelatives); + if (singleRelative) { + const {him2} = getPronouns(singleRelative).appendSuffix('2'); + r.push(`${slave.slaveName} knows that ${his} ${relativeTerm(slave, singleRelative)} ${singleRelative.slaveName} hates being a sex slave, and is <span class="trust dec">afraid</span> for ${him2}.`); + } else if (hatefulRelatives.size > 0) { + const groups = relativeMapToGroupArray(hatefulRelatives); + r.push(`${slave.slaveName} knows that ${arrayToSentence(groups)} all hate being sex slaves, and is <span class="trust dec">afraid</span> for them.`); + } + if (relativeMapTotalSize(hatefulRelatives) > overwhelmed) { + r.push(`${He} has so many relatives that hate being your sex slaves that ${he} is overwhelmed with fear and <span class="trust inc">just has to trust you to take care of them.</span>`); + } } } } diff --git a/src/js/DefaultRules.js b/src/js/DefaultRules.js index 2dde6978006d862b17d7bd4a7295547e699e1052..0b0c0886c2aa7bba25b5ed5a517fb8093fae896c 100644 --- a/src/js/DefaultRules.js +++ b/src/js/DefaultRules.js @@ -1898,8 +1898,8 @@ globalThis.DefaultRules = (function() { r += `<br>${slave.slaveName}'s living standard has been set to ${rule.livingRules}.`; } } + penthouseCensus(); } - penthouseCensus(); } /** diff --git a/src/js/releaseRules.js b/src/js/releaseRules.js index e16e71cac7e98ea7233a9e7f3156962923b418a5..b029004c3b2edd4bf6437706322092bf9f45da9b 100644 --- a/src/js/releaseRules.js +++ b/src/js/releaseRules.js @@ -42,7 +42,18 @@ App.Utils.hasFamilySex = function hasFamilySex(slave) { if (V.seeIncest === 0 || slave.rules.release.family === 0) { return false; } - return jsDef(randomRelatedSlave(slave, (s) => this.sexAllowed(slave, s))); + // check fast cases first + if (slave.mother > 0 && this.sexAllowed(slave, getSlave(slave.mother))) { + return true; + } + if (slave.father > 0 && this.sexAllowed(slave, getSlave(slave.father))) { + return true; + } + // search exhaustively for sisters/daughters only if necessary + if (slave.sisters + slave.daughters === 0) { + return false; + } + return V.slaves.some(s => areRelated(slave, s) && this.sexAllowed(slave, s)); }; /**