From 002487bc4e2cc4b534e7f32941876286b9eddb5c Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Mon, 29 Apr 2024 23:06:49 -0700 Subject: [PATCH 01/14] prototype using actor.statuses instead of Midi flags --- src/module.js | 54 +++++++++++++++++++++++++++++++++++++++++++++--- src/reminders.js | 30 ++++++++++++++++++++++++++- src/sources.js | 9 ++++++++ 3 files changed, 89 insertions(+), 4 deletions(-) diff --git a/src/module.js b/src/module.js index 62c499f..3bfc42b 100644 --- a/src/module.js +++ b/src/module.js @@ -41,9 +41,10 @@ function applyMidiCustom(actor, change) { Hooks.once("setup", () => { if (game.settings.get("adv-reminder", "updateStatusEffects")) { - updateStatusEffects(); - Hooks.on("preCreateActiveEffect", addExhaustionEffects); - Hooks.on("preUpdateActiveEffect", addExhaustionEffects); + //updateStatusEffects(); + updateConditionEffects(); + //Hooks.on("preCreateActiveEffect", addExhaustionEffects); + //Hooks.on("preUpdateActiveEffect", addExhaustionEffects); } }); @@ -282,6 +283,53 @@ function updateStatusEffects() { }); } +/** + * Add advantage-like condition effects for all status effects. + * details: when adding to CONFIG.DND5E.conditionEffects, make sure to include an "advReminder" + * prefix to serve as a namespace to avoid conflicts + */ +function updateConditionEffects() { + // flags.midi-qol.advantage.attack.all + CONFIG.DND5E.conditionEffects.advReminderAdvantageAttack = new Set(["hiding", "invisible"]); + + // flags.midi-qol.advantage.ability.save.dex + CONFIG.DND5E.conditionEffects.advReminderAdvantageDexSave = new Set(["dodging"]); + + // flags.midi-qol.disadvantage.attack.all + CONFIG.DND5E.conditionEffects.advReminderDisadvantageAttack = new Set(["blinded", "frightened", "poisoned", "prone", "restrained"]); + + // flags.midi-qol.disadvantage.ability.check.all + CONFIG.DND5E.conditionEffects.advReminderDisadvantageAbility = new Set(["exhaustion-1", "frightened", "poisoned"]); + + // flags.midi-qol.disadvantage.ability.save.all + CONFIG.DND5E.conditionEffects.advReminderDisadvantageSave = new Set(["exhaustion-3"]); + + // flags.midi-qol.disadvantage.ability.save.dex + CONFIG.DND5E.conditionEffects.advReminderDisadvantageDexSave = new Set(["restrained"]); + + // flags.dnd5e.initiativeDisadv + CONFIG.DND5E.conditionEffects.advReminderDisadvantageInitiative = new Set(["exhaustion-1"]); + + // flags.midi-qol.fail.ability.save.dex + CONFIG.DND5E.conditionEffects.advReminderFailDexSave = new Set(["paralyzed", "petrified", "stunned", "unconscious"]); + + // flags.midi-qol.fail.ability.save.str + CONFIG.DND5E.conditionEffects.advReminderFailStrSave = new Set(["paralyzed", "petrified", "stunned", "unconscious"]); + + // flags.midi-qol.grants.advantage.attack.all + CONFIG.DND5E.conditionEffects.advReminderGrantAdvantageAttack = new Set(["blinded", "paralyzed", "petrified", "restrained", "stunned", "unconscious"]); + + CONFIG.DND5E.conditionEffects.advReminderGrantAdvantageAdjacentAttack = new Set(["prone"]); + + // flags.midi-qol.grants.critical.range + CONFIG.DND5E.conditionEffects.advReminderGrantCriticalAdjacent = new Set(["paralyzed", "unconscious"]); + + // flags.midi-qol.grants.disadvantage.attack.all + CONFIG.DND5E.conditionEffects.advReminderGrantDisadvantageAttack = new Set(["dodging", "exhaustion-3", "hidden", "invisible"]); + + CONFIG.DND5E.conditionEffects.advReminderGrantDisadvantageFarAttack = new Set(["prone"]); +} + function addExhaustionEffects(effect, updates) { debug("addExhaustionEffects"); diff --git a/src/reminders.js b/src/reminders.js index 093e266..6a05c28 100644 --- a/src/reminders.js +++ b/src/reminders.js @@ -2,6 +2,8 @@ import { debug, isEmpty } from "./util.js"; class BaseReminder { constructor(actor) { + /** @type {Actor5e*} */ + this.actor = actor; /** @type {object} */ this.actorFlags = this._getFlags(actor); } @@ -20,6 +22,26 @@ class BaseReminder { debug("checking for adv/dis effects for the roll"); } + /** + * Modeled after Actor5e#hasConditionEffect, check to see if the actor is under the effect of + * this property from some status or due to its level of exhaustion. But instead of a true/false, + * it returns the ID of the condition. + * @param {Actor5e} actor the actor + * @param {string} key the effect key + * @returns {Set} a set of the condition IDs the actor has for the effect + */ + _getConditionForEffect(actor, key) { + const props = CONFIG.DND5E.conditionEffects[key] ?? new Set(); + const level = actor.system.attributes?.exhaustion ?? null; + const imms = actor.system.traits?.ci?.value ?? new Set(); + const statuses = actor.statuses; + return props.filter(k => { + const l = Number(k.split("-").pop()); + return (statuses.has(k) && !imms.has(k)) + || (!imms.has("exhaustion") && (level !== null) && Number.isInteger(l) && (level >= l)); + }); + } + /** * An accumulator that looks for matching keys and tracks advantage/disadvantage. * @param {Object} options @@ -34,6 +56,9 @@ class BaseReminder { advantage = advKeys.reduce((accum, curr) => accum || actorFlags[curr], advantage); disadvantage = disKeys.reduce((accum, curr) => accum || actorFlags[curr], disadvantage); }, + advantage: (label) => { + if (label) advantage = true; + }, disadvantage: (label) => { if (label) disadvantage = true; }, @@ -71,7 +96,7 @@ export class AttackReminder extends BaseReminder { this._message(); // quick return if there are no flags - if (isEmpty(this.actorFlags) && isEmpty(this.targetFlags)) return; + //if (isEmpty(this.actorFlags) && isEmpty(this.targetFlags)) return; // build the active effect keys applicable for this roll const advKeys = [ @@ -99,6 +124,9 @@ export class AttackReminder extends BaseReminder { const accumulator = this._accumulator(); accumulator.add(this.actorFlags, advKeys, disKeys); accumulator.add(this.targetFlags, grantsAdvKeys, grantsDisKeys); + this._getConditionForEffect(this.actor, "advReminderAdvantageAttack").forEach( + accumulator.advantage + ); accumulator.update(options); } } diff --git a/src/sources.js b/src/sources.js index 6c3899a..a4e8d4d 100644 --- a/src/sources.js +++ b/src/sources.js @@ -34,6 +34,15 @@ const SourceMixin = (superclass) => debug("checking for adv/dis effects to display their source"); } + _getConditionForEffect(actor, key) { + const props = super._getConditionForEffect(actor, key); + return props + // remove the number after exhaustion + .map((k) => k.split("-").shift()) + // get name from statusEffects + .map((k) => CONFIG.statusEffects.find((s) => s.id === k)?.name); + } + _accumulator() { const advantageLabels = []; const disadvantageLabels = []; From 02731581d72cd9ba37bac00a117399ce267ced29 Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 30 Apr 2024 00:43:25 -0700 Subject: [PATCH 02/14] add remaining attack checks --- src/module.js | 5 ++--- src/reminders.js | 23 ++++++++++++++++++----- src/rollers/core.js | 5 +++-- src/rollers/midi.js | 9 ++++++++- src/rollers/rsr.js | 7 ++++--- 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/module.js b/src/module.js index 3bfc42b..a65d5de 100644 --- a/src/module.js +++ b/src/module.js @@ -319,15 +319,14 @@ function updateConditionEffects() { // flags.midi-qol.grants.advantage.attack.all CONFIG.DND5E.conditionEffects.advReminderGrantAdvantageAttack = new Set(["blinded", "paralyzed", "petrified", "restrained", "stunned", "unconscious"]); - CONFIG.DND5E.conditionEffects.advReminderGrantAdvantageAdjacentAttack = new Set(["prone"]); - // flags.midi-qol.grants.critical.range CONFIG.DND5E.conditionEffects.advReminderGrantCriticalAdjacent = new Set(["paralyzed", "unconscious"]); // flags.midi-qol.grants.disadvantage.attack.all CONFIG.DND5E.conditionEffects.advReminderGrantDisadvantageAttack = new Set(["dodging", "exhaustion-3", "hidden", "invisible"]); - CONFIG.DND5E.conditionEffects.advReminderGrantDisadvantageFarAttack = new Set(["prone"]); + // if adjacent, grant advantage on the attack, else grant disadvantage + CONFIG.DND5E.conditionEffects.advReminderGrantAdjacentAttack = new Set(["prone"]); } function addExhaustionEffects(effect, updates) { diff --git a/src/reminders.js b/src/reminders.js index 6a05c28..5694cdc 100644 --- a/src/reminders.js +++ b/src/reminders.js @@ -81,15 +81,19 @@ class BaseReminder { } export class AttackReminder extends BaseReminder { - constructor(actor, targetActor, item) { + constructor(actor, targetActor, item, distanceFn) { super(actor); + /** @type {Actor5e*} */ + this.targetActor = targetActor; /** @type {object} */ this.targetFlags = this._getFlags(targetActor); /** @type {string} */ this.actionType = item.system.actionType; /** @type {string} */ this.abilityId = item.abilityMod; + /** @type {function} */ + this.distanceFn = distanceFn; } updateOptions(options) { @@ -120,13 +124,22 @@ export class AttackReminder extends BaseReminder { `grants.disadvantage.attack.${this.actionType}`, ]; - // find matching keys and update options + // find matching keys const accumulator = this._accumulator(); accumulator.add(this.actorFlags, advKeys, disKeys); accumulator.add(this.targetFlags, grantsAdvKeys, grantsDisKeys); - this._getConditionForEffect(this.actor, "advReminderAdvantageAttack").forEach( - accumulator.advantage - ); + // handle status effects + this._getConditionForEffect(this.actor, "advReminderAdvantageAttack").forEach(accumulator.advantage); + this._getConditionForEffect(this.actor, "advReminderDisadvantageAttack").forEach(accumulator.disadvantage); + this._getConditionForEffect(this.targetActor, "advReminderGrantAdvantageAttack").forEach(accumulator.advantage); + this._getConditionForEffect(this.targetActor, "advReminderGrantDisadvantageAttack").forEach(accumulator.disadvantage); + // handle distance-based status effects + const grantAdjacentAttack = this._getConditionForEffect(this.targetActor, "advReminderGrantAdjacentAttack"); + if (grantAdjacentAttack.size) { + const distance = this.distanceFn(); + const accumFn = distance <= 5 ? accumulator.advantage : accumulator.disadvantage; + grantAdjacentAttack.forEach(accumFn); + } accumulator.update(options); } } diff --git a/src/rollers/core.js b/src/rollers/core.js index a44eab4..c030efd 100644 --- a/src/rollers/core.js +++ b/src/rollers/core.js @@ -70,10 +70,11 @@ export default class CoreRollerHooks { if (this.isFastForwarding(config)) return; const target = getTarget(); + const distanceFn = getDistanceToTargetFn(config.messageData.speaker); new AttackMessage(item.actor, target, item).addMessage(config); - if (showSources) new AttackSource(item.actor, target, item).updateOptions(config); - new AttackReminder(item.actor, target, item).updateOptions(config); + if (showSources) new AttackSource(item.actor, target, item, distanceFn).updateOptions(config); + new AttackReminder(item.actor, target, item, distanceFn).updateOptions(config); } preRollAbilitySave(actor, config, abilityId) { diff --git a/src/rollers/midi.js b/src/rollers/midi.js index 0150601..425f507 100644 --- a/src/rollers/midi.js +++ b/src/rollers/midi.js @@ -33,9 +33,16 @@ export default class MidiRollerHooks extends CoreRollerHooks { if (this.isFastForwarding(config)) return; const target = getTarget(); + // use distance from Midi's Workflow + const distanceFn = () => { + const workflow = MidiQOL.Workflow.getWorkflow(item.uuid); + if (!workflow) return Infinity; + const firstTarget = workflow.hitTargets.values().next().value; + return MidiQOL.computeDistance(firstTarget, workflow.token, false); + } new AttackMessage(item.actor, target, item).addMessage(config); - if (showSources) new AttackSource(item.actor, target, item).updateOptions(config); + if (showSources) new AttackSource(item.actor, target, item, distanceFn).updateOptions(config); } preRollAbilitySave(actor, config, abilityId) { diff --git a/src/rollers/rsr.js b/src/rollers/rsr.js index 48621a4..15fce74 100644 --- a/src/rollers/rsr.js +++ b/src/rollers/rsr.js @@ -26,7 +26,7 @@ import { SkillSource, } from "../sources.js"; import { showSources } from "../settings.js"; -import { debug, getTarget } from "../util.js"; +import { debug, getDistanceToTargetFn, getTarget } from "../util.js"; import CoreRollerHooks from "./core.js"; // disable the grants.critical.range flag since RSR can't have it's critical flag changed anyways, @@ -51,14 +51,15 @@ export default class ReadySetRollHooks extends CoreRollerHooks { debug("preRollAttack hook called"); const target = getTarget(); + const distanceFn = getDistanceToTargetFn(config.messageData.speaker); if (this._doMessages(config)) { new AttackMessage(item.actor, target, item).addMessage(config); - if (showSources) new AttackSource(item.actor, target, item).updateOptions(config); + if (showSources) new AttackSource(item.actor, target, item, distanceFn).updateOptions(config); } if (this._doReminder(config)) - new AttackReminder(item.actor, target, item).updateOptions(config); + new AttackReminder(item.actor, target, item, distanceFn).updateOptions(config); } preRollAbilitySave(actor, config, abilityId) { From 472f497de3c3dd5c95589dfc28130f83f345c4b1 Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 30 Apr 2024 13:08:21 -0700 Subject: [PATCH 03/14] get statuses source from the active effect it's on For example, if the target of an attack is under the Sleep spell, this will now show Sleep as the source of advantage instead of Unconscious. --- src/sources.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/sources.js b/src/sources.js index a4e8d4d..f330719 100644 --- a/src/sources.js +++ b/src/sources.js @@ -36,11 +36,21 @@ const SourceMixin = (superclass) => _getConditionForEffect(actor, key) { const props = super._getConditionForEffect(actor, key); - return props - // remove the number after exhaustion - .map((k) => k.split("-").shift()) - // get name from statusEffects - .map((k) => CONFIG.statusEffects.find((s) => s.id === k)?.name); + return ( + props + .toObject() + // remove the number after exhaustion + .map((k) => k.split("-").shift()) + .flatMap((k) => { + // look for active effects with this status in it, get their names + const activeEffectNames = actor.appliedEffects + .filter((e) => e.statuses.some((s) => s === k)) + .map((e) => e.name); + if (activeEffectNames.length) return activeEffectNames; + // fallback to the status effect's name (mostly for exhaustion) + return CONFIG.statusEffects.filter((s) => s.id === k).map((s) => s.name); + }) + ); } _accumulator() { From 0cd4e5123271447556437a4b9b7f6674751aec92 Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 30 Apr 2024 20:53:25 -0700 Subject: [PATCH 04/14] add saving throws Added a helper function to the accumulator, fromConditions, to help with this. Also uses the similar strategy to get the condition effect keys that we do with Midi's keys --- src/reminders.js | 32 +++++++++++++++++++++++++++++--- src/sources.js | 5 ++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/src/reminders.js b/src/reminders.js index 5694cdc..d586c5c 100644 --- a/src/reminders.js +++ b/src/reminders.js @@ -39,7 +39,7 @@ class BaseReminder { const l = Number(k.split("-").pop()); return (statuses.has(k) && !imms.has(k)) || (!imms.has("exhaustion") && (level !== null) && Number.isInteger(l) && (level >= l)); - }); + }).toObject(); } /** @@ -56,6 +56,10 @@ class BaseReminder { advantage = advKeys.reduce((accum, curr) => accum || actorFlags[curr], advantage); disadvantage = disKeys.reduce((accum, curr) => accum || actorFlags[curr], disadvantage); }, + fromConditions: (actor, advConditions, disConditions) => { + if (advConditions.flatMap(c => this._getConditionForEffect(actor, c)).length) advantage = true; + if (disConditions.flatMap(c => this._getConditionForEffect(actor, c)).length) disadvantage = true; + }, advantage: (label) => { if (label) advantage = true; }, @@ -160,20 +164,29 @@ class AbilityBaseReminder extends BaseReminder { return ["disadvantage.all", "disadvantage.ability.all"]; } + get advantageConditions() { + return []; + } + + get disadvantageConditions() { + return []; + } + updateOptions(options) { this._message(); // quick return if there are no flags - if (isEmpty(this.actorFlags)) return; + //if (isEmpty(this.actorFlags)) return; // get the active effect keys applicable for this roll const advKeys = this.advantageKeys; const disKeys = this.disadvantageKeys; debug("advKeys", advKeys, "disKeys", disKeys); - // find matching keys and update options + // find matching keys, status effects, and update options const accumulator = options.isConcentration ? this._accumulator(options) : this._accumulator(); accumulator.add(this.actorFlags, advKeys, disKeys); + accumulator.fromConditions(this.actor, this.advantageConditions, this.disadvantageConditions); accumulator.update(options); } } @@ -212,6 +225,19 @@ export class AbilitySaveReminder extends AbilityBaseReminder { `disadvantage.ability.save.${this.abilityId}`, ]); } + + /** @override */ + get advantageConditions() { + const conditions = []; + if (this.abilityId === "dex") conditions.push("advReminderAdvantageDexSave"); + return conditions; + } + + get disadvantageConditions() { + const conditions = ["advReminderDisadvantageSave"]; + if (this.abilityId === "dex") conditions.push("advReminderDisadvantageDexSave"); + return conditions; + } } export class SkillReminder extends AbilityCheckReminder { diff --git a/src/sources.js b/src/sources.js index f330719..a0dea15 100644 --- a/src/sources.js +++ b/src/sources.js @@ -38,7 +38,6 @@ const SourceMixin = (superclass) => const props = super._getConditionForEffect(actor, key); return ( props - .toObject() // remove the number after exhaustion .map((k) => k.split("-").shift()) .flatMap((k) => { @@ -66,6 +65,10 @@ const SourceMixin = (superclass) => if (changes[key]) disadvantageLabels.push(...changes[key]); }); }, + fromConditions: (actor, advConditions, disConditions) => { + advantageLabels.push(...advConditions.flatMap(c => this._getConditionForEffect(actor, c))); + disadvantageLabels.push(...disConditions.flatMap(c => this._getConditionForEffect(actor, c))); + }, advantage: (label) => { if (label) advantageLabels.push(label); }, From 959fee3582887b4027a854797f19008a8fb551e0 Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 30 Apr 2024 21:07:09 -0700 Subject: [PATCH 05/14] use new accumulator helper in attacks also fix bugs when there isn't a target --- src/reminders.js | 24 +++++++++++++++--------- src/sources.js | 1 + 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/reminders.js b/src/reminders.js index d586c5c..b9614dd 100644 --- a/src/reminders.js +++ b/src/reminders.js @@ -57,6 +57,7 @@ class BaseReminder { disadvantage = disKeys.reduce((accum, curr) => accum || actorFlags[curr], disadvantage); }, fromConditions: (actor, advConditions, disConditions) => { + if (!actor) return; if (advConditions.flatMap(c => this._getConditionForEffect(actor, c)).length) advantage = true; if (disConditions.flatMap(c => this._getConditionForEffect(actor, c)).length) disadvantage = true; }, @@ -127,22 +128,27 @@ export class AttackReminder extends BaseReminder { "grants.disadvantage.attack.all", `grants.disadvantage.attack.${this.actionType}`, ]; + // build the condition effect keys for this roll + const advConditions = ["advReminderAdvantageAttack"]; + const disConditions = ["advReminderDisadvantageAttack"]; + const grantsAdvConditions = ["advReminderGrantAdvantageAttack"]; + const grantsDisConditions = ["advReminderGrantDisadvantageAttack"]; // find matching keys const accumulator = this._accumulator(); accumulator.add(this.actorFlags, advKeys, disKeys); accumulator.add(this.targetFlags, grantsAdvKeys, grantsDisKeys); // handle status effects - this._getConditionForEffect(this.actor, "advReminderAdvantageAttack").forEach(accumulator.advantage); - this._getConditionForEffect(this.actor, "advReminderDisadvantageAttack").forEach(accumulator.disadvantage); - this._getConditionForEffect(this.targetActor, "advReminderGrantAdvantageAttack").forEach(accumulator.advantage); - this._getConditionForEffect(this.targetActor, "advReminderGrantDisadvantageAttack").forEach(accumulator.disadvantage); + accumulator.fromConditions(this.actor, advConditions, disConditions); + accumulator.fromConditions(this.targetActor, grantsAdvConditions, grantsDisConditions); // handle distance-based status effects - const grantAdjacentAttack = this._getConditionForEffect(this.targetActor, "advReminderGrantAdjacentAttack"); - if (grantAdjacentAttack.size) { - const distance = this.distanceFn(); - const accumFn = distance <= 5 ? accumulator.advantage : accumulator.disadvantage; - grantAdjacentAttack.forEach(accumFn); + if (this.targetActor) { + const grantAdjacentAttack = this._getConditionForEffect(this.targetActor, "advReminderGrantAdjacentAttack"); + if (grantAdjacentAttack.size) { + const distance = this.distanceFn(); + const accumFn = distance <= 5 ? accumulator.advantage : accumulator.disadvantage; + grantAdjacentAttack.forEach(accumFn); + } } accumulator.update(options); } diff --git a/src/sources.js b/src/sources.js index a0dea15..939e182 100644 --- a/src/sources.js +++ b/src/sources.js @@ -66,6 +66,7 @@ const SourceMixin = (superclass) => }); }, fromConditions: (actor, advConditions, disConditions) => { + if (!actor) return; advantageLabels.push(...advConditions.flatMap(c => this._getConditionForEffect(actor, c))); disadvantageLabels.push(...disConditions.flatMap(c => this._getConditionForEffect(actor, c))); }, From d0af87ccef41aec5e6bad5d6d1d84a0663e879af Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 30 Apr 2024 21:23:52 -0700 Subject: [PATCH 06/14] add ability checks and skills --- src/reminders.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/reminders.js b/src/reminders.js index b9614dd..aedc353 100644 --- a/src/reminders.js +++ b/src/reminders.js @@ -213,6 +213,10 @@ export class AbilityCheckReminder extends AbilityBaseReminder { `disadvantage.ability.check.${this.abilityId}`, ]); } + + get disadvantageConditions() { + return ["advReminderDisadvantageAbility"]; + } } export class AbilitySaveReminder extends AbilityBaseReminder { @@ -286,6 +290,7 @@ export class SkillReminder extends AbilityCheckReminder { accumulator.disadvantage(this._armorStealthDisadvantage()); } accumulator.add(this.actorFlags, advKeys, disKeys); + accumulator.fromConditions(this.actor, this.advantageConditions, this.disadvantageConditions); accumulator.update(options); } From 3173f37c888f2d7ba83372e120c824db303ea3a4 Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 30 Apr 2024 21:39:57 -0700 Subject: [PATCH 07/14] add critical hits --- src/module.js | 2 +- src/reminders.js | 19 +++++++++++++++++-- src/sources.js | 3 +++ 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/module.js b/src/module.js index a65d5de..e9ed179 100644 --- a/src/module.js +++ b/src/module.js @@ -320,7 +320,7 @@ function updateConditionEffects() { CONFIG.DND5E.conditionEffects.advReminderGrantAdvantageAttack = new Set(["blinded", "paralyzed", "petrified", "restrained", "stunned", "unconscious"]); // flags.midi-qol.grants.critical.range - CONFIG.DND5E.conditionEffects.advReminderGrantCriticalAdjacent = new Set(["paralyzed", "unconscious"]); + CONFIG.DND5E.conditionEffects.advReminderGrantAdjacentCritical = new Set(["paralyzed", "unconscious"]); // flags.midi-qol.grants.disadvantage.attack.all CONFIG.DND5E.conditionEffects.advReminderGrantDisadvantageAttack = new Set(["dodging", "exhaustion-3", "hidden", "invisible"]); diff --git a/src/reminders.js b/src/reminders.js index aedc353..962fa0b 100644 --- a/src/reminders.js +++ b/src/reminders.js @@ -144,7 +144,7 @@ export class AttackReminder extends BaseReminder { // handle distance-based status effects if (this.targetActor) { const grantAdjacentAttack = this._getConditionForEffect(this.targetActor, "advReminderGrantAdjacentAttack"); - if (grantAdjacentAttack.size) { + if (grantAdjacentAttack.length) { const distance = this.distanceFn(); const accumFn = distance <= 5 ? accumulator.advantage : accumulator.disadvantage; grantAdjacentAttack.forEach(accumFn); @@ -332,10 +332,14 @@ export class CriticalReminder extends BaseReminder { constructor(actor, targetActor, item, distanceFn) { super(actor); + /** @type {Actor5e*} */ + this.targetActor = targetActor; /** @type {object} */ this.targetFlags = this._getFlags(targetActor); /** @type {string} */ this.actionType = item.system.actionType; + /** @type {function} */ + this.distanceFn = distanceFn; // get the Range directly from the actor's flags if (targetActor) { @@ -357,7 +361,7 @@ export class CriticalReminder extends BaseReminder { this._message(); // quick return if there are no flags - if (isEmpty(this.actorFlags) && isEmpty(this.targetFlags)) return; + //if (isEmpty(this.actorFlags) && isEmpty(this.targetFlags)) return; // build the active effect keys applicable for this roll const critKeys = ["critical.all", `critical.${this.actionType}`]; @@ -373,6 +377,14 @@ export class CriticalReminder extends BaseReminder { const accumulator = this._accumulator(); accumulator.add(this.actorFlags, critKeys, normalKeys); accumulator.add(this.targetFlags, grantsCritKeys, grantsNormalKeys); + // handle distance-based status effects + if (this.targetActor) { + const grantAdjacentCritical = this._getConditionForEffect(this.targetActor, "advReminderGrantAdjacentCritical"); + if (grantAdjacentCritical.length) { + const distance = this.distanceFn(); + if (distance <= 5) grantAdjacentCritical.forEach(accumulator.critical); + } + } accumulator.update(options, critProp); } @@ -386,6 +398,9 @@ export class CriticalReminder extends BaseReminder { crit = critKeys.reduce((accum, curr) => accum || actorFlags[curr], crit); normal = normalKeys.reduce((accum, curr) => accum || actorFlags[curr], normal); }, + critical: (label) => { + if (label) crit = true; + }, update: (options, critProp) => { // a normal hit overrides a crit const critical = normal ? false : !!crit; diff --git a/src/sources.js b/src/sources.js index 939e182..452f47e 100644 --- a/src/sources.js +++ b/src/sources.js @@ -149,6 +149,9 @@ export class CriticalSource extends SourceMixin(CriticalReminder) { if(changes[key]) normalLabels.push(...changes[key]); }); }, + critical: (label) => { + if (label) criticalLabels.push(label); + }, update: (options) => { debug("criticalLabels", criticalLabels, "normalLabels", normalLabels); const merge = (newLabels, key) => { From 3326586559d961810519818c8aeac1f321f3747a Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 30 Apr 2024 22:03:11 -0700 Subject: [PATCH 08/14] remove initiative conditionEffect --- src/module.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/module.js b/src/module.js index e9ed179..ac6556c 100644 --- a/src/module.js +++ b/src/module.js @@ -307,9 +307,6 @@ function updateConditionEffects() { // flags.midi-qol.disadvantage.ability.save.dex CONFIG.DND5E.conditionEffects.advReminderDisadvantageDexSave = new Set(["restrained"]); - // flags.dnd5e.initiativeDisadv - CONFIG.DND5E.conditionEffects.advReminderDisadvantageInitiative = new Set(["exhaustion-1"]); - // flags.midi-qol.fail.ability.save.dex CONFIG.DND5E.conditionEffects.advReminderFailDexSave = new Set(["paralyzed", "petrified", "stunned", "unconscious"]); From 90f47060baba6946d3829c96a37598f7cc85c18e Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 30 Apr 2024 22:03:51 -0700 Subject: [PATCH 09/14] add fail saving throws --- src/fails.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/fails.js b/src/fails.js index 057589f..52d8c36 100644 --- a/src/fails.js +++ b/src/fails.js @@ -20,6 +20,10 @@ class BaseFail { return ["fail.all"]; } + get failCondition() { + return undefined; + } + /** * Check for auto-fail flags to see if this roll should fail. * @param {object} options the roll options @@ -33,7 +37,9 @@ class BaseFail { debug("failKeys", failKeys); const actorFlags = this._getFlags(this.actor); - const shouldFail = failKeys.reduce((accum, curr) => actorFlags[curr] || accum, false); + const shouldFail = + failKeys.reduce((accum, curr) => actorFlags[curr] || accum, false) || + this.actor.hasConditionEffect(this.failCondition); if (shouldFail) { const messageData = this.createMessageData(options); this.toMessage(messageData); @@ -78,6 +84,14 @@ export class AbilitySaveFail extends BaseFail { ]); } + /** @override */ + get failCondition() { + switch (this.abilityId) { + case "dex": return "advReminderFailDexSave"; + case "str": return "advReminderFailDexSave"; + } + } + createMessageData(options = {}) { // build title, probably used as chat message flavor const label = CONFIG.DND5E.abilities[this.abilityId]; From efccf9cfc2c138b6e6027c553fb576b025338574 Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 30 Apr 2024 22:59:47 -0700 Subject: [PATCH 10/14] remove old updateStatusEffects and addExhaustionEffects --- src/module.js | 325 +++----------------------------------------------- 1 file changed, 14 insertions(+), 311 deletions(-) diff --git a/src/module.js b/src/module.js index ac6556c..253a9f8 100644 --- a/src/module.js +++ b/src/module.js @@ -40,326 +40,29 @@ function applyMidiCustom(actor, change) { } Hooks.once("setup", () => { - if (game.settings.get("adv-reminder", "updateStatusEffects")) { - //updateStatusEffects(); - updateConditionEffects(); - //Hooks.on("preCreateActiveEffect", addExhaustionEffects); - //Hooks.on("preUpdateActiveEffect", addExhaustionEffects); - } + if (game.settings.get("adv-reminder", "updateStatusEffects")) updateConditionEffects(); }); -function updateStatusEffects() { - debug("updateStatusEffects"); - - const effectChanges = { - blinded: { - changes: [ - { - key: "flags.midi-qol.disadvantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.advantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ], - }, - dodging: { - flags: { - dae: { - specialDuration: ["turnStart"], - }, - }, - changes: [ - { - key: "flags.midi-qol.grants.disadvantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.advantage.ability.save.dex", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ], - }, - frightened: { - changes: [ - { - key: "flags.midi-qol.disadvantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.disadvantage.ability.check.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ], - }, - hidden: { - changes: [ - { - key: "flags.midi-qol.advantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.disadvantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ], - }, - invisible: { - changes: [ - { - key: "flags.midi-qol.advantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.disadvantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ], - }, - paralyzed: { - changes: [ - { - key: "flags.midi-qol.fail.ability.save.dex", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.fail.ability.save.str", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.advantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.critical.range", - mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE, - value: "5", - }, - ], - }, - petrified: { - changes: [ - { - key: "flags.midi-qol.grants.advantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.fail.ability.save.dex", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.fail.ability.save.str", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ], - }, - poisoned: { - changes: [ - { - key: "flags.midi-qol.disadvantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.disadvantage.ability.check.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ], - }, - prone: { - changes: [ - { - key: "flags.midi-qol.grants.advantage.attack.mwak", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.advantage.attack.msak", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.disadvantage.attack.rwak", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.disadvantage.attack.rsak", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.disadvantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ], - }, - restrained: { - changes: [ - { - key: "flags.midi-qol.disadvantage.ability.save.dex", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.disadvantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.advantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ], - }, - stunned: { - changes: [ - { - key: "flags.midi-qol.fail.ability.save.dex", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.fail.ability.save.str", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.advantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ], - }, - unconscious: { - changes: [ - { - key: "flags.midi-qol.fail.ability.save.dex", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.fail.ability.save.str", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.advantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.grants.critical.range", - mode: CONST.ACTIVE_EFFECT_MODES.OVERRIDE, - value: "5", - }, - ], - }, - }; - - Object.entries(effectChanges).forEach(([id, data]) => { - const effect = CONFIG.statusEffects.find((e) => e.id === id); - if (effect) foundry.utils.mergeObject(effect, data); - }); -} - /** * Add advantage-like condition effects for all status effects. * details: when adding to CONFIG.DND5E.conditionEffects, make sure to include an "advReminder" * prefix to serve as a namespace to avoid conflicts */ function updateConditionEffects() { - // flags.midi-qol.advantage.attack.all - CONFIG.DND5E.conditionEffects.advReminderAdvantageAttack = new Set(["hiding", "invisible"]); - - // flags.midi-qol.advantage.ability.save.dex - CONFIG.DND5E.conditionEffects.advReminderAdvantageDexSave = new Set(["dodging"]); - - // flags.midi-qol.disadvantage.attack.all - CONFIG.DND5E.conditionEffects.advReminderDisadvantageAttack = new Set(["blinded", "frightened", "poisoned", "prone", "restrained"]); - - // flags.midi-qol.disadvantage.ability.check.all - CONFIG.DND5E.conditionEffects.advReminderDisadvantageAbility = new Set(["exhaustion-1", "frightened", "poisoned"]); - - // flags.midi-qol.disadvantage.ability.save.all - CONFIG.DND5E.conditionEffects.advReminderDisadvantageSave = new Set(["exhaustion-3"]); - - // flags.midi-qol.disadvantage.ability.save.dex - CONFIG.DND5E.conditionEffects.advReminderDisadvantageDexSave = new Set(["restrained"]); - - // flags.midi-qol.fail.ability.save.dex - CONFIG.DND5E.conditionEffects.advReminderFailDexSave = new Set(["paralyzed", "petrified", "stunned", "unconscious"]); - - // flags.midi-qol.fail.ability.save.str - CONFIG.DND5E.conditionEffects.advReminderFailStrSave = new Set(["paralyzed", "petrified", "stunned", "unconscious"]); - - // flags.midi-qol.grants.advantage.attack.all - CONFIG.DND5E.conditionEffects.advReminderGrantAdvantageAttack = new Set(["blinded", "paralyzed", "petrified", "restrained", "stunned", "unconscious"]); - - // flags.midi-qol.grants.critical.range - CONFIG.DND5E.conditionEffects.advReminderGrantAdjacentCritical = new Set(["paralyzed", "unconscious"]); - - // flags.midi-qol.grants.disadvantage.attack.all - CONFIG.DND5E.conditionEffects.advReminderGrantDisadvantageAttack = new Set(["dodging", "exhaustion-3", "hidden", "invisible"]); - + const ce = CONFIG.DND5E.conditionEffects; + ce.advReminderAdvantageAttack = new Set(["hiding", "invisible"]); + ce.advReminderAdvantageDexSave = new Set(["dodging"]); + ce.advReminderDisadvantageAttack = new Set(["blinded", "frightened", "poisoned", "prone", "restrained"]); + ce.advReminderDisadvantageAbility = new Set(["exhaustion-1", "frightened", "poisoned"]); + ce.advReminderDisadvantageSave = new Set(["exhaustion-3"]); + ce.advReminderDisadvantageDexSave = new Set(["restrained"]); + ce.advReminderFailDexSave = new Set(["paralyzed", "petrified", "stunned", "unconscious"]); + ce.advReminderFailStrSave = new Set(["paralyzed", "petrified", "stunned", "unconscious"]); + ce.advReminderGrantAdvantageAttack = new Set(["blinded", "paralyzed", "petrified", "restrained", "stunned", "unconscious"]); + ce.advReminderGrantAdjacentCritical = new Set(["paralyzed", "unconscious"]); + ce.advReminderGrantDisadvantageAttack = new Set(["dodging", "exhaustion-3", "hidden", "invisible"]); // if adjacent, grant advantage on the attack, else grant disadvantage - CONFIG.DND5E.conditionEffects.advReminderGrantAdjacentAttack = new Set(["prone"]); -} - -function addExhaustionEffects(effect, updates) { - debug("addExhaustionEffects"); - - if (effect.id !== dnd5e.documents.ActiveEffect5e.ID.EXHAUSTION) return; - const level = foundry.utils.getProperty(updates, "flags.dnd5e.exhaustionLevel"); - if (!level) return; - // build the changes based on exhaustion level - const changes = [ - { - key: "flags.midi-qol.disadvantage.ability.check.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.dnd5e.initiativeDisadv", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - ]; - if (level >= 3) - changes.push( - { - key: "flags.midi-qol.disadvantage.attack.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - }, - { - key: "flags.midi-qol.disadvantage.ability.save.all", - mode: CONST.ACTIVE_EFFECT_MODES.CUSTOM, - value: "1", - } - ); - // add changes to the active effect - effect.updateSource({ changes }); + ce.advReminderGrantAdjacentAttack = new Set(["prone"]); } // Add message flags to DAE so it shows them in the AE editor From 6d39b311fb4889a82fc8e3bfea9810a0d009f295 Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 30 Apr 2024 23:00:46 -0700 Subject: [PATCH 11/14] rename setting to match new behavior it is functionally the same, so just reuse the existing setting instead of making a new one --- lang/en.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/en.json b/lang/en.json index 7b19c13..fef839e 100644 --- a/lang/en.json +++ b/lang/en.json @@ -29,7 +29,7 @@ "Norm": "Normal from {sources}" }, "adv-reminder.UpdateStatusEffects": { - "Name": "Update Status Effects", - "Hint": "Update the status effects that the system adds to include the appropriate advantage/disadvantage flags. Not recommended if you are using another module to modify or replace them." + "Name": "Enable Condition Effects", + "Hint": "Apply adv/dis/crit with the system's conditions (e.g. apply disadvantage to attacks when Poisoned). Not recommended if you are using another module to modify or replace the status effects." } } From 15c491616f517fcfa294035f8a95d78ccf9ed336 Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 21 May 2024 13:44:56 -0700 Subject: [PATCH 12/14] add support for heavilyEncumbered --- src/module.js | 1 + src/reminders.js | 10 +++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/module.js b/src/module.js index 253a9f8..e6a0aba 100644 --- a/src/module.js +++ b/src/module.js @@ -56,6 +56,7 @@ function updateConditionEffects() { ce.advReminderDisadvantageAbility = new Set(["exhaustion-1", "frightened", "poisoned"]); ce.advReminderDisadvantageSave = new Set(["exhaustion-3"]); ce.advReminderDisadvantageDexSave = new Set(["restrained"]); + ce.advReminderDisadvantagePhysicalRolls = new Set(["heavilyEncumbered"]); ce.advReminderFailDexSave = new Set(["paralyzed", "petrified", "stunned", "unconscious"]); ce.advReminderFailStrSave = new Set(["paralyzed", "petrified", "stunned", "unconscious"]); ce.advReminderGrantAdvantageAttack = new Set(["blinded", "paralyzed", "petrified", "restrained", "stunned", "unconscious"]); diff --git a/src/reminders.js b/src/reminders.js index 962fa0b..c263278 100644 --- a/src/reminders.js +++ b/src/reminders.js @@ -132,7 +132,9 @@ export class AttackReminder extends BaseReminder { const advConditions = ["advReminderAdvantageAttack"]; const disConditions = ["advReminderDisadvantageAttack"]; const grantsAdvConditions = ["advReminderGrantAdvantageAttack"]; - const grantsDisConditions = ["advReminderGrantDisadvantageAttack"]; + const grantsDisConditions = ["advReminderGrantDisadvantageAttack"]; + if (this.abilityId === "str" || this.abilityId === "dex" || this.abilityId === "con") + disConditions.push("advReminderDisadvantagePhysicalRolls"); // find matching keys const accumulator = this._accumulator(); @@ -175,6 +177,8 @@ class AbilityBaseReminder extends BaseReminder { } get disadvantageConditions() { + if (this.abilityId === "str" || this.abilityId === "dex" || this.abilityId === "con") + return ["advReminderDisadvantagePhysicalRolls"]; return []; } @@ -215,7 +219,7 @@ export class AbilityCheckReminder extends AbilityBaseReminder { } get disadvantageConditions() { - return ["advReminderDisadvantageAbility"]; + return super.disadvantageConditions().push("advReminderDisadvantageAbility"); } } @@ -244,7 +248,7 @@ export class AbilitySaveReminder extends AbilityBaseReminder { } get disadvantageConditions() { - const conditions = ["advReminderDisadvantageSave"]; + const conditions = super.disadvantageConditions().push("advReminderDisadvantageSave"); if (this.abilityId === "dex") conditions.push("advReminderDisadvantageDexSave"); return conditions; } From 7e785435efca25fcf562ebc78f0864eb9fe9d3a8 Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 21 May 2024 13:54:24 -0700 Subject: [PATCH 13/14] last-minute cleanup --- CHANGELOG.md | 1 + src/reminders.js | 9 --------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2091036..3b16b63 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ - feature: Support the system's new concentration rolls with sources and messages with `flags.adv-reminder.message.ability.concentration` (system already handles advantage/disadvantage) - feature: Support `flags.midi-qol.grants.critical.range` for conditions like Paralyzed that turn hits into crits if the attacker is adjacent. Does not currently work with Ready Set Roll, will just be ignored. +- feature: Apply conditions directly bases on the `statuses` instead of adding Midi's flags to status effects # 3.4.1 diff --git a/src/reminders.js b/src/reminders.js index c263278..2b84583 100644 --- a/src/reminders.js +++ b/src/reminders.js @@ -104,9 +104,6 @@ export class AttackReminder extends BaseReminder { updateOptions(options) { this._message(); - // quick return if there are no flags - //if (isEmpty(this.actorFlags) && isEmpty(this.targetFlags)) return; - // build the active effect keys applicable for this roll const advKeys = [ "advantage.all", @@ -185,9 +182,6 @@ class AbilityBaseReminder extends BaseReminder { updateOptions(options) { this._message(); - // quick return if there are no flags - //if (isEmpty(this.actorFlags)) return; - // get the active effect keys applicable for this roll const advKeys = this.advantageKeys; const disKeys = this.disadvantageKeys; @@ -364,9 +358,6 @@ export class CriticalReminder extends BaseReminder { updateOptions(options, critProp = "critical") { this._message(); - // quick return if there are no flags - //if (isEmpty(this.actorFlags) && isEmpty(this.targetFlags)) return; - // build the active effect keys applicable for this roll const critKeys = ["critical.all", `critical.${this.actionType}`]; const normalKeys = ["noCritical.all", `noCritical.${this.actionType}`]; From 8117c6a98582c5dd9556858d1045e70f505c4e9e Mon Sep 17 00:00:00 2001 From: Chris Seieroe Date: Tue, 21 May 2024 14:16:28 -0700 Subject: [PATCH 14/14] fix unit tests --- src/reminders.js | 7 +++++-- test/common.js | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/reminders.js b/src/reminders.js index 2b84583..935738a 100644 --- a/src/reminders.js +++ b/src/reminders.js @@ -213,7 +213,9 @@ export class AbilityCheckReminder extends AbilityBaseReminder { } get disadvantageConditions() { - return super.disadvantageConditions().push("advReminderDisadvantageAbility"); + const conditions = super.disadvantageConditions; + conditions.push("advReminderDisadvantageAbility"); + return conditions; } } @@ -242,7 +244,8 @@ export class AbilitySaveReminder extends AbilityBaseReminder { } get disadvantageConditions() { - const conditions = super.disadvantageConditions().push("advReminderDisadvantageSave"); + const conditions = super.disadvantageConditions; + conditions.push("advReminderDisadvantageSave"); if (this.abilityId === "dex") conditions.push("advReminderDisadvantageDexSave"); return conditions; } diff --git a/test/common.js b/test/common.js index a9aaaf8..19ccdd7 100644 --- a/test/common.js +++ b/test/common.js @@ -4,13 +4,36 @@ export default function commonTestInit() { globalThis.createActorWithFlags = (...keys) => { const actor = { flags: {}, + hasConditionEffect: () => false, + system: {}, }; keys.forEach((k) => setProperty(actor, k, true)); return actor; }; + globalThis.CONFIG = {}; + globalThis.CONFIG.DND5E = {}; + globalThis.CONFIG.DND5E.conditionEffects = {}; + // copied from Foundry + function filter(test) { + const filtered = new Set(); + let i = 0; + for ( const v of this ) { + if ( test(v, i, this) ) filtered.add(v); + i++; + } + return filtered; + } + function toObject() { + return Array.from(this); + } + Object.defineProperties(Set.prototype, { + filter: {value: filter}, + toObject: {value: toObject} + }); + globalThis.setProperty = (object, key, value) => { // split the key into parts, removing the last one const parts = key.split(".");