refactor: extract active effect application to DS4ActiveEffect

This commit is contained in:
Johannes Loher 2022-11-03 21:41:44 +01:00
parent b1ed05a796
commit ddfab1813e
3 changed files with 46 additions and 44 deletions

View file

@ -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<string, unknown> = {};
// 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 };

View file

@ -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<string, unknown> = {};
// 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),
);
}
/**

View file

@ -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<string, unknown> = {};
// 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 {