import FormulaField from '../formulaField.mjs'; const fields = foundry.data.fields; export default class UsesField extends fields.SchemaField { /** * Action Workflow order */ static order = 160; /** @inheritDoc */ constructor(options = {}, context = {}) { const usesFields = { value: new fields.NumberField({ nullable: true, initial: null }), max: new FormulaField({ nullable: true, initial: null, deterministic: true }), recovery: new fields.StringField({ choices: CONFIG.DH.GENERAL.refreshTypes, initial: null, nullable: true }), consumeOnSuccess: new fields.BooleanField({ initial: false, label: 'DAGGERHEART.ACTIONS.Settings.consumeOnSuccess.label' }) }; super(usesFields, options, context); } /** * Uses Consumption Action Workflow part. * Increment Action spent uses by 1. * Must be called within Action context or similar or similar. * @param {object} config Object that contains workflow datas. Usually made from Action Fields prepareConfig methods. * @param {boolean} [successCost=false] Consume only resources configured as "On Success only" if not already consumed. */ static async execute(config, successCost = false) { if ( config.uses?.enabled && ((!successCost && (!config.uses?.consumeOnSuccess || config.roll?.success)) || (successCost && config.uses?.consumeOnSuccess)) ) this.update({ 'uses.value': this.uses.value + 1 }); } /** * Update Action Workflow config object. * Must be called within Action context. * @param {object} config Object that contains workflow datas. Usually made from Action Fields prepareConfig methods. * @returns {boolean} Return false if fast-forwarded and no more uses. */ prepareConfig(config) { const uses = this.uses?.max ? foundry.utils.deepClone(this.uses) : null; if (uses && !uses.value) uses.value = 0; config.uses = uses; const hasUses = UsesField.hasUses.call(this, config.uses); if (config.dialog.configure === false && !hasUses) { ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.actionNoUsesRemaining')); return hasUses; } } /** * Prepare Uses object for Action Workflow * Must be called within Action context. * @param {object} uses * @returns {object} */ static calcUses(uses) { if (!uses) return null; return { ...uses, remaining: this.remainingUses, enabled: uses.hasOwnProperty('enabled') ? uses.enabled : true }; } /** * Check if the Action still get atleast one unspent uses. * Must be called within Action context. * @param {*} uses * @returns {boolean} */ static hasUses(uses) { if (!uses) return true; let max = uses.max ?? 0; if (isNaN(max)) { const roll = new Roll(Roll.replaceFormulaData(uses.max, this.getRollData())).evaluateSync(); max = roll.total; } return (uses.hasOwnProperty('enabled') && !uses.enabled) || uses.value + 1 <= max; } }