Add drag & drop support for effects between different sheets
Also refactor some effect related functionality into the DS4ActiveEffect class
This commit is contained in:
parent
b1d0810100
commit
1e7368875c
5 changed files with 60 additions and 29 deletions
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
import { DS4Actor } from "./actor/actor";
|
import { DS4Actor } from "./actor/actor";
|
||||||
import { getGame } from "./helpers";
|
import { getGame } from "./helpers";
|
||||||
|
import { DS4Item } from "./item/item";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface DocumentClassConfig {
|
interface DocumentClassConfig {
|
||||||
|
@ -12,6 +13,7 @@ declare global {
|
||||||
}
|
}
|
||||||
|
|
||||||
type PromisedType<T> = T extends Promise<infer U> ? U : T;
|
type PromisedType<T> = T extends Promise<infer U> ? U : T;
|
||||||
|
|
||||||
export class DS4ActiveEffect extends ActiveEffect {
|
export class DS4ActiveEffect extends ActiveEffect {
|
||||||
/**
|
/**
|
||||||
* A fallback icon that can be used if no icon is defined for the effect.
|
* 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<ReturnType<typeof fromUuid>> | undefined = undefined;
|
protected source: PromisedType<ReturnType<typeof fromUuid>> | 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 */
|
/** @override */
|
||||||
apply(actor: DS4Actor, change: foundry.data.ActiveEffectData["changes"][number]): unknown {
|
apply(actor: DS4Actor, change: foundry.data.ActiveEffectData["changes"][number]): unknown {
|
||||||
change.value = Roll.replaceFormulaData(change.value, actor.data);
|
change.value = Roll.replaceFormulaData(change.value, actor.data);
|
||||||
|
@ -54,4 +88,21 @@ export class DS4ActiveEffect extends ActiveEffect {
|
||||||
}
|
}
|
||||||
return this.source;
|
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<DS4ActiveEffect | undefined> {
|
||||||
|
const createData = {
|
||||||
|
label: getGame().i18n.localize(`DS4.NewEffectLabel`),
|
||||||
|
icon: this.FALLBACK_ICON,
|
||||||
|
};
|
||||||
|
|
||||||
|
return this.create(createData, context);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
import { ModifiableDataBaseTotal } from "../common/common-data";
|
import { ModifiableDataBaseTotal } from "../common/common-data";
|
||||||
import { DS4 } from "../config";
|
import { DS4 } from "../config";
|
||||||
import { getGame } from "../helpers";
|
import { getGame } from "../helpers";
|
||||||
import { DS4Item } from "../item/item";
|
|
||||||
import { DS4ArmorDataProperties, DS4ShieldDataProperties } from "../item/item-data-properties";
|
import { DS4ArmorDataProperties, DS4ShieldDataProperties } from "../item/item-data-properties";
|
||||||
import { ItemType } from "../item/item-data-source";
|
import { ItemType } from "../item/item-data-source";
|
||||||
import { createCheckRoll } from "../rolls/check-factory";
|
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 {
|
applyActiveEffectsFiltered(predicate: (change: foundry.data.ActiveEffectData["changes"][number]) => boolean): void {
|
||||||
const overrides: Record<string, unknown> = {};
|
const overrides: Record<string, unknown> = {};
|
||||||
|
|
||||||
// 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 })[] =
|
const changes: (foundry.data.ActiveEffectData["changes"][number] & { effect: ActiveEffect })[] =
|
||||||
this.effects.reduce(
|
this.effects.reduce(
|
||||||
(changes: (foundry.data.ActiveEffectData["changes"][number] & { effect: ActiveEffect })[], e) => {
|
(changes: (foundry.data.ActiveEffectData["changes"][number] & { effect: ActiveEffect })[], e) => {
|
||||||
if (e.data.disabled) return changes;
|
if (e.data.disabled || e.isSurpressed) return changes;
|
||||||
const item = this.getOriginatingItemOfActiveEffect(e);
|
|
||||||
if (item?.isNonEquippedEuipable()) return changes;
|
|
||||||
|
|
||||||
const factor = item?.activeEffectFactor ?? 1;
|
|
||||||
|
|
||||||
const newChanges = e.data.changes.filter(predicate).flatMap((c) => {
|
const newChanges = e.data.changes.filter(predicate).flatMap((c) => {
|
||||||
const changeSource = c.toObject();
|
const changeSource = c.toObject();
|
||||||
changeSource.priority = changeSource.priority ?? changeSource.mode * 10;
|
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);
|
return changes.concat(newChanges);
|
||||||
|
@ -117,10 +112,6 @@ export class DS4Actor extends Actor {
|
||||||
this.overrides = foundry.utils.expandObject({ ...foundry.utils.flattenObject(this.overrides), ...overrides });
|
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.
|
* Apply transformations to the Actor data after effects have been applied to the base data.
|
||||||
* @override
|
* @override
|
||||||
|
@ -184,8 +175,6 @@ export class DS4Actor extends Actor {
|
||||||
];
|
];
|
||||||
case "creature":
|
case "creature":
|
||||||
return ["weapon", "armor", "shield", "equipment", "loot", "spell", "specialCreatureAbility"];
|
return ["weapon", "armor", "shield", "equipment", "loot", "spell", "specialCreatureAbility"];
|
||||||
default:
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
|
||||||
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "values" }],
|
tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "values" }],
|
||||||
dragDrop: [
|
dragDrop: [
|
||||||
{ dragSelector: ".item-list .item", dropSelector: null },
|
{ dragSelector: ".item-list .item", dropSelector: null },
|
||||||
|
{ dragSelector: ".effect-list .effect", dropSelector: null },
|
||||||
{ dragSelector: ".ds4-check", dropSelector: null },
|
{ dragSelector: ".ds4-check", dropSelector: null },
|
||||||
],
|
],
|
||||||
width: 650,
|
width: 650,
|
||||||
|
@ -202,12 +203,7 @@ export class DS4ActorSheet extends ActorSheet<ActorSheet.Options, DS4ActorSheetD
|
||||||
* @param event - The originating click event
|
* @param event - The originating click event
|
||||||
*/
|
*/
|
||||||
protected onCreateEffect(): void {
|
protected onCreateEffect(): void {
|
||||||
const effectData = {
|
DS4ActiveEffect.createDefault({ parent: this.actor });
|
||||||
label: getGame().i18n.localize(`DS4.NewEffectLabel`),
|
|
||||||
icon: "icons/svg/aura.svg",
|
|
||||||
origin: this.actor.uuid,
|
|
||||||
};
|
|
||||||
ActiveEffect.create(effectData, { parent: this.actor });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
//
|
//
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
import { DS4ActiveEffect } from "../active-effect";
|
||||||
import { DS4 } from "../config";
|
import { DS4 } from "../config";
|
||||||
import { getGame } from "../helpers";
|
import { getGame } from "../helpers";
|
||||||
import notifications from "../ui/notifications";
|
import notifications from "../ui/notifications";
|
||||||
|
@ -97,14 +98,8 @@ export class DS4ItemSheet extends ItemSheet<ItemSheet.Options, DS4ItemSheetData>
|
||||||
/**
|
/**
|
||||||
* Create a new ActiveEffect for the item using default data.
|
* Create a new ActiveEffect for the item using default data.
|
||||||
*/
|
*/
|
||||||
protected async createActiveEffect(): Promise<ActiveEffect | undefined> {
|
protected createActiveEffect(): void {
|
||||||
const createData = {
|
DS4ActiveEffect.createDefault({ parent: this.item });
|
||||||
label: getGame().i18n.localize(`DS4.NewEffectLabel`),
|
|
||||||
icon: "icons/svg/aura.svg",
|
|
||||||
origin: this.item.uuid,
|
|
||||||
};
|
|
||||||
|
|
||||||
return ActiveEffect.create(createData, { parent: this.item });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
<div class="tab effects" data-group="primary" data-tab="effects">
|
<div class="tab effects" data-group="primary" data-tab="effects">
|
||||||
{{#unless (isEmpty data.effects)}}
|
{{#unless (isEmpty data.effects)}}
|
||||||
<ol class="ds4-embedded-document-list ds4-embedded-document-list--effect">
|
<ol class="ds4-embedded-document-list ds4-embedded-document-list--effect effect-list">
|
||||||
{{> systems/ds4/templates/sheets/actor/components/effect-list-header.hbs}}
|
{{> systems/ds4/templates/sheets/actor/components/effect-list-header.hbs}}
|
||||||
{{#each enrichedEffects as |effectData id| }}
|
{{#each enrichedEffects as |effectData id| }}
|
||||||
{{> systems/ds4/templates/sheets/actor/components/effect-list-entry.hbs effectData=effectData}}
|
{{> systems/ds4/templates/sheets/actor/components/effect-list-entry.hbs effectData=effectData}}
|
||||||
|
|
Loading…
Reference in a new issue