ds4/src/item/item.ts
Johannes Loher b1ed05a796 feat: add functionality to apply Active Affects to owned Items
In the Active Effect Config, there are now additional inputs to configure the effect
to be applied to items owned by the actor instead of the actor itself. It is possible
to select the items to which to apply the effect via matching by name, or via a condition
expression, that provides similar capabilities as the evaluation of mathematical
expressions in rolls. Data from the Actor, Item, and Active Effect can be accessed
similar to how properties are accessed in roll formulas (using the prefixes `@actor`,
`@item`, and `@effect`). For example, in order to apply an effect to all ranged
weapons, the conditions would be
```js
'@item.type' === 'weapon' && '@item.data.attackType' === 'ranged'
```
2022-11-03 22:14:36 +01:00

90 lines
2.8 KiB
TypeScript

// SPDX-FileCopyrightText: 2021 Johannes Loher
// SPDX-FileCopyrightText: 2021 Gesina Schwalbe
//
// SPDX-License-Identifier: MIT
import { getGame } from "../helpers";
import type { ItemType } from "./item-data-source";
declare global {
interface DocumentClassConfig {
Item: typeof DS4Item;
}
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace Hooks {
interface StaticCallbacks {
"ds4.rollItem": (item: DS4Item) => void;
}
}
}
/**
* The Item class for DS4
*/
export class DS4Item extends Item {
/** An object that tracks the changes to the data model which were applied by active effects */
overrides: Record<string, unknown> = {};
override prepareData() {
this.data.reset();
this.prepareBaseData();
this.prepareEmbeddedDocuments();
this.prepareDerivedData();
this.applyActiveEffects();
}
applyActiveEffects(): void {
if (!this.actor?.initialized) {
return;
}
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 });
}
override prepareDerivedData(): void {
this.data.data.rollable = false;
}
isNonEquippedEuipable(): boolean {
return "equipped" in this.data.data && !this.data.data.equipped;
}
/**
* The number of times that active effect changes originating from this item should be applied.
*/
get activeEffectFactor(): number | undefined {
return 1;
}
/**
* The list of item types that are rollable.
*/
static get rollableItemTypes(): ItemType[] {
return ["weapon", "spell"];
}
/**
* Roll a check for an action with this item.
* @param options - Additional options to customize the roll
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async roll(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise<void> {
throw new Error(getGame().i18n.format("DS4.ErrorRollingForItemTypeNotPossible", { type: this.data.type }));
}
}