Fix damage & healing roll

This commit is contained in:
Dapoolp 2025-08-01 19:49:59 +02:00
parent 57f19c41cd
commit a25dbb462c
19 changed files with 200 additions and 60 deletions

View file

@ -611,7 +611,8 @@ export default class CharacterSheet extends DHBaseActorSheet {
}),
roll: {
trait: button.dataset.attribute
}
},
hasRoll: true
};
this.document.diceRoll(config);
}

View file

@ -24,7 +24,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
html.querySelectorAll('.duality-action-damage').forEach(element =>
element.addEventListener('click', event => this.onRollDamage(event, data.message))
);
html.querySelectorAll('.target-save-container').forEach(element =>
html.querySelectorAll('.target-save').forEach(element =>
element.addEventListener('click', event => this.onRollSave(event, data.message))
);
html.querySelectorAll('.roll-all-save-button').forEach(element =>
@ -124,7 +124,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
event.stopPropagation();
if (!game.user.isGM) return;
const targets = event.target.parentElement.querySelectorAll(
'.target-section > [data-token] .target-save-container'
'[data-token] .target-save'
);
const actor = await this.getActor(message.system.source.actor),
action = this.getAction(actor, message.system.source.item, message.system.source.action);
@ -211,6 +211,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
async onDamage(event, message) {
event.stopPropagation();
const { isHit, targets } = this.getTargetList(event, message);
console.log(message, isHit, targets)
if (message.system.onSave && isHit) {
const pendingingSaves = message.system.targets.filter(
@ -229,8 +230,9 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo
return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelected'));
for (let target of targets) {
let damages = foundry.utils.deepClone(message.system.damage?.roll ?? message.system.roll);
let damages = foundry.utils.deepClone(message.system.damage);
if (
!message.system.hasHealing &&
message.system.onSave &&
message.system.targets.find(t => t.id === target.id)?.saved?.success === true
) {

View file

@ -1,6 +1,7 @@
import DhpActor from '../../documents/actor.mjs';
import D20RollDialog from '../../applications/dialogs/d20RollDialog.mjs';
import { ActionMixin } from '../fields/actionField.mjs';
import { abilities } from '../../config/actorConfig.mjs';
const fields = foundry.data.fields;
@ -157,22 +158,26 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
prepareConfig(event) {
return {
event,
title: this.item.name,
title: `${this.item.name}: ${this.name}`,
source: {
item: this.item._id,
action: this._id,
actor: this.actor.uuid
},
dialog: {},
dialog: {
configure: this.hasRoll
},
type: this.type,
hasRoll: this.hasRoll,
hasDamage: this.damage?.parts?.length && this.type !== 'healing',
hasHealing: this.damage?.parts?.length && this.type === 'healing',
hasEffect: !!this.effects?.length,
hasSave: this.hasSave,
hasTarget: true,
selectedRollMode: game.settings.get('core', 'rollMode'),
isFastForward: event.shiftKey,
data: this.getRollData()
data: this.getRollData(),
evaluate: this.hasRoll
};
}
@ -189,7 +194,9 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
formula: this.roll.getFormula(),
advantage: CONFIG.DH.ACTIONS.advantageState[this.roll.advState].value
};
if (this.roll?.type === 'diceSet') roll.lite = true;
if (this.roll?.type === 'diceSet'
|| !this.hasRoll
) roll.lite = true;
return roll;
}
@ -293,19 +300,27 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel
/* SAVE */
async rollSave(actor, event, message) {
if (!actor) return;
const title = actor.isNPC
? game.i18n.localize('DAGGERHEART.GENERAL.reactionRoll')
: game.i18n.format('DAGGERHEART.UI.Chat.dualityRoll.abilityCheckTitle', {
ability: game.i18n.localize(abilities[this.save.trait]?.label)
});
return actor.diceRoll({
event,
title: 'Roll Save',
title,
roll: {
trait: this.save.trait,
difficulty: this.save.difficulty ?? this.actor?.baseSaveDifficulty,
type: 'reaction'
},
type: 'trait',
hasRoll: true,
data: actor.getRollData()
});
}
updateSaveMessage(result, message, targetId) {
if(!result) return;
const updateMsg = this.updateChatMessage.bind(this, message, targetId, {
result: result.roll.total,
success: result.roll.success

View file

@ -34,6 +34,7 @@ export default class DHDamageAction extends DHBaseAction {
}
async rollDamage(event, data) {
// console.log(data)
const systemData = data.system ?? data;
let formulas = this.damage.parts.map(p => ({
@ -46,6 +47,36 @@ export default class DHDamageAction extends DHBaseAction {
formulas = this.formatFormulas(formulas, systemData);
delete systemData.evaluate;
systemData.targets.forEach(t => t.hit = true);
const config = {
...systemData,
roll: formulas,
dialog: {},
data: this.getRollData()
}
if (this.hasSave) config.onSave = this.save.damageMod;
if (data.system) {
config.source.message = data._id;
config.directDamage = false;
} else {
config.directDamage = true;
}
return CONFIG.Dice.daggerheart.DamageRoll.build(config);
/* const systemData = data.system ?? data;
let formulas = this.damage.parts.map(p => ({
formula: this.getFormulaValue(p, data).getFormula(this.actor),
damageTypes: p.applyTo === 'hitPoints' && !p.type.size ? new Set(['physical']) : p.type,
applyTo: p.applyTo
}));
if (!formulas.length) return;
formulas = this.formatFormulas(formulas, systemData);
const config = {
title: game.i18n.format(`DAGGERHEART.UI.Chat.${ this.type === 'healing' ? 'healing' : 'damage'}Roll.title`, { damage: game.i18n.localize(this.name) }),
roll: formulas,
@ -53,6 +84,9 @@ export default class DHDamageAction extends DHBaseAction {
hasSave: this.hasSave,
isCritical: systemData.roll?.isCritical ?? false,
isHealing: this.type === 'healing',
hasDamage: this.type !== 'healing',
hasHealing: this.type === 'healing',
hasTarget: true,
source: systemData.source,
data: this.getRollData(),
event
@ -65,6 +99,6 @@ export default class DHDamageAction extends DHBaseAction {
config.directDamage = true;
}
return CONFIG.Dice.daggerheart.DamageRoll.build(config);
return CONFIG.Dice.daggerheart.DamageRoll.build(config); */
}
}

View file

@ -26,6 +26,8 @@ export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel {
hasHealing: new fields.BooleanField({ initial: false }),
hasEffect: new fields.BooleanField({ initial: false }),
hasSave: new fields.BooleanField({ initial: false }),
hasTarget: new fields.BooleanField({ initial: false }),
onSave: new fields.StringField(),
source: new fields.SchemaField({
actor: new fields.StringField(),
item: new fields.StringField(),
@ -54,5 +56,8 @@ export default class DHAdversaryRoll extends foundry.abstract.TypeDataModel {
return a;
}, {hit: 0, miss: 0})
}
this.pendingSaves = this.targets.filter(
target => target.hit && target.saved.success === null
).length > 0;
}
}

View file

@ -19,7 +19,7 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel {
})
})
),
targetSelection: new fields.BooleanField({ initial: true }),
targetSelection: new fields.BooleanField({ initial: false }),
hasSave: new fields.BooleanField({ initial: false }),
isHealing: new fields.BooleanField({ initial: false }),
onSave: new fields.StringField(),
@ -29,7 +29,12 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel {
action: new fields.StringField(),
message: new fields.StringField()
}),
directDamage: new fields.BooleanField({ initial: true })
directDamage: new fields.BooleanField({ initial: true }),
damage: new fields.ObjectField(),
hasRoll: new fields.BooleanField({ initial: false }),
hasDamage: new fields.BooleanField({ initial: false }),
hasHealing: new fields.BooleanField({ initial: false }),
hasEffect: new fields.BooleanField({ initial: false })
};
}
@ -46,5 +51,15 @@ export default class DHDamageRoll extends foundry.abstract.TypeDataModel {
game.system.api.fields.ActionFields.TargetField.formatTarget(t)
)
: this.targets;
if(this.targetSelection === true) {
this.targetShort = this.targets.reduce((a,c) => {
if(c.hit) a.hit += 1;
else c.miss += 1;
return a;
}, {hit: 0, miss: 0})
}
this.pendingSaves = this.targets.filter(
target => target.hit && target.saved.success === null
).length > 0;
}
}

View file

@ -26,7 +26,7 @@ export default class CostField extends fields.ArrayField {
}
static calcCosts(costs) {
console.log(costs, CostField.getResources.call(this, costs));
// console.log(costs, CostField.getResources.call(this, costs));
const resources = CostField.getResources.call(this, costs);
return costs.map(c => {
c.scale = c.scale ?? 1;

View file

@ -6,19 +6,20 @@ export default class DamageRoll extends DHRoll {
super(formula, data, options);
}
static messageType = 'damageRoll';
static messageType = 'dualityRoll';
static DefaultDialog = DamageDialog;
static async buildEvaluate(roll, config = {}, message = {}) {
if (config.evaluate !== false) {
// if (config.dialog.configure === false) roll.constructFormula(config);
console.log(roll,config)
if (config.evaluate !== false)
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);
config.damage = this.unifyDamageRoll(parts);
config.targetSelection = config.targets?.length
}
static postEvaluate(roll, config = {}) {
@ -32,14 +33,6 @@ export default class DamageRoll extends DHRoll {
};
}
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 => {

View file

@ -52,8 +52,10 @@ export default class DHRoll extends Roll {
}
static async buildEvaluate(roll, config = {}, message = {}) {
if (config.evaluate !== false) await roll.evaluate();
config.roll = this.postEvaluate(roll, config);
if (config.evaluate !== false) {
await roll.evaluate();
config.roll = this.postEvaluate(roll, config);
}
}
static async buildPost(roll, config, message) {
@ -62,15 +64,24 @@ export default class DHRoll extends Roll {
}
// Create Chat Message
if (roll instanceof CONFIG.Dice.daggerheart.DamageRoll && Object.values(config.roll)?.length) {
const pool = foundry.dice.terms.PoolTerm.fromRolls(
Object.values(config.roll).flatMap(r => r.parts.map(p => p.roll))
);
roll = Roll.fromTerms([pool]);
}
// if (roll instanceof CONFIG.Dice.daggerheart.DamageRoll && Object.values(config.roll)?.length) {
// const pool = foundry.dice.terms.PoolTerm.fromRolls(
// Object.values(config.roll).flatMap(r => r.parts.map(p => p.roll))
// );
// roll = Roll.fromTerms([pool]);
// }
if (config.source?.message) {
if (game.modules.get('dice-so-nice')?.active) await game.dice3d.showForRoll(roll, game.user, true);
} else config.message = await this.toMessage(roll, config);
const chatMessage = ui.chat.collection.get(config.source.message);
chatMessage.update({ 'system.damage': config.damage });
} else {
console.log(roll, config)
config.message = await this.toMessage(roll, config);
// if(roll._evaluated) {
// const cls = getDocumentClass('ChatMessage');
// await cls.create(config.message, { rollMode: config.selectedRollMode });
// }
}
}
static postEvaluate(roll, config = {}) {
@ -97,7 +108,11 @@ export default class DHRoll extends Roll {
system: config,
rolls: [roll]
};
return await cls.create(msg, { rollMode: config.selectedRollMode });
// msg.applyRollMode(config.selectedRollMode);
// return msg;
if(roll._evaluated) return await cls.create(msg, { rollMode: config.selectedRollMode });
return msg;
// return await cls.create(msg);
}
static applyKeybindings(config) {

View file

@ -17,7 +17,7 @@ export default class DhpChatMessage extends foundry.documents.ChatMessage {
if (this.type === 'dualityRoll') {
html.classList.add('duality');
switch (this.system.roll.result.duality) {
switch (this.system.roll?.result?.duality) {
case 1:
html.classList.add('hope');
break;

View file

@ -11,7 +11,8 @@ export default class RegisterHandlebarsHelpers {
damageSymbols: this.damageSymbols,
rollParsed: this.rollParsed,
hasProperty: foundry.utils.hasProperty,
setVar: this.setVar
setVar: this.setVar,
empty: this.empty
});
}
static add(a, b) {
@ -65,4 +66,9 @@ export default class RegisterHandlebarsHelpers {
static setVar(name, value, context) {
this[name] = value;
}
static empty(object) {
if(!(typeof object === 'object')) return true;
return Object.keys(object).length === 0;
}
}