diff --git a/src/module/active-effect.ts b/src/module/active-effect.ts index 8d53ba28..8a029c4d 100644 --- a/src/module/active-effect.ts +++ b/src/module/active-effect.ts @@ -4,6 +4,7 @@ import { DS4Actor } from "./actor/actor"; import { getGame } from "./helpers"; +import { DS4Item } from "./item/item"; declare global { interface DocumentClassConfig { @@ -12,6 +13,7 @@ declare global { } type PromisedType = T extends Promise ? U : T; + export class DS4ActiveEffect extends ActiveEffect { /** * A fallback icon that can be used if no icon is defined for the effect. @@ -23,6 +25,38 @@ export class DS4ActiveEffect extends ActiveEffect { */ protected source: PromisedType> | undefined = undefined; + /** + * Whether or not this effect is currently surpressed. + */ + get isSurpressed(): boolean { + const originatingItem = this.originatingItem; + if (!originatingItem) { + return false; + } + return originatingItem.isNonEquippedEuipable(); + } + + /** + * 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)) { + return; + } + const [, , , itemId] = this.data.origin?.split(".") ?? []; + if (!itemId) { + return; + } + return this.parent.items.get(itemId); + } + + /** + * The number of times this effect should be applied. + */ + get factor(): number { + return this.originatingItem?.activeEffectFactor ?? 1; + } + /** @override */ apply(actor: DS4Actor, change: foundry.data.ActiveEffectData["changes"][number]): unknown { change.value = Roll.replaceFormulaData(change.value, actor.data); @@ -54,4 +88,21 @@ export class DS4ActiveEffect extends ActiveEffect { } return this.source; } + + /** + * Create a new {@link DS4ActiveEffect} using default data. + * + * @param context The context for the creation of the effect, requiring a parent {@link DS4Actor} or {@link DS4Item}. + * @returns A promise that resolved to the created effect or udifined of the creation was prevented. + */ + static async createDefault( + context: DocumentModificationContext & { parent: DS4Actor | DS4Item }, + ): Promise { + const createData = { + label: getGame().i18n.localize(`DS4.NewEffectLabel`), + icon: this.FALLBACK_ICON, + }; + + return this.create(createData, context); + } } diff --git a/src/module/actor/actor.ts b/src/module/actor/actor.ts index d2b12635..34051c40 100644 --- a/src/module/actor/actor.ts +++ b/src/module/actor/actor.ts @@ -6,7 +6,6 @@ import { ModifiableDataBaseTotal } from "../common/common-data"; import { DS4 } from "../config"; import { getGame } from "../helpers"; -import { DS4Item } from "../item/item"; import { DS4ArmorDataProperties, DS4ShieldDataProperties } from "../item/item-data-properties"; import { ItemType } from "../item/item-data-source"; import { createCheckRoll } from "../rolls/check-factory"; @@ -85,20 +84,16 @@ export class DS4Actor extends Actor { applyActiveEffectsFiltered(predicate: (change: foundry.data.ActiveEffectData["changes"][number]) => boolean): void { const overrides: Record = {}; - // Organize non-disabled effects by their application priority + // Organize non-disabled and -surpressed effects by their application priority const changes: (foundry.data.ActiveEffectData["changes"][number] & { effect: ActiveEffect })[] = this.effects.reduce( (changes: (foundry.data.ActiveEffectData["changes"][number] & { effect: ActiveEffect })[], e) => { - if (e.data.disabled) return changes; - const item = this.getOriginatingItemOfActiveEffect(e); - if (item?.isNonEquippedEuipable()) return changes; - - const factor = item?.activeEffectFactor ?? 1; + if (e.data.disabled || e.isSurpressed) return changes; const newChanges = e.data.changes.filter(predicate).flatMap((c) => { const changeSource = c.toObject(); changeSource.priority = changeSource.priority ?? changeSource.mode * 10; - return Array(factor).fill({ ...changeSource, effect: e }); + return Array(e.factor).fill({ ...changeSource, effect: e }); }); return changes.concat(newChanges); @@ -117,10 +112,6 @@ export class DS4Actor extends Actor { this.overrides = foundry.utils.expandObject({ ...foundry.utils.flattenObject(this.overrides), ...overrides }); } - protected getOriginatingItemOfActiveEffect(effect: ActiveEffect): DS4Item | undefined { - return this.items.find((item) => item.uuid === effect.data.origin); - } - /** * Apply transformations to the Actor data after effects have been applied to the base data. * @override @@ -184,8 +175,6 @@ export class DS4Actor extends Actor { ]; case "creature": return ["weapon", "armor", "shield", "equipment", "loot", "spell", "specialCreatureAbility"]; - default: - return []; } } diff --git a/src/module/actor/sheets/actor-sheet.ts b/src/module/actor/sheets/actor-sheet.ts index 99e8829f..49fa1782 100644 --- a/src/module/actor/sheets/actor-sheet.ts +++ b/src/module/actor/sheets/actor-sheet.ts @@ -27,6 +27,7 @@ export class DS4ActorSheet extends ActorSheet /** * Create a new ActiveEffect for the item using default data. */ - protected async createActiveEffect(): Promise { - const createData = { - label: getGame().i18n.localize(`DS4.NewEffectLabel`), - icon: "icons/svg/aura.svg", - origin: this.item.uuid, - }; - - return ActiveEffect.create(createData, { parent: this.item }); + protected createActiveEffect(): void { + DS4ActiveEffect.createDefault({ parent: this.item }); } } diff --git a/src/templates/sheets/actor/tabs/effects.hbs b/src/templates/sheets/actor/tabs/effects.hbs index 67ed0a36..c8ff101b 100644 --- a/src/templates/sheets/actor/tabs/effects.hbs +++ b/src/templates/sheets/actor/tabs/effects.hbs @@ -7,7 +7,7 @@ SPDX-License-Identifier: MIT
{{#unless (isEmpty data.effects)}} -
    +
      {{> systems/ds4/templates/sheets/actor/components/effect-list-header.hbs}} {{#each enrichedEffects as |effectData id| }} {{> systems/ds4/templates/sheets/actor/components/effect-list-entry.hbs effectData=effectData}}