diff --git a/daggerheart.mjs b/daggerheart.mjs index 63127aa4..31c9f63d 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -6,6 +6,7 @@ import * as documents from './module/documents/_module.mjs'; import { macros } from './module/_module.mjs'; import * as collections from './module/documents/collections/_module.mjs'; import * as dice from './module/dice/_module.mjs'; +import * as die from './module/dice/die/_module.mjs'; import * as fields from './module/data/fields/_module.mjs'; import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs'; import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.mjs'; @@ -38,6 +39,8 @@ CONFIG.RegionBehavior.dataModels = { }; Object.assign(CONFIG.Dice.termTypes, dice.diceTypes); +CONFIG.Dice.terms.d = die.BaseDie; +CONFIG.Dice.types = [die.BaseDie, CONFIG.Dice.terms.f]; CONFIG.Actor.documentClass = documents.DhpActor; CONFIG.Actor.dataModels = models.actors.config; diff --git a/module/applications/ui/chatLog.mjs b/module/applications/ui/chatLog.mjs index 210727d7..60b6cceb 100644 --- a/module/applications/ui/chatLog.mjs +++ b/module/applications/ui/chatLog.mjs @@ -179,15 +179,15 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo } async onRollSimple(event, message) { - const buttonType = event.target.dataset.type ?? 'damage', - total = message.rolls.reduce((a, c) => a + Roll.fromJSON(c).total, 0), - damages = { - hitPoints: { - damageTypes: [], - roll: { total } - } - }, - targets = Array.from(game.user.targets); + const buttonType = event.target.dataset.type ?? 'damage'; + const total = message.rolls.reduce((a, c) => a + Roll.fromJSON(c).total, 0); + const damages = { + hitPoints: { + damageTypes: [], + roll: { total } + } + }; + const targets = Array.from(game.user.targets); if (targets.length === 0) return ui.notifications.info(game.i18n.localize('DAGGERHEART.UI.Notifications.noTargetsSelected')); @@ -255,7 +255,7 @@ export default class DhpChatLog extends foundry.applications.sidebar.tabs.ChatLo if (target.dataset.type === 'damage') { const { damageType, dice, result } = target.dataset; - await message.system.damage.rerollDamageDice(damageType, dice, result); + await message.system.damage.rerollDamageDie(damageType, dice, result); await message.update({ 'system.damage.types': { [damageType]: { diff --git a/module/data/chat-message/actorRoll.mjs b/module/data/chat-message/actorRoll.mjs index 002715fe..10f7ffa9 100644 --- a/module/data/chat-message/actorRoll.mjs +++ b/module/data/chat-message/actorRoll.mjs @@ -1,4 +1,5 @@ import { triggerChatRollFx } from '../../helpers/utils.mjs'; +import { ChatDamageData } from './chatDamageData.mjs'; const fields = foundry.data.fields; @@ -29,60 +30,6 @@ export const originItemField = () => actionIndex: new fields.StringField() }); -class ChatMessageRollDamage extends foundry.abstract.DataModel { - static defineSchema() { - return { - types: new fields.TypedObjectField(new fields.SchemaField({ - roll: new fields.JSONField({validate: ChatMessageRollDamage.#validateRoll}), - damageTypes: new fields.ArrayField(new fields.StringField({ choices: CONFIG.DH.GENERAL.damageTypes })) - })) - }; - } - - get active() { - return Boolean(Object.keys(this.types).length); - } - - static #validateRoll(rollJSON) { - const roll = JSON.parse(rollJSON); - if (!roll.evaluated) throw new Error('Roll objects added to ChatMessage documents must be evaluated'); - } - - prepareRolls() { - for (const key of Object.keys(this.types)) { - const type = this.types[key]; - try { - const roll = Roll.fromData(type.roll); - type.roll = roll; - type.roll.modifierTotal = CONFIG.Dice.daggerheart.DHRoll.calculateTotalModifiers(roll); - } catch {} - } - } - - async rerollDamageDice(damageType, dice, resultIndex) { - const reroll = this.types[damageType].roll; - const rerollDice = reroll.dice[dice]; - const diceResult = rerollDice.results[resultIndex]; - await rerollDice.reroll(`/r1=${diceResult.result}`); - await reroll._evaluate(); - - const rerolledResult = rerollDice.results[rerollDice.results.length - 1]; - if (rerolledResult) { - const fakeRoll = { - _evaluated: true, - dice: [new foundry.dice.terms.Die({ - ...rerollDice, - results: [rerolledResult], - total: rerolledResult.value, - faces: rerollDice.faces - })], - options: { appearance: {} } - }; - await triggerChatRollFx([fakeRoll]); - } - } -} - export default class DHActorRoll extends foundry.abstract.TypeDataModel { static defineSchema() { return { @@ -103,7 +50,7 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { originItem: originItemField(), action: new fields.StringField() }), - damage: new fields.EmbeddedDataField(ChatMessageRollDamage), + damage: new fields.EmbeddedDataField(ChatDamageData), damageOptions: new fields.ObjectField(), costs: new fields.ArrayField(new fields.ObjectField()), successConsumed: new fields.BooleanField({ initial: false }) @@ -186,7 +133,6 @@ export default class DHActorRoll extends foundry.abstract.TypeDataModel { }); } - /* TODO: Change how damage data is stored somehow to enable better rerolling */ async getRerolledDamage() { if (!this.damage.active) return; diff --git a/module/data/chat-message/chatDamageData.mjs b/module/data/chat-message/chatDamageData.mjs new file mode 100644 index 00000000..3c4c6b95 --- /dev/null +++ b/module/data/chat-message/chatDamageData.mjs @@ -0,0 +1,56 @@ +import { triggerChatRollFx } from '../../helpers/utils.mjs'; + +export class ChatDamageData extends foundry.abstract.DataModel { + static defineSchema() { + const fields = foundry.data.fields; + + return { + types: new fields.TypedObjectField(new fields.SchemaField({ + roll: new fields.JSONField({validate: ChatDamageData.#validateRoll}), + damageTypes: new fields.ArrayField(new fields.StringField({ choices: CONFIG.DH.GENERAL.damageTypes })) + })) + }; + } + + get active() { + return Boolean(Object.keys(this.types).length); + } + + static #validateRoll(rollJSON) { + const roll = JSON.parse(rollJSON); + if (!roll.evaluated) throw new Error('Roll objects added to ChatMessage documents must be evaluated'); + } + + prepareRolls() { + for (const key of Object.keys(this.types)) { + const type = this.types[key]; + try { + const roll = Roll.fromData(type.roll); + type.roll = roll; + type.roll.modifierTotal = CONFIG.Dice.daggerheart.DHRoll.calculateTotalModifiers(roll); + } catch {} + } + } + + async rerollDamageDie(damageType, dice, resultIndex) { + const reroll = this.types[damageType].roll; + const rerollDice = reroll.dice[dice]; + await rerollDice.rerollResult(resultIndex); + await reroll._evaluate(); + + const rerolledResult = rerollDice.results[rerollDice.results.length - 1]; + if (rerolledResult) { + const fakeRoll = { + _evaluated: true, + dice: [new foundry.dice.terms.Die({ + ...rerollDice, + results: [rerolledResult], + total: rerolledResult.value, + faces: rerollDice.faces + })], + options: { appearance: {} } + }; + await triggerChatRollFx([fakeRoll]); + } + } +} \ No newline at end of file diff --git a/module/dice/die/_module.mjs b/module/dice/die/_module.mjs index 19ca951a..b84cef86 100644 --- a/module/dice/die/_module.mjs +++ b/module/dice/die/_module.mjs @@ -3,6 +3,7 @@ import HopeDie from './hopeDie.mjs'; import FearDie from './fearDie.mjs'; import AdvantageDie from './advantageDie.mjs'; import DisadvantageDie from './disadvantageDie.mjs'; +export { default as BaseDie } from './baseDie.mjs'; export const diceTypes = { DualityDie, diff --git a/module/dice/die/advantageDie.mjs b/module/dice/die/advantageDie.mjs index 9c2f0b03..66b6f124 100644 --- a/module/dice/die/advantageDie.mjs +++ b/module/dice/die/advantageDie.mjs @@ -1,4 +1,6 @@ -export default class AdvantageDie extends foundry.dice.terms.Die { +import BaseDie from './baseDie.mjs'; + +export default class AdvantageDie extends BaseDie { constructor(options) { super(options); diff --git a/module/dice/die/baseDie.mjs b/module/dice/die/baseDie.mjs new file mode 100644 index 00000000..cc88f753 --- /dev/null +++ b/module/dice/die/baseDie.mjs @@ -0,0 +1,12 @@ +export default class BaseDie extends foundry.dice.terms.Die { + async rerollResult(resultIndex) { + const result = this.results[resultIndex]; + result.rerolled = true; + result.active = false; + await this.roll({ reroll: true }); + + const rerolledResult = this.results[this.results.length - 1]; + this.results.splice(this.results.length - 1, 1); + this.results.splice(resultIndex, 0, rerolledResult); + } +} \ No newline at end of file diff --git a/module/dice/die/disadvantageDie.mjs b/module/dice/die/disadvantageDie.mjs index f56ebe96..e79845f3 100644 --- a/module/dice/die/disadvantageDie.mjs +++ b/module/dice/die/disadvantageDie.mjs @@ -1,4 +1,6 @@ -export default class DisadvantageDie extends foundry.dice.terms.Die { +import BaseDie from './baseDie.mjs'; + +export default class DisadvantageDie extends BaseDie { constructor(options) { super(options); diff --git a/module/dice/die/dualityDie.mjs b/module/dice/die/dualityDie.mjs index cc7ee75e..2f4dae77 100644 --- a/module/dice/die/dualityDie.mjs +++ b/module/dice/die/dualityDie.mjs @@ -1,6 +1,7 @@ +import BaseDie from './baseDie.mjs'; import { updateResourcesForDualityReroll } from '../helpers.mjs'; -export default class DualityDie extends foundry.dice.terms.Die { +export default class DualityDie extends BaseDie { constructor(options) { super(options);