From a54efaeb48b09936caf9016e88b1eb6331d99133 Mon Sep 17 00:00:00 2001 From: Dapoolp Date: Tue, 19 Aug 2025 20:43:05 +0200 Subject: [PATCH] s --- module/applications/dialogs/d20RollDialog.mjs | 4 +- module/data/action/baseAction.mjs | 50 ++++----- module/data/fields/action/damageField.mjs | 39 ++++++- module/data/fields/action/effectsField.mjs | 25 +++-- module/data/fields/action/saveField.mjs | 101 ++++++++++++++---- module/dice/damageRoll.mjs | 4 +- module/dice/dhRoll.mjs | 5 +- module/systemRegistration/socket.mjs | 3 +- 8 files changed, 160 insertions(+), 71 deletions(-) diff --git a/module/applications/dialogs/d20RollDialog.mjs b/module/applications/dialogs/d20RollDialog.mjs index d445f24c..5afe5943 100644 --- a/module/applications/dialogs/d20RollDialog.mjs +++ b/module/applications/dialogs/d20RollDialog.mjs @@ -20,7 +20,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio static DEFAULT_OPTIONS = { tag: 'form', - id: 'roll-selection', + // id: 'roll-selection', classes: ['daggerheart', 'dialog', 'dh-style', 'views', 'roll-selection'], position: { width: 'auto' @@ -42,7 +42,7 @@ export default class D20RollDialog extends HandlebarsApplicationMixin(Applicatio }; get title() { - return this.config.title; + return `${this.config.title}${this.actor ? `: ${this.actor.name}` : ''}`; } get actor() { diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index 3c853720..6597b8e2 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -1,7 +1,6 @@ import DhpActor from '../../documents/actor.mjs'; import D20RollDialog from '../../applications/dialogs/d20RollDialog.mjs'; import { ActionMixin } from '../fields/actionField.mjs'; -import { abilities } from '../../config/actorConfig.mjs'; const fields = foundry.data.fields; @@ -50,6 +49,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel Object.values(this.schema.fields).forEach(s => { if(s.execute) workflow.push( { order: s.order, execute: s.execute } ); }); + if(this.schema.fields.damage) workflow.push( { order: 75, execute: this.schema.fields.damage.applyDamage } ); workflow.sort((a, b) => a.order - b.order); return workflow.map(s => s.execute); } @@ -383,16 +383,16 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel // }); // } - updateSaveMessage(result, message, targetId) { - if (!result) return; - const updateMsg = this.updateChatMessage.bind(this, message, targetId, { - result: result.roll.total, - success: result.roll.success - }); - if (game.modules.get('dice-so-nice')?.active) - game.dice3d.waitFor3DAnimationByMessageID(result.message.id ?? result.message._id).then(() => updateMsg()); - else updateMsg(); - } + // updateSaveMessage(result, message, targetId) { + // if (!result) return; + // const updateMsg = this.updateChatMessage.bind(this, message, targetId, { + // result: result.roll.total, + // success: result.roll.success + // }); + // if (game.modules.get('dice-so-nice')?.active) + // game.dice3d.waitFor3DAnimationByMessageID(result.message.id ?? result.message._id).then(() => updateMsg()); + // else updateMsg(); + // } // static rollSaveQuery({ actionId, actorId, event, message }) { // return new Promise(async (resolve, reject) => { @@ -404,28 +404,20 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel // } /* SAVE */ - async updateChatMessage(message, targetId, changes, chain = true) { + async updateChatMessage(message, targetId, changes/* , chain = true */) { setTimeout(async () => { const chatMessage = ui.chat.collection.get(message._id); - await chatMessage.update({ - flags: { - [game.system.id]: { - reactionRolls: { - [targetId]: changes - } - } - } - }); + await chatMessage.update(changes); }, 100); - if (chain) { - if (message.system.source.message) - this.updateChatMessage(ui.chat.collection.get(message.system.source.message), targetId, changes, false); - const relatedChatMessages = ui.chat.collection.filter(c => c.system.source?.message === message._id); - relatedChatMessages.forEach(c => { - this.updateChatMessage(c, targetId, changes, false); - }); - } + // if (chain) { + // if (message.system.source.message) + // this.updateChatMessage(ui.chat.collection.get(message.system.source.message), targetId, changes, false); + // const relatedChatMessages = ui.chat.collection.filter(c => c.system.source?.message === message._id); + // relatedChatMessages.forEach(c => { + // this.updateChatMessage(c, targetId, changes, false); + // }); + // } } /** diff --git a/module/data/fields/action/damageField.mjs b/module/data/fields/action/damageField.mjs index 151ed8d0..e493f6dc 100644 --- a/module/data/fields/action/damageField.mjs +++ b/module/data/fields/action/damageField.mjs @@ -18,7 +18,7 @@ export default class DamageField extends fields.SchemaField { } async execute(data, force = false) { - if((this.hasRoll && DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.never.id) && !force) return false; + if((this.hasRoll && DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.never.id) && !force) return; const systemData = data.system ?? data; @@ -52,7 +52,38 @@ export default class DamageField extends fields.SchemaField { if(config.source?.message && game.modules.get('dice-so-nice')?.active) await game.dice3d.waitFor3DAnimationByMessageID(config.source.message); - if(!CONFIG.Dice.daggerheart.DamageRoll.build(config)) return false; + if(!(await CONFIG.Dice.daggerheart.DamageRoll.build(config))) return false; + + if(DamageField.getAutomation()) { + + } + } + + async applyDamage(config, targets) { + console.log(config, this) + targets ??= config.targets; + if(!config.damage || !targets?.length || !DamageField.getApplyAutomation()) return; + for (let target of targets) { + const actor = fromUuidSync(target.actorId); + if ( + !this.hasHealing && + this.onSave && + this.system.hitTargets.find(t => t.id === target.id)?.saved?.success === true + ) { + const mod = CONFIG.DH.ACTIONS.damageOnSave[this.onSave]?.mod ?? 1; + Object.entries(config.damage).forEach(([k, v]) => { + v.total = 0; + v.parts.forEach(part => { + part.total = Math.ceil(part.total * mod); + v.total += part.total; + }); + }); + } + + // this.consumeOnSuccess(); + if (this.hasHealing) actor.takeHealing(config.damage); + else actor.takeDamage(config.damage, this.isDirect); + } } static getFormulaValue(part, data) { @@ -86,6 +117,10 @@ export default class DamageField extends fields.SchemaField { static getAutomation() { return (game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damage.gm) || (!game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damage.players) } + + static getApplyAutomation() { + return (game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damageApply.gm) || (!game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.damageApply.players) + } } export class DHActionDiceData extends foundry.abstract.DataModel { diff --git a/module/data/fields/action/effectsField.mjs b/module/data/fields/action/effectsField.mjs index ae17234a..1a943532 100644 --- a/module/data/fields/action/effectsField.mjs +++ b/module/data/fields/action/effectsField.mjs @@ -1,7 +1,7 @@ const fields = foundry.data.fields; export default class EffectsField extends fields.ArrayField { - order = 60; + order = 100; constructor(options = {}, context = {}) { const element = new fields.SchemaField({ @@ -12,19 +12,20 @@ export default class EffectsField extends fields.ArrayField { } async execute(config) { - if(!this.hasRoll) { + if(!this.hasEffect) return; + if(!config.message) { const roll = new CONFIG.Dice.daggerheart.DHRoll(''); roll._evaluated = true; - await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config); - } else { - return; + config.message = await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config); + } + if(EffectsField.getAutomation()) { + EffectsField.applyEffects.call(this, config.targets); } } - async applyEffects(data, targets) { - targets ??= data.system.targets; + static async applyEffects(targets) { const force = true; /* Where should this come from? */ - if (!this.effects?.length || !targets.length) return; + if (!this.effects?.length || !targets?.length) return; let effects = this.effects; targets.forEach(async token => { if (!token.hit && !force) return; @@ -36,12 +37,12 @@ export default class EffectsField extends fields.ArrayField { const actor = canvas.tokens.get(token.id)?.actor, effect = this.item.effects.get(e._id); if (!actor || !effect) return; - await this.applyEffect(effect, actor); + await EffectsField.applyEffect(effect, actor); }); }); } - async applyEffect(effect, actor) { + static async applyEffect(effect, actor) { const existingEffect = actor.effects.find(e => e.origin === effect.uuid); if (existingEffect) { return effect.update( @@ -61,4 +62,8 @@ export default class EffectsField extends fields.ArrayField { }); await ActiveEffect.implementation.create(effectData, { parent: actor }); } + + 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) + } } diff --git a/module/data/fields/action/saveField.mjs b/module/data/fields/action/saveField.mjs index ed314dd9..248a4e5f 100644 --- a/module/data/fields/action/saveField.mjs +++ b/module/data/fields/action/saveField.mjs @@ -1,3 +1,6 @@ +import { abilities } from "../../../config/actorConfig.mjs"; +import { emitAsGM, GMUpdateEvent } from "../../../systemRegistration/socket.mjs"; + const fields = foundry.data.fields; export default class SaveField extends fields.SchemaField { @@ -20,36 +23,95 @@ export default class SaveField extends fields.SchemaField { } async execute(config) { - if(!this.hasRoll) { + if(!this.hasSave) return; + if(!config.message) { const roll = new CONFIG.Dice.daggerheart.DHRoll(''); roll._evaluated = true; - await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config); + config.message = await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config); } - if(true) { - + if(SaveField.getAutomation() !== CONFIG.DH.SETTINGS.actionAutomationChoices.never.id) { + SaveField.rollAllSave.call(this, config.targets, config.event, config.message); } } - async rollSave(actor, event, message) { + static async rollAllSave(targets, event, message) { + if(!targets) return; + targets.forEach(target => { + const actor = fromUuidSync(target.actorId); + if(actor) { + if (game.user === actor.owner) + SaveField.rollSave.call(this, actor, event, message) + .then(result => + emitAsGM( + GMUpdateEvent.UpdateSaveMessage, + SaveField.updateSaveMessage.bind(this, result, message, target.id), + { + action: this.uuid, + message: message._id, + token: target.id, + result + } + ) + ); + else + actor.owner + .query('reactionRoll', { + actionId: this.uuid, + actorId: actor.uuid, + event, + message + }) + .then(result => SaveField.updateSaveMessage.call(this, result, message, target.id)); + } + }); + } + + static async rollSave(actor, event, message) { if (!actor) return; const title = actor.isNPC ? game.i18n.localize('DAGGERHEART.GENERAL.reactionRoll') : game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', { ability: game.i18n.localize(abilities[this.save.trait]?.label) - }); - return actor.diceRoll({ - event, - title, - roll: { - trait: this.save.trait, - difficulty: this.save.difficulty ?? this.actor?.baseSaveDifficulty, - type: 'reaction' - }, - type: 'trait', - hasRoll: true, - data: actor.getRollData() - }); + }), + rollConfig = { + event, + title, + roll: { + trait: this.save.trait, + difficulty: this.save.difficulty ?? this.actor?.baseSaveDifficulty, + type: 'reaction' + }, + type: 'trait', + hasRoll: true, + data: actor.getRollData() + }; + if(SaveField.getAutomation() == CONFIG.DH.SETTINGS.actionAutomationChoices.always.id) rollConfig.dialog = { configure: false }; + return actor.diceRoll(rollConfig); + } + + static updateSaveMessage(result, message, targetId) { + if (!result) return; + const updateMsg = this.updateChatMessage.bind(this, message, targetId, { + flags: { + [game.system.id]: { + reactionRolls: { + [targetId]: + { + result: result.roll.total, + success: result.roll.success + } + } + } + } + }); + if (game.modules.get('dice-so-nice')?.active) + game.dice3d.waitFor3DAnimationByMessageID(result.message.id ?? result.message._id).then(() => updateMsg()); + else updateMsg(); + } + + static getAutomation() { + return (game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.save.gm) || (!game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.save.players) } static rollSaveQuery({ actionId, actorId, event, message }) { @@ -57,7 +119,8 @@ export default class SaveField extends fields.SchemaField { const actor = await fromUuid(actorId), action = await fromUuid(actionId); if (!actor || !actor?.isOwner) reject(); - action.rollSave(actor, event, message).then(result => resolve(result)); + SaveField.rollSave.call(action, actor, event, message) + .then(result => resolve(result)); }); } } diff --git a/module/dice/damageRoll.mjs b/module/dice/damageRoll.mjs index 07297e0f..d7b1dcb0 100644 --- a/module/dice/damageRoll.mjs +++ b/module/dice/damageRoll.mjs @@ -41,10 +41,8 @@ export default class DamageRoll extends DHRoll { await game.dice3d.showForRoll(diceRoll, game.user, true, chatMessage.whisper, chatMessage.blind); } await super.buildPost(roll, config, message); - // console.log(config, config.source?.message) - if (config.source?.message) { + if (config.source?.message) chatMessage.update({ 'system.damage': config.damage }); - } } static unifyDamageRoll(rolls) { diff --git a/module/dice/dhRoll.mjs b/module/dice/dhRoll.mjs index 6d691c20..f8c18ac8 100644 --- a/module/dice/dhRoll.mjs +++ b/module/dice/dhRoll.mjs @@ -45,10 +45,7 @@ export default class DHRoll extends Roll { } for (const hook of config.hooks) { - if ( - Hooks.call(`${CONFIG.DH.id}.post${hook.capitalize()}RollConfiguration`, roll, config, message) === false - ) - return []; + if (Hooks.call(`${CONFIG.DH.id}.post${hook.capitalize()}RollConfiguration`, roll, config, message) === false) return []; } return roll; } diff --git a/module/systemRegistration/socket.mjs b/module/systemRegistration/socket.mjs index d7d45ad0..4f91362c 100644 --- a/module/systemRegistration/socket.mjs +++ b/module/systemRegistration/socket.mjs @@ -1,5 +1,4 @@ import DamageReductionDialog from '../applications/dialogs/damageReductionDialog.mjs'; -import SaveField from '../data/fields/action/saveField.mjs'; export function handleSocketEvent({ action = null, data = {} } = {}) { switch (action) { @@ -79,7 +78,7 @@ export const registerSocketHooks = () => { export const registerUserQueries = () => { CONFIG.queries.armorSlot = DamageReductionDialog.armorSlotQuery; - CONFIG.queries.reactionRoll = SaveField.rollSaveQuery; + CONFIG.queries.reactionRoll = game.system.api.fields.ActionFields.SaveField.rollSaveQuery; }; export const emitAsGM = async (eventName, callback, update, uuid = null) => {