diff --git a/devTools/types/FC/RA.d.ts b/devTools/types/FC/RA.d.ts index 5c9869eebf40ce0f04076567ab027654debce32d..a7dbfbbdaf7ea25173b7eec3cf496466a3aaa078 100644 --- a/devTools/types/FC/RA.d.ts +++ b/devTools/types/FC/RA.d.ts @@ -16,6 +16,7 @@ declare namespace FC { assignment: Assignment[]; selectedSlaves: number[]; excludedSlaves: number[]; + applyRuleOnce: boolean; } interface RuleSurgerySettings { diff --git a/js/003-data/gameVariableData.js b/js/003-data/gameVariableData.js index 99506112fb311cc155888ffd65b41485ff1775c9..a632beba1a2f64dcc587ad48aadc0761125d3447 100644 --- a/js/003-data/gameVariableData.js +++ b/js/003-data/gameVariableData.js @@ -474,6 +474,7 @@ App.Data.resetOnNGPlus = { enduringDevotion: 0, /** @type {FC.RA.Rule[]} */ defaultRules: [], + rulesToApplyOnce: {}, REFeminizationCheckinIDs: [], REMILFCheckinIDs: [], diff --git a/src/data/backwardsCompatibility/backwardsCompatibility.js b/src/data/backwardsCompatibility/backwardsCompatibility.js index 461923d668c58af6a30986941a4ef21236d0c47e..05ac47febd792f9464cbeaf66a72c8d5f824867f 100644 --- a/src/data/backwardsCompatibility/backwardsCompatibility.js +++ b/src/data/backwardsCompatibility/backwardsCompatibility.js @@ -1525,7 +1525,22 @@ App.Update.genePoolRecords = function(node) { }; App.Update.RAassistantData = function(node) { + const ruleIDs = V.defaultRules.map(rule => rule.ID); + const slaveIDs = V.slaves.map(slave => slave.ID); V.defaultRules = V.defaultRules.map(rule => App.Entity.Utils.RARuleDatatypeCleanup(rule)); + + for (const ruleID of Object.keys(V.rulesToApplyOnce)) { + if (!ruleIDs.includes(ruleID)) { + delete V.rulesToApplyOnce[ruleID]; + } else { + for (const slaveID of V.rulesToApplyOnce[ruleID]) { + if (!slaveIDs.includes(slaveID)) { + V.rulesToApplyOnce[ruleID].delete(slaveID); + } + } + } + } + node.append(`Done!`); }; diff --git a/src/interaction/siRules.js b/src/interaction/siRules.js index bf16d17c1e88f97ce39dd2f074a9510d9a9c4dc4..0a2a8e381634687f4330d665bde0e4d9826be815 100644 --- a/src/interaction/siRules.js +++ b/src/interaction/siRules.js @@ -90,6 +90,16 @@ App.UI.SlaveInteract.rules = function(slave) { } ) ); + array.push( + App.UI.DOM.link( + `Apply all rules to ${him} again`, + () => { + removeFromRulesToApplyOnce(slave); + DefaultRules(slave); + refresh(); + } + ) + ); array.push(App.UI.DOM.passageLink("Rules Assistant Options", "Rules Assistant")); } p.append(App.UI.DOM.generateLinksStrip(array)); diff --git a/src/js/DefaultRules.js b/src/js/DefaultRules.js index 6b17e48aab38a9fed4b457a585b3f2ae27739a11..e39da3fd2d9e3ccf91745298596da8587d047603 100644 --- a/src/js/DefaultRules.js +++ b/src/js/DefaultRules.js @@ -109,7 +109,7 @@ globalThis.DefaultRules = (function() { function ProcessSlaveRules(slave) { // merge all rules applying on a slave into one big rule /** @type {FC.RA.Rule[]} */ - const rules = V.defaultRules.filter((x) => ruleAppliesP(x.condition, slave)); + const rules = V.defaultRules.filter((rule) => ruleAppliesP(rule, slave)); const ruleIds = [], assignments = []; for (const rule of rules) { ruleIds.push(rule.ID); @@ -3046,3 +3046,11 @@ globalThis.DefaultRules = (function() { globalThis.DefaultRulesError = () => V.defaultRules.some(r => RuleHasError(r)); return DefaultRules; })(); + +globalThis.removeFromRulesToApplyOnce = function(slave) { + for (const rule of Object.keys(V.rulesToApplyOnce)) { + if (V.rulesToApplyOnce[rule].includes(slave.ID)) { + V.rulesToApplyOnce[rule].delete(slave.ID); + } + } +}; \ No newline at end of file diff --git a/src/js/assayJS.js b/src/js/assayJS.js index ed35411dddaece5c2dd9db63ebaeaf28f925880f..5764907752a870d7ef55d19af92fe9b64c94b477 100644 --- a/src/js/assayJS.js +++ b/src/js/assayJS.js @@ -1673,4 +1673,5 @@ globalThis.initRules = function() { rule.set.removalAssignment = "rest"; V.defaultRules = [rule]; + V.rulesToApplyOnce = {}; }; diff --git a/src/js/removeSlave.js b/src/js/removeSlave.js index f5db93e4917e0e0f4b50a31196cbf204ae0dfeea..57cadb798d59a47d16cd46689c47519fd40a557e 100644 --- a/src/js/removeSlave.js +++ b/src/js/removeSlave.js @@ -242,6 +242,9 @@ globalThis.removeSlave = function(slave) { delete V.assignmentRecords[AS_ID]; } + // remove slaves from V.rulesToApplyOnce if needed + removeFromRulesToApplyOnce(slave); + V.slaves.deleteAt(INDEX); V.slaveIndices = slaves2indices(); LENGTH--; diff --git a/src/js/rulesAssistant.js b/src/js/rulesAssistant.js index febf9cf4b3a3ef1fa5b7f260acd0f6d01261e361..fcde2c4ddc2e2ec9988d8b79fa5985f89961a0fc 100644 --- a/src/js/rulesAssistant.js +++ b/src/js/rulesAssistant.js @@ -102,13 +102,31 @@ globalThis.RAFacilityRemove = function(slave, rule) { /** * return whether the rule applies to the slave - * @param {FC.RA.RuleConditions} cond + * @param {FC.RA.Rule} rule * @param {App.Entity.SlaveState} slave * @returns {boolean} flag */ -globalThis.ruleAppliesP = function(cond, slave) { +globalThis.ruleAppliesP = function(rule, slave) { let flag = true; + let V = State.variables; + let cond = rule.condition; let slaveAttribute = slave[cond.data.attribute]; + // Check if slave should be excluded from having rule applied to again + if (cond.applyRuleOnce) { + if (!V.rulesToApplyOnce[rule.ID]) { + V.rulesToApplyOnce[rule.ID] = []; + } + if (V.rulesToApplyOnce[rule.ID].includes(slave.ID)) { + return false; + } else { + V.rulesToApplyOnce[rule.ID].push(slave.ID); + } + } else { + if (V.rulesToApplyOnce[rule.ID]) { + delete V.rulesToApplyOnce[rule.ID]; + } + } + // attribute / function check switch (cond.function) { case false: // never applies @@ -178,6 +196,7 @@ App.RA.newRule = function() { assignment: [], selectedSlaves: [], excludedSlaves: [], + applyRuleOnce: false, }; } /** @returns {FC.RA.RuleSetters} */ diff --git a/src/js/rulesAssistantOptions.js b/src/js/rulesAssistantOptions.js index fb79af53893405046e7f6e9a19bdd552c4ebe623..2c7c384dc4edcb5a5facb2f9d71ef6ee463a4e1a 100644 --- a/src/js/rulesAssistantOptions.js +++ b/src/js/rulesAssistantOptions.js @@ -39,6 +39,9 @@ globalThis.rulesAssistantOptions = (function() { function removeRule() { const idx = V.defaultRules.findIndex(rule => rule.ID === current_rule.ID); + if (V.rulesToApplyOnce[V.defaultRules[idx].ID] !== "undefined") { + delete V.rulesToApplyOnce[V.defaultRules[idx].ID]; + } V.defaultRules.splice(idx, 1); if (V.defaultRules.length > 0) { const new_idx = idx < V.defaultRules.length ? idx : V.defaultRules.length - 1; @@ -1157,6 +1160,7 @@ globalThis.rulesAssistantOptions = (function() { this.appendChild(new AssignmentInclusion()); this.appendChild(new FacilityHeadAssignmentInclusion()); this.appendChild(new SpecificInclusionExclusion()); + this.appendChild(new ApplyRuleOnce()); } } @@ -1548,6 +1552,20 @@ globalThis.rulesAssistantOptions = (function() { } } + class ApplyRuleOnce extends ButtonItem { + constructor() { + super("Do not apply rule (and overwrite manual changes) every time rule is executed, but only once per slave", false, (current_rule.condition.applyRuleOnce === true)); + } + + onchange() { + if (!current_rule.condition.applyRuleOnce) { + current_rule.condition.applyRuleOnce = true; + } else { + current_rule.condition.applyRuleOnce = false; + } + } + } + // parent section for effect editing class EffectEditor extends Element { constructor() {