daggerheart/module/dice/damageRoll.mjs
Dapoulp 0632a8c6bb
Refactor/actions v2 (#402)
* Action Refactor Part #1

* Fixed Weapon/Armor features. Fixed Feature actions

* f

* Action Refactor Part #2

* Fixes

* Remove ActionsField from Companion

* Fixes

* Localization fix

* BaseDataItem hasActions false

---------

Co-authored-by: WBHarry <williambjrklund@gmail.com>
2025-07-25 01:10:49 +02:00

130 lines
4.8 KiB
JavaScript

import DamageDialog from '../applications/dialogs/damageDialog.mjs';
import DHRoll from './dhRoll.mjs';
export default class DamageRoll extends DHRoll {
constructor(formula, data = {}, options = {}) {
super(formula, data, options);
}
static messageType = 'damageRoll';
static DefaultDialog = DamageDialog;
static async buildEvaluate(roll, config = {}, message = {}) {
if (config.evaluate !== false) {
if(config.dialog.configure === false) roll.constructFormula(config);
for (const roll of config.roll) await roll.roll.evaluate();
}
roll._evaluated = true;
const parts = config.roll.map(r => this.postEvaluate(r));
config.roll = this.unifyDamageRoll(parts);
}
static postEvaluate(roll, config = {}) {
return {
...roll,
...super.postEvaluate(roll.roll, config),
damageTypes: [...(roll.damageTypes ?? [])],
roll: roll.roll,
type: config.type,
modifierTotal: this.calculateTotalModifiers(roll.roll)
};
}
static async buildPost(roll, config, message) {
await super.buildPost(roll, config, message);
if (config.source?.message) {
const chatMessage = ui.chat.collection.get(config.source.message);
chatMessage.update({ 'system.damage': config });
}
}
static unifyDamageRoll(rolls) {
const unified = {};
rolls.forEach(r => {
const resource = unified[r.applyTo] ?? { formula: '', total: 0, parts: [] };
resource.formula += `${resource.formula !== '' ? ' + ' : ''}${r.formula}`;
resource.total += r.total;
resource.parts.push(r);
unified[r.applyTo] = resource;
});
return unified;
}
static formatGlobal(rolls) {
let formula, total;
const applyTo = new Set(rolls.flatMap(r => r.applyTo));
if (applyTo.size > 1) {
const data = {};
rolls.forEach(r => {
if (data[r.applyTo]) {
data[r.applyTo].formula += ` + ${r.formula}`;
data[r.applyTo].total += r.total;
} else {
data[r.applyTo] = {
formula: r.formula,
total: r.total
};
}
});
formula = Object.entries(data).reduce((a, [k, v]) => a + ` ${k}: ${v.formula}`, '');
total = Object.entries(data).reduce((a, [k, v]) => a + ` ${k}: ${v.total}`, '');
} else {
formula = rolls.map(r => r.formula).join(' + ');
total = rolls.reduce((a, c) => a + c.total, 0);
}
return { formula, total };
}
applyBaseBonus(part) {
const modifiers = [],
type = this.options.messageType ?? 'damage',
options = part ?? this.options;
modifiers.push(...this.getBonus(`${type}`, `${type.capitalize()} Bonus`));
options.damageTypes?.forEach(t => {
modifiers.push(...this.getBonus(`${type}.${t}`, `${t.capitalize()} ${type.capitalize()} Bonus`));
});
const weapons = ['primaryWeapon', 'secondaryWeapon'];
weapons.forEach(w => {
if (this.options.source.item && this.options.source.item === this.data[w]?.id)
modifiers.push(...this.getBonus(`${type}.${w}`, 'Weapon Bonus'));
});
return modifiers;
}
constructFormula(config) {
this.options.roll.forEach(part => {
part.roll = new Roll(Roll.replaceFormulaData(part.formula, config.data));
this.constructFormulaPart(config, part);
});
return this.options.roll;
}
constructFormulaPart(config, part) {
part.roll.terms = Roll.parse(part.roll.formula, config.data);
if (part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
part.modifiers = this.applyBaseBonus(part);
this.addModifiers(part);
part.modifiers?.forEach(m => {
part.roll.terms.push(...this.formatModifier(m.value));
});
}
if (part.extraFormula) {
part.roll.terms.push(
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
...this.constructor.parse(part.extraFormula, this.options.data)
);
}
if (config.isCritical && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
const tmpRoll = Roll.fromTerms(part.roll.terms)._evaluateSync({ maximize: true }),
criticalBonus = tmpRoll.total - this.constructor.calculateTotalModifiers(tmpRoll);
part.roll.terms.push(...this.formatModifier(criticalBonus));
}
return (part.roll._formula = this.constructor.getFormula(part.roll.terms));
}
}