refactor: convert to ECMAScript where necessary
Also drop @league-of-foundry-developers/foundry-vtt-types.
This commit is contained in:
parent
df4538f6ed
commit
6277e27056
69 changed files with 1077 additions and 1679 deletions
|
@ -11,24 +11,12 @@ import { getGame } from "../../utils/utils";
|
|||
import { DS4ActiveEffect } from "../active-effect";
|
||||
import { isAttribute, isTrait } from "./actor-data-source-base";
|
||||
|
||||
import type { ModifiableDataBaseTotal } from "../common/common-data";
|
||||
import type { DS4ArmorDataProperties } from "../item/armor/armor-data-properties";
|
||||
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";
|
||||
|
||||
declare global {
|
||||
interface DocumentClassConfig {
|
||||
Actor: typeof DS4Actor;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The Actor class for DS4
|
||||
*/
|
||||
export class DS4Actor extends Actor {
|
||||
override prepareData(): void {
|
||||
/** @override */
|
||||
prepareData() {
|
||||
this.data.reset();
|
||||
this.prepareBaseData();
|
||||
this.prepareEmbeddedDocuments();
|
||||
|
@ -39,7 +27,8 @@ export class DS4Actor extends Actor {
|
|||
this.prepareFinalDerivedData();
|
||||
}
|
||||
|
||||
override prepareBaseData(): void {
|
||||
/** @override */
|
||||
prepareBaseData() {
|
||||
const data = this.data;
|
||||
|
||||
data.data.rolling = {
|
||||
|
@ -48,17 +37,14 @@ export class DS4Actor extends Actor {
|
|||
};
|
||||
|
||||
const attributes = data.data.attributes;
|
||||
Object.values(attributes).forEach(
|
||||
(attribute: ModifiableDataBaseTotal<number>) => (attribute.total = attribute.base + attribute.mod),
|
||||
);
|
||||
Object.values(attributes).forEach((attribute) => (attribute.total = attribute.base + attribute.mod));
|
||||
|
||||
const traits = data.data.traits;
|
||||
Object.values(traits).forEach(
|
||||
(trait: ModifiableDataBaseTotal<number>) => (trait.total = trait.base + trait.mod),
|
||||
);
|
||||
Object.values(traits).forEach((trait) => (trait.total = trait.base + trait.mod));
|
||||
}
|
||||
|
||||
override prepareEmbeddedDocuments() {
|
||||
/** @override */
|
||||
prepareEmbeddedDocuments() {
|
||||
super.prepareEmbeddedDocuments();
|
||||
this.applyActiveEffectsToItems();
|
||||
}
|
||||
|
@ -71,16 +57,21 @@ export class DS4Actor extends Actor {
|
|||
this.data.data.armorValueSpellMalus = this.armorValueSpellMalusOfEquippedItems;
|
||||
}
|
||||
|
||||
protected get actorEffects() {
|
||||
/**
|
||||
* The effects that should be applioed to this actor.
|
||||
* @type {this["effects"]}
|
||||
* @protected
|
||||
*/
|
||||
get actorEffects() {
|
||||
return this.effects.filter((effect) => !effect.data.flags.ds4?.itemEffectConfig?.applyToItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the effects of this actor that should be applied to the given item.
|
||||
* @param item The item for which to get effects
|
||||
* @param {import("../item/item").DS4Item} item The item for which to get effects
|
||||
* @returns The array of effects that are candidates to be applied to the item
|
||||
*/
|
||||
itemEffects(item: DS4Item) {
|
||||
itemEffects(item) {
|
||||
return this.effects.filter((effect) => {
|
||||
const { applyToItems, itemName, condition } = effect.data.flags.ds4?.itemEffectConfig ?? {};
|
||||
|
||||
|
@ -106,7 +97,14 @@ export class DS4Actor extends Actor {
|
|||
});
|
||||
}
|
||||
|
||||
protected static replaceFormulaData(formula: string, data: object): string | undefined {
|
||||
/**
|
||||
* Replace placholders in a formula with data.
|
||||
* @param {string} formula The formular to enricht with data
|
||||
* @param {object} data The data to use for enriching
|
||||
* @returns {string | undefined} The Enriched formula or undefined, if it contains placeholders that cannot be resolved
|
||||
* @protected
|
||||
*/
|
||||
static replaceFormulaData(formula, data) {
|
||||
const dataRgx = new RegExp(/@([a-z.0-9_\-]+)/gi);
|
||||
try {
|
||||
return formula.replace(dataRgx, (_, term) => {
|
||||
|
@ -124,8 +122,9 @@ export class DS4Actor extends Actor {
|
|||
/**
|
||||
* We override this with an empty implementation because we have our own custom way of applying
|
||||
* {@link ActiveEffect}s and {@link Actor#prepareEmbeddedDocuments} calls this.
|
||||
* @override
|
||||
*/
|
||||
override applyActiveEffects(): void {
|
||||
applyActiveEffects() {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -138,7 +137,7 @@ export class DS4Actor extends Actor {
|
|||
* no special ordering among talents. This means that having a talents that provide effects that adjust the total
|
||||
* rank of talents can lead to nondeterministic behavior and thus must be avoided.
|
||||
*/
|
||||
applyActiveEffectsToItems(): void {
|
||||
applyActiveEffectsToItems() {
|
||||
/* Handle talents before all other item types, because their rank might be affected, which in turn affects how
|
||||
many times effects provided by that talent are applied */
|
||||
for (const item of this.itemTypes.talent) {
|
||||
|
@ -150,12 +149,21 @@ export class DS4Actor extends Actor {
|
|||
}
|
||||
}
|
||||
|
||||
protected applyActiveEffectsToItem(item: DS4Item) {
|
||||
/**
|
||||
* Apply effects to the given item.
|
||||
* @param {import("../item/item").DS4Item} item The item to which to apply effects
|
||||
* @protected
|
||||
*/
|
||||
applyActiveEffectsToItem(item) {
|
||||
item.overrides = {};
|
||||
DS4ActiveEffect.applyEffetcs(item, this.itemEffects(item));
|
||||
}
|
||||
|
||||
applyActiveEffectsToBaseData(): void {
|
||||
/**
|
||||
* Apply effects to base data
|
||||
* @protected
|
||||
*/
|
||||
applyActiveEffectsToBaseData() {
|
||||
this.overrides = {};
|
||||
DS4ActiveEffect.applyEffetcs(
|
||||
this,
|
||||
|
@ -166,7 +174,11 @@ export class DS4Actor extends Actor {
|
|||
);
|
||||
}
|
||||
|
||||
applyActiveEffectsToDerivedData(): void {
|
||||
/**
|
||||
* Apply effects to derived data
|
||||
* @protected
|
||||
*/
|
||||
applyActiveEffectsToDerivedData() {
|
||||
DS4ActiveEffect.applyEffetcs(this, this.actorEffects, (change) =>
|
||||
this.derivedDataProperties.includes(change.key),
|
||||
);
|
||||
|
@ -174,8 +186,9 @@ export class DS4Actor extends Actor {
|
|||
|
||||
/**
|
||||
* Apply transformations to the Actor data after effects have been applied to the base data.
|
||||
* @override
|
||||
*/
|
||||
override prepareDerivedData(): void {
|
||||
prepareDerivedData() {
|
||||
this.data.data.armorValueSpellMalus = Math.max(this.data.data.armorValueSpellMalus, 0);
|
||||
this.prepareCombatValues();
|
||||
this.prepareChecks();
|
||||
|
@ -183,8 +196,9 @@ export class DS4Actor extends Actor {
|
|||
|
||||
/**
|
||||
* The list of properties that are derived from others, given in dot notation.
|
||||
* @returns {string[]} The list of derived propertie
|
||||
*/
|
||||
get derivedDataProperties(): Array<string> {
|
||||
get derivedDataProperties() {
|
||||
const combatValueProperties = Object.keys(DS4.i18n.combatValues).map(
|
||||
(combatValue) => `data.combatValues.${combatValue}.total`,
|
||||
);
|
||||
|
@ -197,20 +211,14 @@ export class DS4Actor extends Actor {
|
|||
/**
|
||||
* Apply final transformations to the Actor data after all effects have been applied.
|
||||
*/
|
||||
prepareFinalDerivedData(): void {
|
||||
Object.values(this.data.data.attributes).forEach(
|
||||
(attribute: ModifiableDataBaseTotal<number>) => (attribute.total = Math.ceil(attribute.total)),
|
||||
);
|
||||
Object.values(this.data.data.traits).forEach(
|
||||
(trait: ModifiableDataBaseTotal<number>) => (trait.total = Math.ceil(trait.total)),
|
||||
);
|
||||
prepareFinalDerivedData() {
|
||||
Object.values(this.data.data.attributes).forEach((attribute) => (attribute.total = Math.ceil(attribute.total)));
|
||||
Object.values(this.data.data.traits).forEach((trait) => (trait.total = Math.ceil(trait.total)));
|
||||
Object.entries(this.data.data.combatValues)
|
||||
.filter(([key]) => key !== "movement")
|
||||
.map(([, value]) => value)
|
||||
.forEach(
|
||||
(combatValue: ModifiableDataBaseTotal<number>) => (combatValue.total = Math.ceil(combatValue.total)),
|
||||
);
|
||||
(Object.keys(this.data.data.checks) as (keyof typeof this.data.data.checks)[]).forEach((key) => {
|
||||
.forEach((combatValue) => (combatValue.total = Math.ceil(combatValue.total)));
|
||||
Object.keys(this.data.data.checks).forEach((key) => {
|
||||
this.data.data.checks[key] = Math.ceil(this.data.data.checks[key]);
|
||||
});
|
||||
|
||||
|
@ -221,30 +229,34 @@ export class DS4Actor extends Actor {
|
|||
/**
|
||||
* The list of properties that are completely derived (i.e. {@link ActiveEffect}s cannot be applied to them),
|
||||
* given in dot notation.
|
||||
* @type {string[]}
|
||||
*/
|
||||
get finalDerivedDataProperties(): string[] {
|
||||
get finalDerivedDataProperties() {
|
||||
return ["data.combatValues.hitPoints.max", "data.checks.defend"];
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of item types that can be owned by this actor.
|
||||
* @type {import("../item/item-data-source").ItemType[]}
|
||||
*/
|
||||
get ownableItemTypes(): Array<ItemType> {
|
||||
get ownableItemTypes() {
|
||||
return ["weapon", "armor", "shield", "equipment", "loot", "spell"];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether or not the given item type can be owned by the actor.
|
||||
* @param itemType - The item type to check
|
||||
* @param {import("../item/item-data-source").ItemType} itemType The item type to check
|
||||
* @returns {boolean} Whether or not this actor can own the given item type
|
||||
*/
|
||||
canOwnItemType(itemType: ItemType): boolean {
|
||||
canOwnItemType(itemType) {
|
||||
return this.ownableItemTypes.includes(itemType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the combat values of the actor.
|
||||
* Prepares the combat values of the actor.
|
||||
* @protected
|
||||
*/
|
||||
protected prepareCombatValues(): void {
|
||||
prepareCombatValues() {
|
||||
const data = this.data.data;
|
||||
|
||||
data.combatValues.hitPoints.base = data.attributes.body.total + data.traits.constitution.total + 10;
|
||||
|
@ -260,21 +272,25 @@ export class DS4Actor extends Actor {
|
|||
data.attributes.mind.total + data.traits.dexterity.total - data.armorValueSpellMalus;
|
||||
|
||||
Object.values(data.combatValues).forEach(
|
||||
(combatValue: ModifiableDataBaseTotal<number>) => (combatValue.total = combatValue.base + combatValue.mod),
|
||||
(combatValue) => (combatValue.total = combatValue.base + combatValue.mod),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The total armor value of the equipped items.
|
||||
* @type {number}
|
||||
* @protected
|
||||
*/
|
||||
protected get armorValueOfEquippedItems(): number {
|
||||
get armorValueOfEquippedItems() {
|
||||
return this.equippedItemsWithArmor.map((item) => item.data.data.armorValue).reduce((a, b) => a + b, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* The armor value spell malus from equipped items.
|
||||
* @type {number}
|
||||
* @protected
|
||||
*/
|
||||
protected get armorValueSpellMalusOfEquippedItems(): number {
|
||||
get armorValueSpellMalusOfEquippedItems() {
|
||||
return this.equippedItemsWithArmor
|
||||
.filter(
|
||||
(item) =>
|
||||
|
@ -284,19 +300,22 @@ export class DS4Actor extends Actor {
|
|||
.reduce((a, b) => a + b, 0);
|
||||
}
|
||||
|
||||
protected get equippedItemsWithArmor() {
|
||||
/**
|
||||
* The equipped items of this actor that provide armor.
|
||||
* @type {(import("../item/armor/armor").DS4Armor | import("../item/shield/shield").DS4Shield)[]}
|
||||
* @protected
|
||||
*/
|
||||
get equippedItemsWithArmor() {
|
||||
return this.items
|
||||
.filter(
|
||||
(item): item is DS4Item & { data: DS4ArmorDataProperties | DS4ShieldDataProperties } =>
|
||||
item.data.type === "armor" || item.data.type === "shield",
|
||||
)
|
||||
.filter((item) => item.data.type === "armor" || item.data.type === "shield")
|
||||
.filter((item) => item.data.data.equipped);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the check target numbers of checks for the actor.
|
||||
* @protected
|
||||
*/
|
||||
protected prepareChecks(): void {
|
||||
prepareChecks() {
|
||||
const data = this.data.data;
|
||||
data.checks = {
|
||||
appraise: data.attributes.mind.total + data.traits.intellect.total,
|
||||
|
@ -334,17 +353,14 @@ export class DS4Actor extends Actor {
|
|||
/**
|
||||
* Handle how changes to a Token attribute bar are applied to the Actor.
|
||||
* This only differs from the base implementation by also allowing negative values.
|
||||
* @override
|
||||
*/
|
||||
override async modifyTokenAttribute(
|
||||
attribute: string,
|
||||
value: number,
|
||||
isDelta = false,
|
||||
isBar = true,
|
||||
): Promise<this | undefined> {
|
||||
async modifyTokenAttribute(attribute, value, isDelta = false, isBar = true) {
|
||||
const current = foundry.utils.getProperty(this.data.data, attribute);
|
||||
|
||||
// Determine the updates to make to the actor data
|
||||
let updates: Record<string, number>;
|
||||
/** @type {Record<string, number>} */
|
||||
let updates;
|
||||
if (isBar) {
|
||||
if (isDelta) value = Math.min(Number(current.value) + value, current.max);
|
||||
updates = { [`data.${attribute}.value`]: value };
|
||||
|
@ -360,13 +376,11 @@ export class DS4Actor extends Actor {
|
|||
|
||||
/**
|
||||
* Roll for a given check.
|
||||
* @param check - The check to perform
|
||||
* @param options - Additional options to customize the roll
|
||||
* @param {import("./actor-data-properties-base").Check} check The check to perform
|
||||
* @param {import("../common/roll-options").RollOptions} [options={}] Additional options to customize the roll
|
||||
* @returns {Promise<void>} A promise that resolves once the roll has been performed
|
||||
*/
|
||||
async rollCheck(
|
||||
check: Check,
|
||||
options: { speaker?: { token?: TokenDocument; alias?: string } } = {},
|
||||
): Promise<void> {
|
||||
async rollCheck(check, options = {}) {
|
||||
const speaker = ChatMessage.getSpeaker({ actor: this, ...options.speaker });
|
||||
await createCheckRoll(this.data.data.checks[check], {
|
||||
rollMode: getGame().settings.get("core", "rollMode"),
|
||||
|
@ -381,9 +395,10 @@ export class DS4Actor extends Actor {
|
|||
/**
|
||||
* Roll a generic check. A dialog is presented to select the combination of
|
||||
* Attribute and Trait to perform the check against.
|
||||
* @param options - Additional options to customize the roll
|
||||
* @param {import("../common/roll-options").RollOptions} [options={}] Additional options to customize the roll
|
||||
* @returns {Promise<void>} A promise that resolves once the roll has been performed
|
||||
*/
|
||||
async rollGenericCheck(options: { speaker?: { token?: TokenDocument; alias?: string } } = {}): Promise<void> {
|
||||
async rollGenericCheck(options = {}) {
|
||||
const attributeAndTrait = await this.selectAttributeAndTrait();
|
||||
if (!attributeAndTrait) {
|
||||
return;
|
||||
|
@ -405,10 +420,12 @@ export class DS4Actor extends Actor {
|
|||
});
|
||||
}
|
||||
|
||||
protected async selectAttributeAndTrait(): Promise<{
|
||||
attribute: keyof typeof DS4.i18n.attributes;
|
||||
trait: keyof typeof DS4.i18n.traits;
|
||||
} | null> {
|
||||
/**
|
||||
* Prompt the use to select an attribute and a trait.
|
||||
* @returns {Promise<AttributeAndTrait | null>}
|
||||
* @protected
|
||||
*/
|
||||
async selectAttributeAndTrait() {
|
||||
const attributeIdentifier = "attribute-trait-selection-attribute";
|
||||
const traitIdentifier = "attribute-trait-selection-trait";
|
||||
return Dialog.prompt({
|
||||
|
@ -419,24 +436,20 @@ export class DS4Actor extends Actor {
|
|||
label: getGame().i18n.localize("DS4.Attribute"),
|
||||
identifier: attributeIdentifier,
|
||||
options: Object.fromEntries(
|
||||
(Object.entries(DS4.i18n.attributes) as [keyof typeof DS4.i18n.attributes, string][]).map(
|
||||
([attribute, translation]) => [
|
||||
attribute,
|
||||
`${translation} (${this.data.data.attributes[attribute].total})`,
|
||||
],
|
||||
),
|
||||
Object.entries(DS4.i18n.attributes).map(([attribute, translation]) => [
|
||||
attribute,
|
||||
`${translation} (${this.data.data.attributes[attribute].total})`,
|
||||
]),
|
||||
),
|
||||
},
|
||||
{
|
||||
label: getGame().i18n.localize("DS4.Trait"),
|
||||
identifier: traitIdentifier,
|
||||
options: Object.fromEntries(
|
||||
(Object.entries(DS4.i18n.traits) as [keyof typeof DS4.i18n.traits, string][]).map(
|
||||
([trait, translation]) => [
|
||||
trait,
|
||||
`${translation} (${this.data.data.traits[trait].total})`,
|
||||
],
|
||||
),
|
||||
Object.entries(DS4.i18n.traits).map(([trait, translation]) => [
|
||||
trait,
|
||||
`${translation} (${this.data.data.traits[trait].total})`,
|
||||
]),
|
||||
),
|
||||
},
|
||||
],
|
||||
|
@ -474,3 +487,9 @@ export class DS4Actor extends Actor {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {object} AttributeAndTrait
|
||||
* @property {keyof typeof DS4.i18n.attributes} attribute
|
||||
* @property {keyof typeof DS4.i18n.traits} trait
|
||||
*/
|
|
@ -4,23 +4,20 @@
|
|||
|
||||
import { DS4Actor } from "../actor";
|
||||
|
||||
import type { ItemType } from "../../item/item-data-source";
|
||||
|
||||
export class DS4Character extends DS4Actor {
|
||||
override prepareFinalDerivedData(): void {
|
||||
/** @override */
|
||||
prepareFinalDerivedData() {
|
||||
super.prepareFinalDerivedData();
|
||||
this.data.data.slayerPoints.max = 3;
|
||||
}
|
||||
|
||||
override get finalDerivedDataProperties(): string[] {
|
||||
/** @override */
|
||||
get finalDerivedDataProperties() {
|
||||
return [...super.finalDerivedDataProperties, "data.slayerPoints.max"];
|
||||
}
|
||||
|
||||
override get ownableItemTypes(): Array<ItemType> {
|
||||
/** @override */
|
||||
get ownableItemTypes() {
|
||||
return [...super.ownableItemTypes, "talent", "racialAbility", "language", "alphabet"];
|
||||
}
|
||||
}
|
||||
|
||||
export interface DS4Character {
|
||||
data: foundry.data.ActorData & { type: "character"; _source: { type: "character" } };
|
||||
}
|
|
@ -11,7 +11,3 @@ export class DS4Creature extends DS4Actor {
|
|||
return [...super.ownableItemTypes, "specialCreatureAbility"];
|
||||
}
|
||||
}
|
||||
|
||||
export interface DS4Creature {
|
||||
data: foundry.data.ActorData & { type: "creature"; _source: { type: "creature" } };
|
||||
}
|
||||
|
|
|
@ -8,7 +8,11 @@ import { DS4Character } from "./character/character";
|
|||
import { DS4Creature } from "./creature/creature";
|
||||
|
||||
const handler = {
|
||||
construct(_: typeof DS4Actor, args: ConstructorParameters<typeof DS4Actor>) {
|
||||
/**
|
||||
* @param {typeof import("./actor").DS4Actor}
|
||||
* @param {unknown[]} args
|
||||
*/
|
||||
construct(_, args) {
|
||||
switch (args[0]?.type) {
|
||||
case "character":
|
||||
return new DS4Character(...args);
|
||||
|
@ -20,4 +24,5 @@ const handler = {
|
|||
},
|
||||
};
|
||||
|
||||
export const DS4ActorProxy: typeof DS4Actor = new Proxy(DS4Actor, handler);
|
||||
/** @type {typeof import("./actor").DS4Actor} */
|
||||
export const DS4ActorProxy = new Proxy(DS4Actor, handler);
|
Loading…
Add table
Add a link
Reference in a new issue