diff --git a/module/applications/ui/chatLog.mjs b/module/applications/ui/chatLog.mjs index 4775d425..5031a28c 100644 --- a/module/applications/ui/chatLog.mjs +++ b/module/applications/ui/chatLog.mjs @@ -112,7 +112,8 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo if (message.system.source.item && message.system.source.action) { const action = this.getAction(actor, message.system.source.item, message.system.source.action); if (!action || !action?.hasDamagePart) return; - await game.system.api.fields.ActionFields.DamageField.execute.call(action, message, true); + // await game.system.api.fields.ActionFields.DamageField.execute.call(action, message, true); + action.schema.fields.damage.execute.call(action, message, true); } } diff --git a/module/config/settingsConfig.mjs b/module/config/settingsConfig.mjs index dd8aeffe..f29ffd75 100644 --- a/module/config/settingsConfig.mjs +++ b/module/config/settingsConfig.mjs @@ -28,3 +28,22 @@ export const gameSettings = { LevelTiers: 'LevelTiers', Countdowns: 'Countdowns' }; + +export const actionAutomationChoices = { + never: { + id: "never", + label: "Never" + }, + showDialog: { + id: "showDialog", + label: "Show Dialog only" + }, + // npcOnly: { + // id: "npcOnly", + // label: "Always for non-characters" + // }, + always: { + id: "always", + label: "Always" + } +} diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index c0d6d5eb..3c853720 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -19,9 +19,6 @@ const fields = foundry.data.fields; export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel) { static extraSchemas = ['cost', 'uses', 'range']; - // static schemaFields = new Map(); - static schemaFields = []; - // static workflow = []; static defineSchema() { const schemaFields = { @@ -41,26 +38,38 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel this.extraSchemas.forEach(s => { let clsField; - if ((clsField = this.getActionField(s))) { - // this.schemaFields.set(s, clsField); - this.schemaFields.push(clsField); + if ((clsField = this.getActionField(s))) schemaFields[s] = new clsField(); - } }); - this.schemaFields.sort((a, b) => a.order - b.order); - - // this.prepareWorkflow(); - console.log(this.schemaFields); - return schemaFields; } + static defineWorkflow() { + const workflow = []; + Object.values(this.schema.fields).forEach(s => { + if(s.execute) workflow.push( { order: s.order, execute: s.execute } ); + }); + workflow.sort((a, b) => a.order - b.order); + return workflow.map(s => s.execute); + } + + static get workflow() { + if ( this.hasOwnProperty("_workflow") ) return this._workflow; + const workflow = Object.freeze(this.defineWorkflow()); + Object.defineProperty(this, "_workflow", {value: workflow, writable: false}); + return workflow; + } + static getActionField(name) { const field = game.system.api.fields.ActionFields[`${name.capitalize()}Field`]; return fields.DataField.isPrototypeOf(field) && field; } + get workflow() { + return this.constructor.workflow; + } + prepareData() { this.name = this.name || game.i18n.localize(CONFIG.DH.ACTIONS.actionTypes[this.type].name); this.img = this.img ?? this.parent?.parent?.img; @@ -123,28 +132,9 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel return actorData; } - // static prepareWorkflow() { - // this.schemaFields.forEach( clsField => { - // if (clsField?.execute) - // this.workflow.push({ order: clsField.order, exec: clsField.execute}); - // }) - /* for (let i = 0; i < this.constructor.extraSchemas.length; i++) { - // let clsField = this.constructor.getActionField(this.constructor.extraSchemas[i]); - let clsField = this.constructor.schemaFields.get(this.constructor.extraSchemas[i]); - if (clsField?.execute) { - workflow.push({ order: clsField.order, exec: clsField.execute}); - // const keep = clsField.prepareConfig.call(this, config); - // if (config.isFastForward && !keep) return; - } - } */ - // this.workflow.sort((a, b) => a.order - b.order); - // } - async executeWorkflow(config) { - console.log(this.constructor.workflow) - for(const part of this.constructor.workflow) { - console.log(part) - if(await part.exec.call(this, config) === false) return; + for(const part of this.workflow) { + if(await part.call(this, config) === false) return; } } @@ -152,12 +142,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel if (!this.actor) throw new Error("An Action can't be used outside of an Actor context."); if (this.chatDisplay) await this.toChat(); + let { byPassRoll } = options, config = this.prepareConfig(event, byPassRoll); - // for (let i = 0; i < this.constructor.extraSchemas.length; i++) { - // let clsField = this.constructor.getActionField(this.constructor.extraSchemas[i]); - // let clsField = this.constructor.schemaFields.get(this.constructor.extraSchemas[i]); - this.constructor.schemaFields.forEach( clsField => { + + Object.values(this.schema.fields).forEach( clsField => { if (clsField?.prepareConfig) { const keep = clsField.prepareConfig.call(this, config); if (config.isFastForward && !keep) return; @@ -171,10 +160,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel config = await D20RollDialog.configure(null, config); if (!config) return; } - - const workflow = []; - - // this.prepareWorkflow(workflow); + await this.executeWorkflow(config); // if (config.hasRoll) { @@ -376,26 +362,26 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel /* EFFECTS */ /* SAVE */ - 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() - }); - } + // 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() + // }); + // } updateSaveMessage(result, message, targetId) { if (!result) return; @@ -408,14 +394,14 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel else updateMsg(); } - static rollSaveQuery({ actionId, actorId, event, message }) { - return new Promise(async (resolve, reject) => { - const actor = await fromUuid(actorId), - action = await fromUuid(actionId); - if (!actor || !actor?.isOwner) reject(); - action.rollSave(actor, event, message).then(result => resolve(result)); - }); - } + // static rollSaveQuery({ actionId, actorId, event, message }) { + // return new Promise(async (resolve, reject) => { + // const actor = await fromUuid(actorId), + // action = await fromUuid(actionId); + // if (!actor || !actor?.isOwner) reject(); + // action.rollSave(actor, event, message).then(result => resolve(result)); + // }); + // } /* SAVE */ async updateChatMessage(message, targetId, changes, chain = true) { diff --git a/module/data/fields/action/costField.mjs b/module/data/fields/action/costField.mjs index f4d942b1..0b6ac715 100644 --- a/module/data/fields/action/costField.mjs +++ b/module/data/fields/action/costField.mjs @@ -20,7 +20,7 @@ export default class CostField extends fields.ArrayField { super(element, options, context); } - static prepareConfig(config) { + prepareConfig(config) { const costs = this.cost?.length ? foundry.utils.deepClone(this.cost) : []; config.costs = CostField.calcCosts.call(this, costs); const hasCost = CostField.hasCost.call(this, config.costs); diff --git a/module/data/fields/action/damageField.mjs b/module/data/fields/action/damageField.mjs index 11975e7b..151ed8d0 100644 --- a/module/data/fields/action/damageField.mjs +++ b/module/data/fields/action/damageField.mjs @@ -3,7 +3,7 @@ import FormulaField from '../formulaField.mjs'; const fields = foundry.data.fields; export default class DamageField extends fields.SchemaField { - static order = 20; + order = 20; constructor(options, context = {}) { const damageFields = { @@ -17,8 +17,8 @@ export default class DamageField extends fields.SchemaField { super(damageFields, options, context); } - static async execute(data, force = false) { - if(this.hasRoll && !force) return; + async execute(data, force = false) { + if((this.hasRoll && DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.never.id) && !force) return false; const systemData = data.system ?? data; @@ -39,14 +39,19 @@ export default class DamageField extends fields.SchemaField { dialog: {}, data: this.getRollData() }; + if(DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.always.id) config.dialog.configure = false; if (this.hasSave) config.onSave = this.save.damageMod; - if (data.system) { - config.source.message = data._id; + + if (data.message || data.system) { + config.source.message = data.message?._id ?? data._id; config.directDamage = false; } else { config.directDamage = true; } + 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; } @@ -77,6 +82,10 @@ export default class DamageField extends fields.SchemaField { }); return formattedFormulas; } + + 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) + } } export class DHActionDiceData extends foundry.abstract.DataModel { diff --git a/module/data/fields/action/effectsField.mjs b/module/data/fields/action/effectsField.mjs index 1014c26d..ae17234a 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 { - static order = 60; + order = 60; constructor(options = {}, context = {}) { const element = new fields.SchemaField({ @@ -11,7 +11,7 @@ export default class EffectsField extends fields.ArrayField { super(element, options, context); } - static async execute(config) { + async execute(config) { if(!this.hasRoll) { const roll = new CONFIG.Dice.daggerheart.DHRoll(''); roll._evaluated = true; diff --git a/module/data/fields/action/macroField.mjs b/module/data/fields/action/macroField.mjs index e957262d..6fc0c650 100644 --- a/module/data/fields/action/macroField.mjs +++ b/module/data/fields/action/macroField.mjs @@ -1,13 +1,13 @@ const fields = foundry.data.fields; export default class MacroField extends fields.DocumentUUIDField { - static order = 70; + order = 70; constructor(context = {}) { super({ type: "Macro" }, context); } - static async execute(config) { + async execute(config) { const fixUUID = !this.macro.includes('Macro.') ? `Macro.${this.macro}` : this.macro, macro = await fromUuid(fixUUID); try { diff --git a/module/data/fields/action/rangeField.mjs b/module/data/fields/action/rangeField.mjs index 221f00af..d6709a78 100644 --- a/module/data/fields/action/rangeField.mjs +++ b/module/data/fields/action/rangeField.mjs @@ -11,7 +11,7 @@ export default class RangeField extends fields.StringField { super(options, context); } - static prepareConfig(config) { + prepareConfig(config) { return true; } } diff --git a/module/data/fields/action/rollField.mjs b/module/data/fields/action/rollField.mjs index 10c868f4..9922971d 100644 --- a/module/data/fields/action/rollField.mjs +++ b/module/data/fields/action/rollField.mjs @@ -110,20 +110,22 @@ export class DHActionRollData extends foundry.abstract.DataModel { } export default class RollField extends fields.EmbeddedDataField { - static order = 10; + order = 10; constructor(options, context = {}) { super(DHActionRollData, options, context); } - static async execute(config) { + async execute(config) { if(!config.hasRoll) return; config = await this.actor.diceRoll(config); if(!config) return false; } - static prepareConfig(config) { + prepareConfig(config) { if(!config.hasRoll) return true; + + config.dialog.configure = !RollField.getAutomation(); const roll = { baseModifiers: this.roll.getModifier(), @@ -138,4 +140,8 @@ export default class RollField extends fields.EmbeddedDataField { config.roll = roll; return true; } + + static getAutomation() { + return (game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.roll.gm) || (!game.user.isGM && game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).roll.roll.players) + } } diff --git a/module/data/fields/action/saveField.mjs b/module/data/fields/action/saveField.mjs index ca0eb220..ed314dd9 100644 --- a/module/data/fields/action/saveField.mjs +++ b/module/data/fields/action/saveField.mjs @@ -1,7 +1,7 @@ const fields = foundry.data.fields; export default class SaveField extends fields.SchemaField { - static order = 50; + order = 50; constructor(options = {}, context = {}) { const saveFields = { @@ -19,13 +19,45 @@ export default class SaveField extends fields.SchemaField { super(saveFields, options, context); } - static async execute(config) { + async execute(config) { if(!this.hasRoll) { const roll = new CONFIG.Dice.daggerheart.DHRoll(''); roll._evaluated = true; await CONFIG.Dice.daggerheart.DHRoll.toMessage(roll, config); - } else { - return; } + if(true) { + + } + + } + + 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() + }); + } + + static rollSaveQuery({ actionId, actorId, event, message }) { + return new Promise(async (resolve, reject) => { + const actor = await fromUuid(actorId), + action = await fromUuid(actionId); + if (!actor || !actor?.isOwner) reject(); + action.rollSave(actor, event, message).then(result => resolve(result)); + }); } } diff --git a/module/data/fields/action/targetField.mjs b/module/data/fields/action/targetField.mjs index bfb01db9..43f4a574 100644 --- a/module/data/fields/action/targetField.mjs +++ b/module/data/fields/action/targetField.mjs @@ -13,8 +13,8 @@ export default class TargetField extends fields.SchemaField { super(targetFields, options, context); } - static prepareConfig(config) { - if (!this.target?.type) return []; + prepareConfig(config) { + if (!this.target?.type) return config.targets = []; config.hasTarget = true; let targets; if (this.target?.type === CONFIG.DH.GENERAL.targetTypes.self.id) diff --git a/module/data/fields/action/usesField.mjs b/module/data/fields/action/usesField.mjs index 3993ca3b..f4ee30b9 100644 --- a/module/data/fields/action/usesField.mjs +++ b/module/data/fields/action/usesField.mjs @@ -20,7 +20,7 @@ export default class UsesField extends fields.SchemaField { super(usesFields, options, context); } - static prepareConfig(config) { + prepareConfig(config) { const uses = this.uses?.max ? foundry.utils.deepClone(this.uses) : null; if (uses && !uses.value) uses.value = 0; config.uses = uses; diff --git a/module/data/settings/Automation.mjs b/module/data/settings/Automation.mjs index 94e492ea..da71e899 100644 --- a/module/data/settings/Automation.mjs +++ b/module/data/settings/Automation.mjs @@ -83,8 +83,6 @@ export default class DhAutomation extends foundry.abstract.DataModel { }), roll: new fields.SchemaField({ roll: new fields.SchemaField({ - // label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.roll.roll.label', - // hint: 'DAGGERHEART.SETTINGS.Automation.FIELDS.roll.roll.hint', gm: new fields.BooleanField({ required: true, initial: false, @@ -97,36 +95,34 @@ export default class DhAutomation extends foundry.abstract.DataModel { }) }), damage: new fields.SchemaField({ - // label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.roll.damage.label', - // hint: 'DAGGERHEART.SETTINGS.Automation.FIELDS.roll.damage.hint', - gm: new fields.BooleanField({ + gm: new fields.StringField({ required: true, - initial: false, + initial: "never", + choices: CONFIG.DH.SETTINGS.actionAutomationChoices, label: 'DAGGERHEART.GENERAL.gm' }), - players: new fields.BooleanField({ + players: new fields.StringField({ required: true, - initial: false, + initial: "never", + choices: CONFIG.DH.SETTINGS.actionAutomationChoices, label: 'DAGGERHEART.GENERAL.player.plurial' }) }), save: new fields.SchemaField({ - // label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.roll.save.label', - // hint: 'DAGGERHEART.SETTINGS.Automation.FIELDS.roll.save.hint', - gm: new fields.BooleanField({ + gm: new fields.StringField({ required: true, - initial: false, + initial: "never", + choices: CONFIG.DH.SETTINGS.actionAutomationChoices, label: 'DAGGERHEART.GENERAL.gm' }), - players: new fields.BooleanField({ + players: new fields.StringField({ required: true, - initial: false, + initial: "never", + choices: CONFIG.DH.SETTINGS.actionAutomationChoices, label: 'DAGGERHEART.GENERAL.player.plurial' }) }), damageApply: new fields.SchemaField({ - // label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.roll.damageApply.label', - // hint: 'DAGGERHEART.SETTINGS.Automation.FIELDS.roll.damageApply.hint', gm: new fields.BooleanField({ required: true, initial: false, @@ -139,8 +135,6 @@ export default class DhAutomation extends foundry.abstract.DataModel { }) }), effect: new fields.SchemaField({ - // label: 'DAGGERHEART.SETTINGS.Automation.FIELDS.roll.effect.label', - // hint: 'DAGGERHEART.SETTINGS.Automation.FIELDS.roll.effect.hint', gm: new fields.BooleanField({ required: true, initial: false, diff --git a/module/dice/damageRoll.mjs b/module/dice/damageRoll.mjs index 427b6273..07297e0f 100644 --- a/module/dice/damageRoll.mjs +++ b/module/dice/damageRoll.mjs @@ -4,6 +4,7 @@ import DHRoll from './dhRoll.mjs'; export default class DamageRoll extends DHRoll { constructor(formula, data = {}, options = {}) { super(formula, data, options); + if(options.dialog.configure === false) this.constructFormula(options); } static DefaultDialog = DamageDialog; @@ -40,6 +41,7 @@ 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) { chatMessage.update({ 'system.damage': config.damage }); } diff --git a/module/systemRegistration/socket.mjs b/module/systemRegistration/socket.mjs index b47fee85..d7d45ad0 100644 --- a/module/systemRegistration/socket.mjs +++ b/module/systemRegistration/socket.mjs @@ -1,4 +1,5 @@ import DamageReductionDialog from '../applications/dialogs/damageReductionDialog.mjs'; +import SaveField from '../data/fields/action/saveField.mjs'; export function handleSocketEvent({ action = null, data = {} } = {}) { switch (action) { @@ -78,7 +79,7 @@ export const registerSocketHooks = () => { export const registerUserQueries = () => { CONFIG.queries.armorSlot = DamageReductionDialog.armorSlotQuery; - CONFIG.queries.reactionRoll = game.system.api.models.actions.actionsTypes.base.rollSaveQuery; + CONFIG.queries.reactionRoll = SaveField.rollSaveQuery; }; export const emitAsGM = async (eventName, callback, update, uuid = null) => { diff --git a/styles/less/ui/settings/settings.less b/styles/less/ui/settings/settings.less index 79c31a4e..faddb3e6 100644 --- a/styles/less/ui/settings/settings.less +++ b/styles/less/ui/settings/settings.less @@ -145,7 +145,7 @@ gap: .5rem; .form-group { - flex-wrap: wrap; + // flex-wrap: wrap; gap: .25rem; label { diff --git a/templates/settings/automation-settings/roll.hbs b/templates/settings/automation-settings/roll.hbs index 41927a5d..5769bf61 100644 --- a/templates/settings/automation-settings/roll.hbs +++ b/templates/settings/automation-settings/roll.hbs @@ -7,7 +7,6 @@ - {{log @root}} {{#each settingFields.schema.fields.roll.fields as | field |}} {{!-- {{formGroup field value=(lookup @root.settingFields.roll field.name) localize=true rootId="automation-roll"}} --}}