Skip to content

Commit 62e3180

Browse files
committed
[#6261] Add modifiers to DamageData
Adds a new modifiers field for damage that is applied automatically to the formula. The `DamageData` model now automatically adds these modifiers to the formula, attaching to the first roll (if one can be found when using a custom formula). The `DamageData#scaledFormula` supports passing in additional modifiers that are also appended. This is to support a future Rule active effect that adds modifiers to certain rolls at evaluation time (such as Elemental Adept, which would add `min2` to all damage rolls from spells that deal a certain damage type). Closes #6261
1 parent c95dd30 commit 62e3180

6 files changed

Lines changed: 58 additions & 19 deletions

File tree

lang/en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,10 @@
20772077
"label": "Die Denomination",
20782078
"hint": "Denomination of the dice to roll."
20792079
},
2080+
"modifiers": {
2081+
"label": "Modifiers",
2082+
"hint": "Roll modifiers added to the base die."
2083+
},
20802084
"number": {
20812085
"label": "Die Number",
20822086
"hint": "Number of dice to roll."
@@ -3800,6 +3804,7 @@
38003804
},
38013805
"DND5E.RollExample": "e.g. 1d4",
38023806
"DND5E.RollMode": "Roll Mode",
3807+
"DND5E.RollModifiers": "Modifiers",
38033808
"DND5E.RollSituationalBonus": "Situational Bonus?",
38043809
"DND5E.Rule": {
38053810
"Tooltip": "Tooltip",

less/v2/forms.less

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,12 @@
335335
&.multi-select {
336336
position: relative;
337337

338-
multi-select .tags.input-element-tags {
339-
min-height: 10px;
340-
padding-left: 40%;
338+
:is(multi-select, string-tags) {
339+
&:has(.input-element-tags:empty) { margin-block-start: 8px; }
340+
.tags.input-element-tags {
341+
min-height: 10px;
342+
padding-left: 40%;
343+
}
341344
}
342345

343346
> label {
@@ -506,7 +509,7 @@
506509
&:not(:disabled) { cursor: var(--cursor-pointer); }
507510
}
508511

509-
:is(document-tags, multi-select) .tags.input-element-tags .tag {
512+
:is(document-tags, multi-select, string-tags) .tags.input-element-tags .tag {
510513
cursor: var(--cursor-pointer);
511514
font-size: var(--font-size-10);
512515
border: var(--dnd5e-border-gold);
@@ -516,7 +519,7 @@
516519
&:hover a { text-shadow: 0 0 6px var(--color-shadow-primary); }
517520
}
518521

519-
:is(document-tags, multi-select):has(select:disabled) .tags.input-element-tags .tag {
522+
:is(document-tags, multi-select, string-tags):has(select:disabled) .tags.input-element-tags .tag {
520523
cursor: var(--cursor-default);
521524
a { cursor: var(--cursor-default); }
522525
&:hover a { text-shadow: none; }
@@ -526,7 +529,7 @@
526529

527530
multi-select.hidden-tags .tags.input-element-tags { display: none; }
528531

529-
:is(file-picker, document-tags) > button {
532+
:is(file-picker, document-tags, string-tags) > button {
530533
height: var(--form-field-height);
531534
border: var(--dnd5e-border-gold);
532535
}
@@ -712,7 +715,7 @@
712715
&:not(.copy-button, .unbutton, .reveal) { line-height: 28px; }
713716
}
714717

715-
:is(document-tags, multi-select) .tags.input-element-tags .tag {
718+
:is(document-tags, multi-select, string-tags) .tags.input-element-tags .tag {
716719
padding: 1px 4px;
717720
color: var(--color-text-primary);
718721
height: unset;

module/data/shared/_types.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
* @property {object} custom
3333
* @property {boolean} custom.enabled Should the custom formula be used?
3434
* @property {string} custom.formula Custom damage formula.
35+
* @property {Set<string>} modifiers Modifiers to apply to damage roll.
3536
* @property {object} scaling
3637
* @property {string} scaling.mode How the damage scales in relation with levels.
3738
* @property {number} scaling.number Number of dice to add per scaling level.

module/data/shared/damage-field.mjs

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class DamageData extends foundry.abstract.DataModel {
3434
enabled: new BooleanField(),
3535
formula: new FormulaField()
3636
}),
37+
modifiers: new SetField(new StringField()),
3738
scaling: new SchemaField({
3839
mode: new StringField(),
3940
number: new NumberField({ initial: 1, min: 0, integer: true }),
@@ -51,7 +52,7 @@ export class DamageData extends foundry.abstract.DataModel {
5152
* @type {string}
5253
*/
5354
get formula() {
54-
if ( this.custom.enabled ) return this.custom.formula ?? "";
55+
if ( this.custom.enabled ) return this._manualFormula();
5556
return this._automaticFormula();
5657
}
5758

@@ -60,44 +61,65 @@ export class DamageData extends foundry.abstract.DataModel {
6061
/* -------------------------------------------- */
6162

6263
/**
63-
* Produce the auto-generated formula from the `number`, `denomination`, and `bonus`.
64-
* @param {number} [increase=0] Amount to increase the die count.
64+
* Produce the auto-generated formula from the `number`, `denomination`, `modifiers`, and `bonus`.
65+
* @param {number} [increase=0] Amount to increase the die count.
66+
* @param {object} [options={}]
67+
* @param {Set<string>} [options.modifiers] Additional modifiers to apply to the formula, if possible.
6568
* @returns {string}
6669
* @protected
6770
*/
68-
_automaticFormula(increase=0) {
71+
_automaticFormula(increase=0, { modifiers }={}) {
6972
let formula;
7073
const number = (this.number ?? 0) + increase;
71-
if ( number && this.denomination ) formula = `${number}d${this.denomination}`;
74+
if ( number && this.denomination ) {
75+
formula = `${number}d${this.denomination}${Array.from(this.modifiers).concat(modifiers ?? []).join("")}`;
76+
}
7277
if ( this.bonus ) formula = formula ? `${formula} + ${this.bonus}` : this.bonus;
7378
return formula ?? "";
7479
}
7580

7681
/* -------------------------------------------- */
7782

83+
/**
84+
* Produce the manual formula from the `custom.formula` and `modifiers` (if possible).
85+
* @param {object} [options={}]
86+
* @param {Set<string>} [options.modifiers] Additional modifiers to apply to the formula, if possible.
87+
* @returns {string}
88+
* @protected
89+
*/
90+
_manualFormula({ modifiers }={}) {
91+
if ( !this.custom.formula ) return "";
92+
modifiers = Array.from(this.modifiers).concat(modifiers ?? []).join("");
93+
return this.custom.formula.replace(/(?:\d|\))d(?:\d+\w*|\(.+\)\d*\w*)/, `$&${modifiers}`);
94+
}
95+
96+
/* -------------------------------------------- */
97+
7898
/**
7999
* Scale the damage by a number of steps using its configured scaling configuration.
80-
* @param {number|Scaling} increase Number of steps above base damage to scaling.
100+
* @param {number|Scaling} increase Number of steps above base damage to scaling.
101+
* @param {object} [options={}]
102+
* @param {Set<string>} [options.modifiers] Additional modifiers to apply to the formula, if possible.
81103
* @returns {string}
82104
*/
83-
scaledFormula(increase) {
105+
scaledFormula(increase, { modifiers }={}) {
84106
if ( increase instanceof Scaling ) increase = increase.increase;
85107

86108
switch ( this.scaling.mode ) {
87109
case "whole": break;
88110
case "half": increase = Math.floor(increase * .5); break;
89111
default: increase = 0; break;
90112
}
91-
if ( !increase ) return this.formula;
113+
if ( !increase ) return this.custom.enabled ? this._manualFormula() : this._automaticFormula(0, { modifiers });
92114
let formula;
93115

94116
// If dice count scaling, increase the count on the first die rolled
95117
const dieIncrease = (this.scaling.number ?? 0) * increase;
96118
if ( this.custom.enabled ) {
97-
formula = this.custom.formula;
119+
formula = this._manualFormula({ modifiers });
98120
formula = formula.replace(/^(\d)+d/, (match, number) => `${Number(number) + dieIncrease}d`);
99121
} else {
100-
formula = this._automaticFormula(dieIncrease);
122+
formula = this._automaticFormula(dieIncrease, { modifiers });
101123
}
102124

103125
// If custom scaling included, modify to match increase and append for formula

templates/activity/parts/damage-part.hbs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,14 @@
3434
{{/unless}}
3535
</div>
3636

37+
<div class="field-group">
38+
{{ formField fields.modifiers name=(concat prefix "modifiers") value=source.modifiers label="DND5E.RollModifiers"
39+
localize=true classes="label-top multi-select" rootId=@root.partId }}
40+
</div>
41+
3742
<div class="field-group">
3843
{{ formField fields.types name=(concat prefix "types") value=source.types options=typeOptions hint=false
39-
label="DND5E.Type" localize=true classes="label-top multi-select"
40-
rootId=@root.partId }}
44+
label="DND5E.Type" localize=true classes="label-top multi-select" rootId=@root.partId }}
4145
</div>
4246

4347
{{#if canScale}}

templates/shared/fields/field-damage.hbs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@
3535
</div>
3636
{{/unless}}
3737

38+
{{!-- Modifiers --}}
39+
{{ formField fields.modifiers name=(concat prefix "modifiers") value=source.modifiers label="DND5E.RollModifiers"
40+
localize=true rootId=@root.partId }}
41+
3842
{{!-- Types --}}
3943
{{#if types}}
4044
{{ formField fields.types name=(concat prefix "types") value=source.types options=types label="DND5E.Type"

0 commit comments

Comments
 (0)