mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-07-22 02:19:54 +02:00
Fixed ChatMessage damage creation
This commit is contained in:
parent
1f12a98c63
commit
42ec4f8c30
8 changed files with 152 additions and 113 deletions
|
|
@ -51,7 +51,11 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
|
||||||
const context = await super._prepareContext(_options);
|
const context = await super._prepareContext(_options);
|
||||||
context.config = CONFIG.DH;
|
context.config = CONFIG.DH;
|
||||||
context.title = this.config.title ?? this.title;
|
context.title = this.config.title ?? this.title;
|
||||||
context.formula = this.roll.constructFormula(this.config);
|
|
||||||
|
const { damageFormula, resourceFormulas } = this.roll.constructFormulas(this.config);
|
||||||
|
context.damageFormula = damageFormula;
|
||||||
|
context.resourceFormulas = resourceFormulas;
|
||||||
|
|
||||||
context.hasHealing = this.config.hasHealing;
|
context.hasHealing = this.config.hasHealing;
|
||||||
context.directDamage = this.config.directDamage;
|
context.directDamage = this.config.directDamage;
|
||||||
context.selectedMessageMode = this.config.selectedMessageMode;
|
context.selectedMessageMode = this.config.selectedMessageMode;
|
||||||
|
|
@ -73,7 +77,8 @@ export default class DamageDialog extends HandlebarsApplicationMixin(Application
|
||||||
|
|
||||||
static updateRollConfiguration(_event, _, formData) {
|
static updateRollConfiguration(_event, _, formData) {
|
||||||
const data = foundry.utils.expandObject(formData.object);
|
const data = foundry.utils.expandObject(formData.object);
|
||||||
foundry.utils.mergeObject(this.config.roll, data.roll);
|
foundry.utils.mergeObject(this.config.damageFormula, data.damageFormula);
|
||||||
|
foundry.utils.mergeObject(this.config.resourceFormulas, data.resourceFormulas);
|
||||||
foundry.utils.mergeObject(this.config.modifiers, data.modifiers);
|
foundry.utils.mergeObject(this.config.modifiers, data.modifiers);
|
||||||
this.config.selectedMessageMode = data.selectedMessageMode;
|
this.config.selectedMessageMode = data.selectedMessageMode;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -429,11 +429,11 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasDamage() {
|
get hasDamage() {
|
||||||
return Boolean(Object.keys(this.damage?.parts ?? {}).length) && this.type !== 'healing';
|
return this.type !== 'healing' && Boolean(this.damage.main) || Boolean(this.damage.resources.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasHealing() {
|
get hasHealing() {
|
||||||
return Boolean(Object.keys(this.damage?.parts ?? {}).length) && this.type === 'healing';
|
return this.type === 'healing' && Boolean(this.damage.main) || Boolean(this.damage.resources.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
get hasSave() {
|
get hasSave() {
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,8 @@ export default class DHDamageAction extends DHBaseAction {
|
||||||
* @returns Formula string
|
* @returns Formula string
|
||||||
*/
|
*/
|
||||||
getDamageFormula() {
|
getDamageFormula() {
|
||||||
const strings = [];
|
if (!this.damage.main) return '';
|
||||||
for (const { value } of this.damage.parts) {
|
|
||||||
strings.push(Roll.replaceFormulaData(value.getFormula(), this.actor?.getRollData() ?? {}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return strings.join(' + ');
|
return Roll.replaceFormulaData(this.damage.main.value.getFormula(), this.actor?.getRollData() ?? {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ export class ChatDamageData extends foundry.abstract.DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
get active() {
|
get active() {
|
||||||
return Boolean(Object.keys(this.types).length);
|
return !!this.main || Boolean(Object.keys(this.resources).length);
|
||||||
}
|
}
|
||||||
|
|
||||||
static #validateRoll(rollJSON) {
|
static #validateRoll(rollJSON) {
|
||||||
|
|
@ -28,12 +28,12 @@ export class ChatDamageData extends foundry.abstract.DataModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
_prepareRolls() {
|
_prepareRolls() {
|
||||||
for (const key of Object.keys(this.types)) {
|
if (this.main) {
|
||||||
const type = this.types[key];
|
this.main = Roll.fromData(this.main);
|
||||||
try {
|
}
|
||||||
this.types[key] = Roll.fromData(type);
|
|
||||||
this.types[key].options.modifierTotal = CONFIG.Dice.daggerheart.DHRoll.calculateTotalModifiers(type);
|
for (const key of Object.keys(this.resources)) {
|
||||||
} catch {}
|
this.resources[key] = Roll.fromData(this.resources[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -32,25 +32,23 @@ export default class DamageField extends fields.SchemaField {
|
||||||
this.hasRoll &&
|
this.hasRoll &&
|
||||||
DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.never.id &&
|
DamageField.getAutomation() === CONFIG.DH.SETTINGS.actionAutomationChoices.never.id &&
|
||||||
!force
|
!force
|
||||||
)
|
) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let formulas = this.damage.parts.map(p => ({
|
const damageFormula = this.damage.main ?
|
||||||
formula: DamageField.getFormulaValue.call(this, p, config).getFormula(this.actor),
|
DamageField.formatFormulas.call(this, [this.damage.main], config)[0] : null;
|
||||||
damageTypes: p.applyTo === 'hitPoints' && !p.type.size ? new Set(['physical']) : p.type,
|
const resourceFormulas = DamageField.formatFormulas.call(this, this.damage.resources, config);
|
||||||
applyTo: p.applyTo
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (!formulas.length) return false;
|
if (!damageFormula && !resourceFormulas.length) return false;
|
||||||
|
|
||||||
formulas = DamageField.formatFormulas.call(this, formulas, config);
|
|
||||||
|
|
||||||
messageId = config.message?._id ?? messageId;
|
messageId = config.message?._id ?? messageId;
|
||||||
const message = game.messages.get(messageId);
|
const message = game.messages.get(messageId);
|
||||||
const damageConfig = {
|
const damageConfig = {
|
||||||
dialog: {},
|
dialog: {},
|
||||||
...config,
|
...config,
|
||||||
roll: formulas,
|
damageFormula,
|
||||||
|
resourceFormulas,
|
||||||
data: this.getRollData(),
|
data: this.getRollData(),
|
||||||
isCritical: Boolean(message?.system.roll?.isCritical)
|
isCritical: Boolean(message?.system.roll?.isCritical)
|
||||||
};
|
};
|
||||||
|
|
@ -175,11 +173,17 @@ export default class DamageField extends fields.SchemaField {
|
||||||
/**
|
/**
|
||||||
* Prepare formulas for Damage Roll
|
* Prepare formulas for Damage Roll
|
||||||
* Must be called within Action context or similar.
|
* Must be called within Action context or similar.
|
||||||
* @param {object[]} formulas Array of formatted formulas object
|
* @param {DHResourceData[]} damageData Array of DHResourceData
|
||||||
* @param {object} data Action getRollData
|
* @param {object} data Action getRollData
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
static formatFormulas(formulas, data) {
|
static formatFormulas(damageData, data) {
|
||||||
|
const formulas = damageData.map(x => ({
|
||||||
|
formula: DamageField.getFormulaValue.call(this, x, data).getFormula(this.actor),
|
||||||
|
damageTypes: x.applyTo === 'hitPoints' && !x.type.size ? new Set(['physical']) : x.type,
|
||||||
|
applyTo: x.applyTo
|
||||||
|
}));
|
||||||
|
|
||||||
const formattedFormulas = [];
|
const formattedFormulas = [];
|
||||||
formulas.forEach(formula => {
|
formulas.forEach(formula => {
|
||||||
if (isNaN(formula.formula))
|
if (isNaN(formula.formula))
|
||||||
|
|
@ -190,6 +194,7 @@ export default class DamageField extends fields.SchemaField {
|
||||||
if (same) same.formula += ` + ${formula.formula}`;
|
if (same) same.formula += ` + ${formula.formula}`;
|
||||||
else formattedFormulas.push(formula);
|
else formattedFormulas.push(formula);
|
||||||
});
|
});
|
||||||
|
|
||||||
return formattedFormulas;
|
return formattedFormulas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,16 +13,27 @@ export default class DamageRoll extends DHRoll {
|
||||||
|
|
||||||
static DefaultDialog = DamageDialog;
|
static DefaultDialog = DamageDialog;
|
||||||
|
|
||||||
|
static createRollInstance(config) {
|
||||||
|
return new this(undefined, config.data, config);
|
||||||
|
}
|
||||||
|
|
||||||
/** @inheritdoc */
|
/** @inheritdoc */
|
||||||
static async buildEvaluate(roll, config = {}) {
|
static async buildEvaluate(roll, config = {}) {
|
||||||
if (config.dialog.configure === false) roll.constructFormula(config);
|
if (config.dialog.configure === false) roll.constructFormulas(config);
|
||||||
|
|
||||||
for (const roll of config.roll) {
|
const evaluateRoll = async roll => {
|
||||||
await roll.roll.evaluate();
|
await roll.roll.evaluate();
|
||||||
roll.roll.options = { damageTypes: roll.damageTypes ? [...roll.damageTypes] : [] };
|
roll.roll.options = { damageTypes: roll.damageTypes ? [...roll.damageTypes] : [] };
|
||||||
|
return roll.roll;
|
||||||
|
}
|
||||||
|
|
||||||
if (!config.damage?.types) config.damage = { types: {} };
|
config.damage.main = await evaluateRoll(config.damageFormula);
|
||||||
config.damage.types[roll.applyTo] = roll.roll;
|
config.damage.main.options = { damageTypes:
|
||||||
|
config.damageFormula.damageTypes ? [...config.damageFormula.damageTypes] : []
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const roll of config.resourceFormulas) {
|
||||||
|
config.damage.resources[roll.applyTo] = await evaluateRoll(roll);
|
||||||
}
|
}
|
||||||
|
|
||||||
roll._evaluated = true;
|
roll._evaluated = true;
|
||||||
|
|
@ -51,7 +62,8 @@ export default class DamageRoll extends DHRoll {
|
||||||
if (config.source?.message) {
|
if (config.source?.message) {
|
||||||
chatMessage.update({ 'system.damage': {
|
chatMessage.update({ 'system.damage': {
|
||||||
...config.damage.toObject(),
|
...config.damage.toObject(),
|
||||||
types: config.damage.types
|
main: config.damage.main,
|
||||||
|
resources: config.damage.resources
|
||||||
}});
|
}});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -125,62 +137,72 @@ export default class DamageRoll extends DHRoll {
|
||||||
return changeKeys;
|
return changeKeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructFormula(config) {
|
constructFormulas(config) {
|
||||||
|
return {
|
||||||
|
damageFormula: this.constructFormula(this.options.damageFormula, config, true),
|
||||||
|
resourceFormulas: this.options.resourceFormulas.map(x => this.constructFormula(x, config))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
constructFormula(formulaData, config, isDamage) {
|
||||||
this.options.isCritical = config.isCritical;
|
this.options.isCritical = config.isCritical;
|
||||||
for (const [index, part] of this.options.roll.entries()) {
|
|
||||||
const isHitpointPart = part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id;
|
|
||||||
part.roll = new Roll(Roll.replaceFormulaData(part.formula, config.data));
|
|
||||||
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));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/* To Remove When Reaction System */
|
const isHitpointPart = formulaData.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id;
|
||||||
if (index === 0 && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
|
formulaData.roll = new Roll(Roll.replaceFormulaData(formulaData.formula, config.data));
|
||||||
for (const mod in config.modifiers) {
|
formulaData.roll.terms = Roll.parse(formulaData.roll.formula, config.data);
|
||||||
const modifier = config.modifiers[mod];
|
if (formulaData.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
|
||||||
if (modifier.beforeCrit === true && (modifier.enabled || modifier.value)) modifier.callback(part);
|
formulaData.modifiers = this.applyBaseBonus(formulaData);
|
||||||
}
|
this.addModifiers(formulaData);
|
||||||
}
|
formulaData.modifiers?.forEach(m => {
|
||||||
|
formulaData.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.damageOptions.groupAttack?.numAttackers > 1 && isHitpointPart) {
|
|
||||||
const damageTypes = [foundry.dice.terms.Die, foundry.dice.terms.NumericTerm];
|
|
||||||
for (const term of part.roll.terms) {
|
|
||||||
if (damageTypes.some(type => term instanceof type)) {
|
|
||||||
term.number *= config.damageOptions.groupAttack.numAttackers;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config.isCritical && isHitpointPart) {
|
|
||||||
const total = part.roll.dice.reduce((acc, term) => acc + term._faces * term._number, 0);
|
|
||||||
if (total > 0) {
|
|
||||||
part.roll.terms.push(...this.formatModifier(total));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* To Remove When Reaction System */
|
|
||||||
if (index === 0 && part.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
|
|
||||||
for (const mod in config.modifiers) {
|
|
||||||
const modifier = config.modifiers[mod];
|
|
||||||
if (!modifier.beforeCrit && (modifier.enabled || modifier.value)) modifier.callback(part);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
part.roll._formula = this.constructor.getFormula(part.roll.terms);
|
|
||||||
}
|
}
|
||||||
return this.options.roll;
|
|
||||||
|
/* To Remove When Reaction System */
|
||||||
|
if (isDamage && formulaData.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
|
||||||
|
for (const mod in config.modifiers) {
|
||||||
|
const modifier = config.modifiers[mod];
|
||||||
|
if (
|
||||||
|
modifier.beforeCrit === true &&
|
||||||
|
(modifier.enabled || modifier.value)
|
||||||
|
) modifier.callback(formulaData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (formulaData.extraFormula) {
|
||||||
|
formulaData.roll.terms.push(
|
||||||
|
new foundry.dice.terms.OperatorTerm({ operator: '+' }),
|
||||||
|
...this.constructor.parse(formulaData.extraFormula, this.options.data)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.damageOptions.groupAttack?.numAttackers > 1 && isHitpointPart) {
|
||||||
|
const damageTypes = [foundry.dice.terms.Die, foundry.dice.terms.NumericTerm];
|
||||||
|
for (const term of formulaData.roll.terms) {
|
||||||
|
if (damageTypes.some(type => term instanceof type)) {
|
||||||
|
term.number *= config.damageOptions.groupAttack.numAttackers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.isCritical && isHitpointPart) {
|
||||||
|
const total = formulaData.roll.dice.reduce((acc, term) => acc + term._faces * term._number, 0);
|
||||||
|
if (total > 0) {
|
||||||
|
formulaData.roll.terms.push(...this.formatModifier(total));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To Remove When Reaction System */
|
||||||
|
if (isDamage && formulaData.applyTo === CONFIG.DH.GENERAL.healingTypes.hitPoints.id) {
|
||||||
|
for (const mod in config.modifiers) {
|
||||||
|
const modifier = config.modifiers[mod];
|
||||||
|
if (!modifier.beforeCrit && (modifier.enabled || modifier.value)) modifier.callback(formulaData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formulaData.roll._formula = this.constructor.getFormula(formulaData.roll.terms);
|
||||||
|
|
||||||
|
return formulaData;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* To Remove When Reaction System */
|
/* To Remove When Reaction System */
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,10 @@ export default class DHRoll extends BaseRoll {
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static createRollInstance(config) {
|
||||||
|
return new this(config.roll.formula, config.data, config);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {Partial<RollConfig>} config
|
* @param {Partial<RollConfig>} config
|
||||||
* @returns {Promise<RollConfig>}
|
* @returns {Promise<RollConfig>}
|
||||||
|
|
@ -58,7 +62,7 @@ export default class DHRoll extends BaseRoll {
|
||||||
|
|
||||||
this.temporaryModifierBuilder(config);
|
this.temporaryModifierBuilder(config);
|
||||||
|
|
||||||
let roll = new this(config.roll.formula, config.data, config);
|
let roll = this.createRollInstance(config);
|
||||||
if (config.dialog.configure !== false) {
|
if (config.dialog.configure !== false) {
|
||||||
// Open Roll Dialog
|
// Open Roll Dialog
|
||||||
const DialogClass = config.dialog?.class ?? this.DefaultDialog;
|
const DialogClass = config.dialog?.class ?? this.DefaultDialog;
|
||||||
|
|
|
||||||
|
|
@ -16,31 +16,10 @@
|
||||||
</fieldset>
|
</fieldset>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#each @root.formula}}
|
{{> formula @root.damageFormula path="damageFormula"}}
|
||||||
<div class="damage-formula">
|
|
||||||
<span class="damage-resource"><b>{{localize "DAGGERHEART.GENERAL.formula"}}:</b> {{roll.formula}}</span>
|
{{#each @root.resourceFormulas}}
|
||||||
<span class="damage-details">
|
{{> formula path=(concat "resourceFormulas." @key)}}
|
||||||
{{#with (lookup @root.config.GENERAL.healingTypes applyTo)}}
|
|
||||||
{{localize label}}
|
|
||||||
{{/with}}
|
|
||||||
{{#unless @root.hasHealing}}
|
|
||||||
{{#if damageTypes}}
|
|
||||||
{{#each damageTypes as | type | }}
|
|
||||||
{{#with (lookup @root.config.GENERAL.damageTypes type)}}
|
|
||||||
<i class="fa-solid {{icon}}"></i>
|
|
||||||
{{/with}}
|
|
||||||
{{/each}}
|
|
||||||
{{/if}}
|
|
||||||
{{/unless}}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="bonuses form-group flexrow">
|
|
||||||
<input type="text" value="{{extraFormula}}" name="roll.{{ @index }}.extraFormula" placeholder="{{localize "DAGGERHEART.GENERAL.situationalBonus"}}">
|
|
||||||
<button class="critical-chip" data-action="toggleCritical">
|
|
||||||
<span><i class="{{#if @root.isCritical}}fa-solid{{else}}fa-regular{{/if}} fa-circle"></i></span>
|
|
||||||
<span class="label">{{localize "DAGGERHEART.GENERAL.criticalShort"}}</span>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
{{#if damageOptions.groupAttack}}
|
{{#if damageOptions.groupAttack}}
|
||||||
|
|
@ -87,4 +66,31 @@
|
||||||
<span class="label">{{localize "DAGGERHEART.GENERAL.roll"}}</span>
|
<span class="label">{{localize "DAGGERHEART.GENERAL.roll"}}</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
{{#*inline "formula"}}
|
||||||
|
<div class="damage-formula">
|
||||||
|
<span class="damage-resource"><b>{{localize "DAGGERHEART.GENERAL.formula"}}:</b> {{roll.formula}}</span>
|
||||||
|
<span class="damage-details">
|
||||||
|
{{#with (lookup @root.config.GENERAL.healingTypes applyTo)}}
|
||||||
|
{{localize label}}
|
||||||
|
{{/with}}
|
||||||
|
{{#unless @root.hasHealing}}
|
||||||
|
{{#if damageTypes}}
|
||||||
|
{{#each damageTypes as | type | }}
|
||||||
|
{{#with (lookup @root.config.GENERAL.damageTypes type)}}
|
||||||
|
<i class="fa-solid {{icon}}"></i>
|
||||||
|
{{/with}}
|
||||||
|
{{/each}}
|
||||||
|
{{/if}}
|
||||||
|
{{/unless}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="bonuses form-group flexrow">
|
||||||
|
<input type="text" value="{{extraFormula}}" name={{concat path ".extraFormula"}} placeholder="{{localize "DAGGERHEART.GENERAL.situationalBonus"}}">
|
||||||
|
<button class="critical-chip" data-action="toggleCritical">
|
||||||
|
<span><i class="{{#if @root.isCritical}}fa-solid{{else}}fa-regular{{/if}} fa-circle"></i></span>
|
||||||
|
<span class="label">{{localize "DAGGERHEART.GENERAL.criticalShort"}}</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{{/inline}}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue