Merge branch '068-enable-strict-mode' into 050-basic-active-effects
This commit is contained in:
commit
b74ee5ec7c
45 changed files with 3088 additions and 2119 deletions
|
@ -1,15 +1,16 @@
|
|||
import { ModifiableData } from "../common/common-data";
|
||||
import { DS4 } from "../config";
|
||||
import { DS4Item } from "../item/item";
|
||||
import { DS4Armor, DS4EquippableItemDataType, DS4ItemDataType, DS4Shield, ItemType } from "../item/item-data";
|
||||
import { DS4ActorDataType } from "./actor-data";
|
||||
import { DS4ItemData, ItemType } from "../item/item-data";
|
||||
import { DS4ActorData } from "./actor-data";
|
||||
|
||||
type DS4ActiveEffect = ActiveEffect<DS4ActorDataType, DS4ItemDataType, DS4Actor, DS4Item>;
|
||||
|
||||
export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item> {
|
||||
/**
|
||||
* The Actor class for DS4
|
||||
*/
|
||||
export class DS4Actor extends Actor<DS4ActorData, DS4Item> {
|
||||
/** @override */
|
||||
prepareData(): void {
|
||||
this.data = duplicate(this._data);
|
||||
this.data = duplicate(this._data) as DS4ActorData;
|
||||
if (!this.data.img) this.data.img = CONST.DEFAULT_TOKEN;
|
||||
if (!this.data.name) this.data.name = "New " + this.entity;
|
||||
this.prepareBaseData();
|
||||
|
@ -45,20 +46,23 @@ export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item>
|
|||
* @param predicate The predicate that ActiveEffectChanges need to satisfy in order to be applied
|
||||
*/
|
||||
applyActiveEffectsFiltered(predicate: (change: ActiveEffectChange) => boolean): void {
|
||||
const overrides = {};
|
||||
const overrides: Record<string, unknown> = {};
|
||||
|
||||
// Organize non-disabled effects by their application priority
|
||||
const changes = this.effects.reduce((changes: Array<ActiveEffectChange & { effect: DS4ActiveEffect }>, e) => {
|
||||
if (e.data.disabled) return changes;
|
||||
const changes = this.effects.reduce(
|
||||
(changes: Array<ActiveEffectChange & { effect: ActiveEffect<DS4Actor> }>, e) => {
|
||||
if (e.data.disabled) return changes;
|
||||
|
||||
return changes.concat(
|
||||
e.data.changes.filter(predicate).map((c) => {
|
||||
c = duplicate(c);
|
||||
c.priority = c.priority ?? c.mode * 10;
|
||||
return { ...c, effect: e };
|
||||
}),
|
||||
);
|
||||
}, []);
|
||||
return changes.concat(
|
||||
e.data.changes.filter(predicate).map((c) => {
|
||||
const duplicatedChange = duplicate(c) as ActiveEffect.Change;
|
||||
duplicatedChange.priority = duplicatedChange.priority ?? duplicatedChange.mode * 10;
|
||||
return { ...duplicatedChange, effect: e };
|
||||
}),
|
||||
);
|
||||
},
|
||||
[],
|
||||
);
|
||||
changes.sort((a, b) => a.priority - b.priority);
|
||||
|
||||
// Apply all changes
|
||||
|
@ -68,7 +72,7 @@ export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item>
|
|||
}
|
||||
|
||||
// Expand the set of final overrides
|
||||
this["overrides"] = expandObject({ ...flattenObject(this["overrides"] ?? {}), ...overrides });
|
||||
this.overrides = expandObject({ ...flattenObject(this.overrides ?? {}), ...overrides });
|
||||
}
|
||||
|
||||
/** @override */
|
||||
|
@ -78,7 +82,7 @@ export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item>
|
|||
|
||||
/** The list of properties that are derived from others, given in dot notation */
|
||||
get derivedDataProperties(): Array<string> {
|
||||
return Object.keys(DS4.combatValues)
|
||||
return Object.keys(DS4.i18n.combatValues)
|
||||
.map((combatValue) => `data.combatValues.${combatValue}.total`)
|
||||
.concat("data.combatValues.hitPoints.max");
|
||||
}
|
||||
|
@ -110,7 +114,7 @@ export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item>
|
|||
|
||||
/**
|
||||
* Checks whether or not the given item type can be owned by the actor.
|
||||
* @param itemType the item type to check
|
||||
* @param itemType - The item type to check
|
||||
*/
|
||||
canOwnItemType(itemType: ItemType): boolean {
|
||||
return this.ownableItemTypes.includes(itemType);
|
||||
|
@ -149,10 +153,13 @@ export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item>
|
|||
*/
|
||||
private _calculateArmorValueOfEquippedItems(): number {
|
||||
return this.items
|
||||
.filter((item) => ["armor", "shield"].includes(item.type))
|
||||
.map((item) => item.data.data as DS4Armor | DS4Shield)
|
||||
.filter((itemData) => itemData.equipped)
|
||||
.map((itemData) => itemData.armorValue)
|
||||
.map((item) => {
|
||||
if (item.data.type === "armor" || item.data.type === "shield") {
|
||||
return item.data.data.equipped ? item.data.data.armorValue : 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
})
|
||||
.reduce((a, b) => a + b, 0);
|
||||
}
|
||||
|
||||
|
@ -161,7 +168,7 @@ export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item>
|
|||
* This only differs from the base implementation by also allowing negative values.
|
||||
* @override
|
||||
*/
|
||||
async modifyTokenAttribute(attribute: string, value: number, isDelta = false, isBar = true): Promise<DS4Actor> {
|
||||
async modifyTokenAttribute(attribute: string, value: number, isDelta = false, isBar = true): Promise<this> {
|
||||
const current = getProperty(this.data.data, attribute);
|
||||
|
||||
// Determine the updates to make to the actor data
|
||||
|
@ -180,59 +187,77 @@ export class DS4Actor extends Actor<DS4ActorDataType, DS4ItemDataType, DS4Item>
|
|||
}
|
||||
|
||||
/** @override */
|
||||
// TODO(types): Improve typing once it's fixed in upstream (arrays can be passed!)
|
||||
createEmbeddedEntity(
|
||||
embeddedName: string,
|
||||
createData: Record<string, unknown> | Array<Record<string, unknown>>,
|
||||
embeddedName: "OwnedItem",
|
||||
data: DeepPartial<DS4ItemData>,
|
||||
options?: Record<string, unknown>,
|
||||
): Promise<this> {
|
||||
): Promise<DS4ItemData>;
|
||||
createEmbeddedEntity(
|
||||
embeddedName: "ActiveEffect",
|
||||
data: DeepPartial<DS4ItemData>,
|
||||
options?: Record<string, unknown>,
|
||||
): Promise<ActiveEffect.Data>;
|
||||
createEmbeddedEntity(
|
||||
embeddedName: "OwnedItem" | "ActiveEffect",
|
||||
data: DeepPartial<DS4ItemData> | DeepPartial<ActiveEffect.Data>,
|
||||
options?: Record<string, unknown>,
|
||||
): Promise<DS4ItemData> | Promise<ActiveEffect.Data> {
|
||||
if (embeddedName === "OwnedItem") {
|
||||
this._preCreateOwnedItem((createData as unknown) as ItemData<DS4ItemDataType>);
|
||||
this._preCreateOwnedItem(data);
|
||||
return super.createEmbeddedEntity(embeddedName, data, options);
|
||||
}
|
||||
return super.createEmbeddedEntity(embeddedName, createData, options);
|
||||
return super.createEmbeddedEntity(embeddedName, data, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the item that is going to be created is equippable, set it to be non equipped and disable all ActiveEffects
|
||||
* If the item that is going to be created is equipable, set it to be non equipped and disable all ActiveEffects
|
||||
* contained in the item
|
||||
* @param itemData The data of the item to be created
|
||||
*/
|
||||
private _preCreateOwnedItem(itemData: ItemData<DS4ItemDataType>): void {
|
||||
if ("equipped" in itemData.data) {
|
||||
itemData.effects = itemData.effects.map((effect) => ({ ...effect, disabled: true }));
|
||||
const equippableUpdateData = itemData as ItemData<DS4EquippableItemDataType>;
|
||||
equippableUpdateData.data.equipped = false;
|
||||
protected _preCreateOwnedItem(itemData: DeepPartial<DS4ItemData>): void {
|
||||
if (itemData.data && "equipped" in itemData.data) {
|
||||
itemData.effects = itemData.effects?.map((effect) => ({ ...effect, disabled: true }));
|
||||
itemData.data.equipped = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
// TODO(types): Improve typing once it's fixed in upstream
|
||||
updateEmbeddedEntity(embeddedName: string, data: unknown[], options?: Entity.UpdateOptions): Promise<unknown[]>;
|
||||
updateEmbeddedEntity(embeddedName: string, data: unknown, options?: Entity.UpdateOptions): Promise<unknown>;
|
||||
updateEmbeddedEntity(
|
||||
embeddedName: string,
|
||||
updateData: Record<string, unknown> | Array<Record<string, unknown>>,
|
||||
updateData: unknown | unknown[],
|
||||
options?: Record<string, unknown>,
|
||||
): Promise<this> {
|
||||
): Promise<unknown> {
|
||||
if (embeddedName === "OwnedItem") {
|
||||
this._preUpdateOwnedItem(updateData as Partial<ItemData<DS4ItemDataType>>);
|
||||
this._preUpdateOwnedItem(updateData as DeepPartial<DS4ItemData> | Array<DeepPartial<DS4ItemData>>);
|
||||
}
|
||||
return super.updateEmbeddedEntity(embeddedName, updateData, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the equipped flag of an item changed, update all ActiveEffects originating from that item accordingly.
|
||||
* @param updateData The change that is going to be applied to the owned item
|
||||
* If the equipped flag of one or more items changed, update all ActiveEffects originating from those items
|
||||
* accordingly.
|
||||
* @param updateData The change that is going to be applied to the owned item(s)
|
||||
*/
|
||||
private _preUpdateOwnedItem(updateData: Partial<ItemData<DS4ItemDataType>>): void {
|
||||
if ("equipped" in updateData.data) {
|
||||
const equippableUpdateData = updateData as Partial<ItemData<DS4EquippableItemDataType>>;
|
||||
const origin = `Actor.${this.id}.OwnedItem.${updateData._id}`;
|
||||
const effects = this.effects
|
||||
.filter((e) => e.data.origin === origin)
|
||||
.map((e) => {
|
||||
const data = duplicate(e.data);
|
||||
data.disabled = !equippableUpdateData.data.equipped;
|
||||
return data;
|
||||
});
|
||||
if (effects.length > 0)
|
||||
this.updateEmbeddedEntity("ActiveEffect", (effects as unknown) as Record<string, unknown>);
|
||||
}
|
||||
private _preUpdateOwnedItem(updateData: DeepPartial<DS4ItemData> | Array<DeepPartial<DS4ItemData>>): void {
|
||||
const dataArray = updateData instanceof Array ? updateData : [updateData];
|
||||
dataArray.forEach((data) => {
|
||||
if (data.data && "equipped" in data.data) {
|
||||
const equipped = data.data.equipped;
|
||||
const origin = `Actor.${this.id}.OwnedItem.${data._id}`;
|
||||
const effects = this.effects
|
||||
.filter((e) => e.data.origin === origin)
|
||||
.map((e) => {
|
||||
const effectData = duplicate(e.data);
|
||||
effectData.disabled = !(equipped ?? true);
|
||||
return effectData;
|
||||
});
|
||||
if (effects.length > 0)
|
||||
this.updateEmbeddedEntity("ActiveEffect", (effects as unknown) as Record<string, unknown>);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue