From ddfab1813e6b47d904c98bdaf731423c5a2cc205 Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Thu, 3 Nov 2022 21:41:44 +0100 Subject: [PATCH] refactor: extract active effect application to DS4ActiveEffect --- src/active-effect/active-effect.ts | 41 ++++++++++++++++++++++++++---- src/actor/actor.ts | 33 ++++++------------------ src/item/item.ts | 16 ++---------- 3 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/active-effect/active-effect.ts b/src/active-effect/active-effect.ts index 6aa13ebe..68049d7a 100644 --- a/src/active-effect/active-effect.ts +++ b/src/active-effect/active-effect.ts @@ -2,11 +2,12 @@ // // SPDX-License-Identifier: MIT -import { DS4Actor } from "../actor/actor"; import { mathEvaluator } from "../expression-evaluation/evaluator"; import { getGame } from "../helpers"; +import type { DS4Actor } from "../actor/actor"; import type { DS4Item } from "../item/item"; + declare global { interface DocumentClassConfig { ActiveEffect: typeof DS4ActiveEffect; @@ -52,7 +53,7 @@ export class DS4ActiveEffect extends ActiveEffect { * The item which this effect originates from if it has been transferred from an item to an actor. */ get originatingItem(): DS4Item | undefined { - if (!(this.parent instanceof DS4Actor)) { + if (!(this.parent instanceof Actor)) { return; } const itemIdRegex = /Item\.([a-zA-Z0-9]+)/; @@ -127,12 +128,42 @@ export class DS4ActiveEffect extends ActiveEffect { return result as number | `${number | boolean}`; } + /** + * Apply the given effects to the gicen Actor or item. + * @param document The Actor or Item to which to apply the effects + * @param effetcs The effects to apply + * @param predicate Apply only changes that fullfill this predicate + */ + static applyEffetcs( + document: DS4Actor | DS4Item, + effetcs: DS4ActiveEffect[], + predicate: (change: EffectChangeData) => boolean = () => true, + ): void { + const overrides: Record = {}; + + // Organize non-disabled and -surpressed effects by their application priority + const changesWithEffect = effetcs.flatMap((e) => e.getFactoredChangesWithEffect(predicate)); + changesWithEffect.sort((a, b) => (a.change.priority ?? 0) - (b.change.priority ?? 0)); + + // Apply all changes + for (const changeWithEffect of changesWithEffect) { + const result = changeWithEffect.effect.apply(document, changeWithEffect.change); + if (result !== null) overrides[changeWithEffect.change.key] = result; + } + + // Expand the set of final overrides + document.overrides = foundry.utils.expandObject({ + ...foundry.utils.flattenObject(document.overrides), + ...overrides, + }); + } + /** * Get the array of changes for this effect, considering the {@link DS4ActiveEffect#factor}. * @param predicate An optional predicate to filter which changes should be considered * @returns The array of changes from this effect, considering the factor. */ - getFactoredChangesWithEffect( + protected getFactoredChangesWithEffect( predicate: (change: EffectChangeData) => boolean = () => true, ): EffectChangeDataWithEffect[] { if (this.data.disabled || this.isSurpressed) { @@ -146,5 +177,5 @@ export class DS4ActiveEffect extends ActiveEffect { } } -export type EffectChangeData = foundry.data.ActiveEffectData["changes"][number]; -export type EffectChangeDataWithEffect = { effect: DS4ActiveEffect; change: EffectChangeData }; +type EffectChangeData = foundry.data.ActiveEffectData["changes"][number]; +type EffectChangeDataWithEffect = { effect: DS4ActiveEffect; change: EffectChangeData }; diff --git a/src/actor/actor.ts b/src/actor/actor.ts index 538eb8a9..7c87d4d9 100644 --- a/src/actor/actor.ts +++ b/src/actor/actor.ts @@ -3,6 +3,7 @@ // // SPDX-License-Identifier: MIT +import { DS4ActiveEffect } from "../active-effect/active-effect"; import { DS4 } from "../config"; import { mathEvaluator } from "../expression-evaluation/evaluator"; import { getGame } from "../helpers"; @@ -16,7 +17,7 @@ import type { DS4Item } from "../item/item"; import type { ItemType } from "../item/item-data-source"; import type { DS4ShieldDataProperties } from "../item/shield/shield-data-properties"; import type { Check } from "./actor-data-properties-base"; -import type { EffectChangeData } from "../active-effect/active-effect"; + declare global { interface DocumentClassConfig { Actor: typeof DS4Actor; @@ -105,7 +106,9 @@ export class DS4Actor extends Actor { applyActiveEffectsToBaseData(): void { // reset overrides because our variant of applying active effects does not set them, it only adds overrides this.overrides = {}; - this.applyActiveEffectsFiltered( + DS4ActiveEffect.applyEffetcs( + this, + this.actorEffects, (change) => !this.derivedDataProperties.includes(change.key) && !this.finalDerivedDataProperties.includes(change.key), @@ -113,29 +116,9 @@ export class DS4Actor extends Actor { } applyActiveEffectsToDerivedData(): void { - this.applyActiveEffectsFiltered((change) => this.derivedDataProperties.includes(change.key)); - } - - /** - * Apply ActiveEffectChanges to the Actor data which are caused by ActiveEffects and satisfy the given predicate. - * - * @param predicate - The predicate that ActiveEffectChanges need to satisfy in order to be applied - */ - applyActiveEffectsFiltered(predicate: (change: EffectChangeData) => boolean): void { - const overrides: Record = {}; - - // Organize non-disabled and -surpressed effects by their application priority - const changesWithEffect = this.actorEffects.flatMap((e) => e.getFactoredChangesWithEffect(predicate)); - changesWithEffect.sort((a, b) => (a.change.priority ?? 0) - (b.change.priority ?? 0)); - - // Apply all changes - for (const changeWithEffect of changesWithEffect) { - const result = changeWithEffect.effect.apply(this, changeWithEffect.change); - if (result !== null) overrides[changeWithEffect.change.key] = result; - } - - // Expand the set of final overrides - this.overrides = foundry.utils.expandObject({ ...foundry.utils.flattenObject(this.overrides), ...overrides }); + DS4ActiveEffect.applyEffetcs(this, this.actorEffects, (change) => + this.derivedDataProperties.includes(change.key), + ); } /** diff --git a/src/item/item.ts b/src/item/item.ts index 7b5ae881..9b3e8db4 100644 --- a/src/item/item.ts +++ b/src/item/item.ts @@ -3,6 +3,7 @@ // // SPDX-License-Identifier: MIT +import { DS4ActiveEffect } from "../active-effect/active-effect"; import { getGame } from "../helpers"; import type { ItemType } from "./item-data-source"; @@ -41,20 +42,7 @@ export class DS4Item extends Item { } this.overrides = {}; - const overrides: Record = {}; - - // Organize non-disabled and -surpressed effects by their application priority - const changesWithEffect = this.actor?.itemEffects(this).flatMap((e) => e.getFactoredChangesWithEffect()) ?? []; - changesWithEffect.sort((a, b) => (a.change.priority ?? 0) - (b.change.priority ?? 0)); - - // Apply all changes - for (const changeWithEffect of changesWithEffect) { - const result = changeWithEffect.effect.apply(this, changeWithEffect.change); - if (result !== null) overrides[changeWithEffect.change.key] = result; - } - - // Expand the set of final overrides - this.overrides = foundry.utils.expandObject({ ...foundry.utils.flattenObject(this.overrides), ...overrides }); + DS4ActiveEffect.applyEffetcs(this, this.actor.itemEffects(this)); } override prepareDerivedData(): void {