feat: full reroll includes D30 + shows dice breakdown in chat

- Remove forceNoD30 from rerollConfiguredRoll so mulligan
  rerolls the D30 along with the d20 and modifier
- Reset defenseD30Processed/attackD30Processed after mulligan
  so the new D30's effects (bonus dice, specials) are applied
- Render reroll dice breakdown (diceResults + D30 result) as
  inline HTML in the reaction chat message using existing
  CSS classes so players see what was rolled
This commit is contained in:
2026-06-28 08:04:20 +02:00
parent fa5c4cc9ce
commit bb005ee9fc
2 changed files with 36 additions and 5 deletions
+36 -4
View File
@@ -572,7 +572,7 @@ Hooks.on("createChatMessage", async (message) => {
return
}
const {
let {
attackerId,
attackRoll,
attackerName,
@@ -588,7 +588,7 @@ Hooks.on("createChatMessage", async (message) => {
defenderTokenId
} = attackData
let defenseRoll = message.rolls[0]?.options?.rollTotal || message.rolls[0]?.total || 0
const defenseD30message = message.rolls[0]?.options?.D30message || null
let defenseD30message = message.rolls[0]?.options?.D30message || null
log("Processing defense:", { attackRoll, defenseRoll, attackerId, defenderId })
@@ -806,7 +806,23 @@ Hooks.on("createChatMessage", async (message) => {
canRerollDefense = false
if (!reroll) continue
defenseRoll = reroll.options?.rollTotal || reroll.total || oldDefenseRoll
await createReactionMessage(defender, `<p><strong>${defenderName}</strong> uses Mulligan and re-rolls defense: <strong>${oldDefenseRoll}</strong> → <strong>${defenseRoll}</strong>. Both sides may now react to the new numbers.</p>`)
// Build dice breakdown HTML from the reroll
const rerollBreakdown = (reroll.options?.diceResults || [])
.map(r => `<span class="dice-item"><span class="dice-type">${r.dice}</span><span class="dice-separator">→</span><span class="dice-value">${r.value}</span></span>`)
.join("")
const rerollD30 = reroll.options?.D30message
? `<div class="d30-result"><span class="d30-value">D30 → ${reroll.options.D30result || "?"}</span> — ${reroll.options.D30message.description}</div>`
: ""
await createReactionMessage(defender,
`<p><strong>${defenderName}</strong> uses Mulligan and re-rolls defense: <strong>${oldDefenseRoll}</strong> → <strong>${defenseRoll}</strong>.</p>
<div class="dice-breakdown">${rerollBreakdown}</div>${rerollD30}
<p>Both sides may now react to the new numbers.</p>`
)
// Apply new D30 result on the restart
if (reroll.options?.D30message) {
defenseD30message = reroll.options.D30message
defenseD30Processed = false
}
// Restart the full comparison so both sides can react to the new roll
mulliganRestart = true
break
@@ -1003,7 +1019,23 @@ Hooks.on("createChatMessage", async (message) => {
canRerollAttack = false
if (!reroll) continue
attackRollFinal = reroll.options?.rollTotal || reroll.total || oldAttackRoll
await createReactionMessage(attacker, `<p><strong>${attackerName}</strong> uses Mulligan and re-rolls attack: <strong>${oldAttackRoll}</strong> → <strong>${attackRollFinal}</strong>. Both sides may now react to the new numbers.</p>`)
// Build dice breakdown HTML from the reroll
const rerollBreakdown = (reroll.options?.diceResults || [])
.map(r => `<span class="dice-item"><span class="dice-type">${r.dice}</span><span class="dice-separator">→</span><span class="dice-value">${r.value}</span></span>`)
.join("")
const rerollD30 = reroll.options?.D30message
? `<div class="d30-result"><span class="d30-value">D30 → ${reroll.options.D30result || "?"}</span> — ${reroll.options.D30message.description}</div>`
: ""
await createReactionMessage(attacker,
`<p><strong>${attackerName}</strong> uses Mulligan and re-rolls attack: <strong>${oldAttackRoll}</strong> → <strong>${attackRollFinal}</strong>.</p>
<div class="dice-breakdown">${rerollBreakdown}</div>${rerollD30}
<p>Both sides may now react to the new numbers.</p>`
)
// Apply new D30 result on the restart
if (reroll.options?.D30message) {
attackD30message = reroll.options.D30message
attackD30Processed = false
}
// Restart the full comparison so both sides can react to the new roll
mulliganRestart = true
break
-1
View File
@@ -1128,7 +1128,6 @@ export default class LethalFantasyUtils {
return await RollClass.prompt({
...foundry.utils.duplicate(rerollContext),
rollContext: foundry.utils.duplicate(rerollContext.rollContext || {}),
forceNoD30: true,
hasTarget: false,
target: false
})