diff --git a/module/data/activity/base-activity.mjs b/module/data/activity/base-activity.mjs index e7af81a688..5a98b0dbc7 100644 --- a/module/data/activity/base-activity.mjs +++ b/module/data/activity/base-activity.mjs @@ -769,14 +769,16 @@ export default class BaseActivityData extends foundry.abstract.DataModel { const lastType = this.item.getFlag("dnd5e", `last.${this.id}.damageType.${index}`); + const options = foundry.utils.mergeObject(foundry.utils.deepClone(damage.options ?? {}), { + type: (damage.types.has(lastType) ? lastType : null) ?? damage.types.first(), + types: Array.from(damage.types), + properties: Array.from(this.item.system.properties ?? []) + .filter(p => CONFIG.DND5E.itemProperties[p]?.isPhysical) + }, { inplace: false }); + return { data, parts, - options: { - type: (damage.types.has(lastType) ? lastType : null) ?? damage.types.first(), - types: Array.from(damage.types), - properties: Array.from(this.item.system.properties ?? []) - .filter(p => CONFIG.DND5E.itemProperties[p]?.isPhysical) - } + options }; } diff --git a/module/data/shared/_types.mjs b/module/data/shared/_types.mjs index 0c8b625820..c29bf9df9a 100644 --- a/module/data/shared/_types.mjs +++ b/module/data/shared/_types.mjs @@ -29,6 +29,7 @@ * @property {string} bonus Bonus added to the damage. * @property {Set} types One or more damage types. If multiple are selected, then the user will be able to * select from those types. + * @property {object} options Options to pass through to the damage roll. * @property {object} custom * @property {boolean} custom.enabled Should the custom formula be used? * @property {string} custom.formula Custom damage formula. diff --git a/module/data/shared/damage-field.mjs b/module/data/shared/damage-field.mjs index 0b80fd9652..16e3e6e494 100644 --- a/module/data/shared/damage-field.mjs +++ b/module/data/shared/damage-field.mjs @@ -1,7 +1,8 @@ import Scaling from "../../documents/scaling.mjs"; import FormulaField from "../fields/formula-field.mjs"; -const { BooleanField, EmbeddedDataField, NumberField, SchemaField, SetField, StringField } = foundry.data.fields; +const { BooleanField, EmbeddedDataField, NumberField, ObjectField, SchemaField, SetField, StringField } = + foundry.data.fields; /** * Field for storing damage data. @@ -30,6 +31,7 @@ export class DamageData extends foundry.abstract.DataModel { denomination: new NumberField({ min: 0, integer: true }), bonus: new FormulaField(), types: new SetField(new StringField()), + options: new ObjectField(), custom: new SchemaField({ enabled: new BooleanField(), formula: new FormulaField() diff --git a/module/dice/_types.mjs b/module/dice/_types.mjs index 009c2d6c0a..bc125ae54c 100644 --- a/module/dice/_types.mjs +++ b/module/dice/_types.mjs @@ -122,6 +122,8 @@ * * @typedef {BasicRollOptions} DamageRollOptions * @property {boolean} [isCritical] Should critical damage be calculated for this roll? + * @property {boolean} [maximize] Maximize dice results when evaluating this roll? + * @property {boolean} [minimize] Minimize dice results when evaluating this roll? * @property {CriticalDamageConfiguration} [critical] Critical configuration for this roll. * @property {string[]} [properties] Physical properties of the source (e.g. magical, silvered). * @property {string} [type] Type of damage represented. diff --git a/module/dice/damage-roll.mjs b/module/dice/damage-roll.mjs index ca36f97c88..e4e8de4835 100644 --- a/module/dice/damage-roll.mjs +++ b/module/dice/damage-roll.mjs @@ -89,6 +89,36 @@ export default class DamageRoll extends BasicRoll { return this.options.isCritical === true; } + /* -------------------------------------------- */ + /* Evaluate Methods */ + /* -------------------------------------------- */ + + /** @inheritDoc */ + async evaluate(options={}) { + options = this._prepareEvaluationOptions(options); + return super.evaluate(options); + } + + /* -------------------------------------------- */ + + /** @inheritDoc */ + evaluateSync(options={}) { + options = this._prepareEvaluationOptions(options); + return super.evaluateSync(options); + } + + /* -------------------------------------------- */ + + /** + * Merge roll-level evaluation options into the explicit evaluation options. + * @param {object} [options={}] Evaluation options. + * @returns {object} + * @protected + */ + _prepareEvaluationOptions(options={}) { + return foundry.utils.mergeObject(this.options, options, { inplace: false }); + } + /* -------------------------------------------- */ /* Roll Configuration */ /* -------------------------------------------- */ @@ -159,6 +189,7 @@ export default class DamageRoll extends BasicRoll { */ configureDamage({ critical={} }={}) { critical = foundry.utils.mergeObject(critical, this.options.critical ?? {}, { inplace: false }); + const allowCritical = critical.allow !== false; // Remove previous critical bonus damage this.terms = this.terms.filter(t => !t.options.criticalBonusDamage && !t.options.criticalFlatBonus); @@ -174,7 +205,7 @@ export default class DamageRoll extends BasicRoll { } term.options.baseNumber = term.options.baseNumber ?? term.number; // Reset back term.number = term.options.baseNumber; - if ( this.isCritical ) { + if ( this.isCritical && allowCritical ) { let cm = critical.multiplier ?? 2; // Powerful critical - maximize damage and reduce the multiplier by 1 @@ -199,7 +230,7 @@ export default class DamageRoll extends BasicRoll { if ( critical.multiplyNumeric ) { term.options.baseNumber = term.options.baseNumber ?? term.number; // Reset back term.number = term.options.baseNumber; - if ( this.isCritical ) { + if ( this.isCritical && allowCritical ) { term.number *= (critical.multiplier ?? 2); term.options.critical = true; } @@ -216,7 +247,7 @@ export default class DamageRoll extends BasicRoll { } // Add extra critical damage term - if ( this.isCritical && critical.bonusDamage ) { + if ( this.isCritical && allowCritical && critical.bonusDamage ) { let extraTerms = new Roll(critical.bonusDamage, this.data).terms; if ( !(extraTerms[0] instanceof OperatorTerm) ) extraTerms.unshift(new OperatorTerm({ operator: "+" })); extraTerms.forEach(t => t.options.criticalBonusDamage = true);