mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-04-21 23:13:39 +02:00
175 lines
7.2 KiB
JavaScript
175 lines
7.2 KiB
JavaScript
import { emitAsGM, GMUpdateEvent } from '../../../systemRegistration/socket.mjs';
|
|
|
|
const fields = foundry.data.fields;
|
|
|
|
export default class EffectsField extends fields.ArrayField {
|
|
/**
|
|
* Action Workflow order
|
|
*/
|
|
static order = 100;
|
|
|
|
/** @inheritDoc */
|
|
constructor(options = {}, context = {}) {
|
|
const element = new fields.SchemaField({
|
|
_id: new fields.DocumentIdField(),
|
|
onSave: new fields.BooleanField({ initial: false })
|
|
});
|
|
super(element, options, context);
|
|
}
|
|
|
|
/**
|
|
* Apply Effects Action Workflow part.
|
|
* Must be called within Action context or similar.
|
|
* @param {object} config Object that contains workflow datas. Usually made from Action Fields prepareConfig methods.
|
|
* @param {object[]} [targets=null] Array of targets to override pre-selected ones.
|
|
* @param {boolean} [force=false] If the method should be executed outside of Action workflow, for ChatMessage button for example.
|
|
*/
|
|
static async execute(config, targets = null, force = false) {
|
|
if (!config.hasEffect) return;
|
|
let message = config.message ?? ui.chat.collection.get(config.parent?._id);
|
|
if (!message && !config.skips.createMessage) {
|
|
const roll = new CONFIG.Dice.daggerheart.DHRoll('');
|
|
roll._evaluated = true;
|
|
message = config.message = await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config);
|
|
}
|
|
if (EffectsField.getAutomation() || force) {
|
|
targets ??= (message.system?.targets ?? config.targets).filter(t => !config.hasRoll || t.hit);
|
|
await emitAsGM(GMUpdateEvent.UpdateEffect, EffectsField.applyEffects.bind(this), targets, this.uuid);
|
|
// EffectsField.applyEffects.call(this, config.targets.filter(t => !config.hasRoll || t.hit));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Apply Action Effects to a list of Targets
|
|
* Must be called within Action context or similar.
|
|
* @param {object[]} targets Array of formatted targets
|
|
*/
|
|
static async applyEffects(targets) {
|
|
if (!this.effects?.length) return;
|
|
|
|
let effects = this.effects.map(e => (this.item.applyEffects ?? this.item.effects).get(e._id));
|
|
const targettingRequired = effects.some(x => x.system.area?.type !== CONFIG.DH.EFFECTS.areaTypes.placed.id);
|
|
if (targettingRequired && !targets?.length)
|
|
return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm'));;
|
|
|
|
for(const effect of effects.filter(effect => effect.system.area?.type === CONFIG.DH.EFFECTS.areaTypes.placed.id)) {
|
|
await EffectsField.placeEffectRegion(effect);
|
|
}
|
|
|
|
const conditions = CONFIG.DH.GENERAL.conditions();
|
|
const messageTargets = [];
|
|
targets.forEach(async baseToken => {
|
|
if (this.hasSave && baseToken.saved.success === true) effects = this.effects.filter(e => e.onSave === true);
|
|
if (!effects.length) return;
|
|
|
|
const token =
|
|
canvas.tokens.get(baseToken.id) ?? foundry.utils.fromUuidSync(baseToken.actorId).prototypeToken;
|
|
if (!token) return;
|
|
|
|
const messageToken = token.document ?? token;
|
|
const conditionImmunities = messageToken.actor.system.rules.conditionImmunities ?? {};
|
|
messageTargets.push({
|
|
token: messageToken,
|
|
conditionImmunities: Object.values(conditionImmunities).some(x => x)
|
|
? game.i18n.format('DAGGERHEART.UI.Chat.effectSummary.immunityTo', {
|
|
immunities: Object.keys(conditionImmunities)
|
|
.filter(x => conditionImmunities[x])
|
|
.map(x => game.i18n.localize(conditions[x].name))
|
|
.join(', ')
|
|
})
|
|
: null
|
|
});
|
|
|
|
effects.forEach(async effect => {
|
|
if (!token.actor || !effect) return;
|
|
if (effect.system.area?.type !== CONFIG.DH.EFFECTS.areaTypes.placed.id)
|
|
await EffectsField.applyEffect(effect, token.actor);
|
|
});
|
|
});
|
|
|
|
if (targettingRequired && messageTargets.length === 0)
|
|
return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelectedOrPerm'));;
|
|
|
|
const summaryMessageSettings = game.settings.get(
|
|
CONFIG.DH.id,
|
|
CONFIG.DH.SETTINGS.gameSettings.Automation
|
|
).summaryMessages;
|
|
const appliedEffects = effects
|
|
.filter(e => e.system.area?.type !== CONFIG.DH.EFFECTS.areaTypes.placed.id);
|
|
|
|
if (!summaryMessageSettings.effects || !appliedEffects.length) return;
|
|
|
|
const cls = getDocumentClass('ChatMessage');
|
|
const msg = {
|
|
type: 'systemMessage',
|
|
user: game.user.id,
|
|
speaker: cls.getSpeaker(),
|
|
title: game.i18n.localize('DAGGERHEART.UI.Chat.effectSummary.title'),
|
|
content: await foundry.applications.handlebars.renderTemplate(
|
|
'systems/daggerheart/templates/ui/chat/effectSummary.hbs',
|
|
{
|
|
effects: appliedEffects,
|
|
targets: messageTargets
|
|
}
|
|
)
|
|
};
|
|
|
|
cls.create(msg);
|
|
}
|
|
|
|
/**
|
|
* Apply an Effect to a target
|
|
* @param {object} effect Effect object containing ActiveEffect UUID
|
|
* @param {object} actor Actor Document
|
|
*/
|
|
static async applyEffect(effect, actor) {
|
|
const effectData = foundry.utils.mergeObject({
|
|
...(effect.toObject?.() ?? effect),
|
|
disabled: false,
|
|
transfer: false,
|
|
origin: effect.uuid
|
|
});
|
|
await ActiveEffect.implementation.create(effectData, { parent: actor });
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
static async placeEffectRegion(effect) {
|
|
const { shape: type, size: range } = effect.system.area;
|
|
const shapeData = CONFIG.Canvas.layers.regions.layerClass.getTemplateShape({ type, range });
|
|
|
|
await canvas.regions.placeRegion(
|
|
{
|
|
name: effect.name,
|
|
shapes: [shapeData],
|
|
restriction: { enabled: false, type: 'move', priority: 0 },
|
|
behaviors: [{
|
|
name: game.i18n.localize('TYPES.RegionBehavior.applyActiveEffect'),
|
|
type: 'applyActiveEffect',
|
|
system: {
|
|
effects: [effect.uuid]
|
|
}
|
|
}],
|
|
displayMeasurements: true,
|
|
locked: false,
|
|
ownership: { default: CONST.DOCUMENT_OWNERSHIP_LEVELS.NONE },
|
|
visibility: CONST.REGION_VISIBILITY.ALWAYS
|
|
},
|
|
{ create: true }
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Return the automation setting for execute method for current user role
|
|
* @returns {boolean} If execute should be triggered automatically
|
|
*/
|
|
static getAutomation() {
|
|
return (
|
|
(game.user.isGM &&
|
|
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.effect.gm) ||
|
|
(!game.user.isGM &&
|
|
game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.effect.players)
|
|
);
|
|
}
|
|
}
|