Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90fde23ebc | |||
| d17c9cba49 | |||
| bfbce9557b | |||
| 881cecf5b7 | |||
| de31c397fa |
@@ -55,6 +55,8 @@ Fix Grit/Luck defense reaction dialog UX (stacking dialogs, multiple clicks, rev
|
||||
- **Fix ensures cross-client agreement**: Player and GM clients see the same boosted attack roll because it's computed once at attack time and sent via socket, not separately per client in the defense handler.
|
||||
- **BUG FIX: `d30AttackEffects` not propagated through `_storeNextDefenseData`** — added `d30AttackEffects` to `nextDefenseData` in `combat.mjs:353-355` so the `createChatMessage` handler finds pre-computed values for same-client path (was silently falling back to legacy dice-roll, causing double boost).
|
||||
- **BUG FIX: `d30AttackPrecomputedStale` flag for mulligan rerolls** — added `chat-reaction.mjs:464` flag and check at `chat-reaction.mjs:632-634`. After a mulligan reroll updates `attackD30message`, the stale pre-computed effects are bypassed and the new D30 message is processed fresh via `processD30BonusDice`.
|
||||
- **BUG FIX: `_dice-breakdown.hbs` partial never registered** — `loadTemplates([path])` registers partials with the full file path as the Handlebars ID, but the template references it by the short name `chat/dice-breakdown`. Fixed by passing an object `{"chat/dice-breakdown": "path"}` which explicitly sets the partial ID to match the template reference.
|
||||
- **SAFETY: do-while loop body wrapped in try/catch** — any exception from `createReactionMessage` calls now logs the error and continues safely instead of silently aborting the handler.
|
||||
|
||||
## Key Decisions
|
||||
- **Auto-roll bonus dice without dialog** — matches existing D30=27 (d6E) flow
|
||||
|
||||
+7
-4
@@ -114,10 +114,13 @@ Hooks.once("ready", async function () {
|
||||
// Initialiser la table des résultats D30
|
||||
await documents.D30Roll.initialize()
|
||||
|
||||
// Register Handlebars partials used by chat templates
|
||||
await foundry.applications.handlebars.loadTemplates([
|
||||
"systems/fvtt-lethal-fantasy/templates/chat/_dice-breakdown.hbs"
|
||||
])
|
||||
// Register Handlebars partials used by chat templates.
|
||||
// The object key is the partial ID referenced in templates (e.g., {{> chat/dice-breakdown}}),
|
||||
// the value is the file path. Using an array would register with the full path as the ID,
|
||||
// which does NOT match the template reference.
|
||||
await foundry.applications.handlebars.loadTemplates({
|
||||
"chat/dice-breakdown": "systems/fvtt-lethal-fantasy/templates/chat/_dice-breakdown.hbs"
|
||||
})
|
||||
|
||||
// Saignement piloté par le combat tracker
|
||||
_registerBleedingHooks()
|
||||
|
||||
@@ -466,6 +466,7 @@ Hooks.on("createChatMessage", async (message) => {
|
||||
let d30AttackPrecomputedStale = false
|
||||
|
||||
do {
|
||||
try {
|
||||
mulliganRestart = false
|
||||
defenderHandledBonus = false
|
||||
attackerHandledBonus = false
|
||||
@@ -551,6 +552,7 @@ Hooks.on("createChatMessage", async (message) => {
|
||||
canRerollDefense = false
|
||||
if (!reroll) continue
|
||||
defenseRoll = reroll.options?.rollTotal || reroll.total || oldDefenseRoll
|
||||
try {
|
||||
await createReactionMessage(defender, {
|
||||
type: "mulligan",
|
||||
actorName: defenderName,
|
||||
@@ -561,6 +563,9 @@ Hooks.on("createChatMessage", async (message) => {
|
||||
D30result: reroll.options?.D30result,
|
||||
D30message: reroll.options?.D30message
|
||||
})
|
||||
} catch(e) {
|
||||
console.error("Mulligan message creation failed (non-fatal):", e)
|
||||
}
|
||||
// Apply new D30 result on the restart
|
||||
if (reroll.options?.D30message) {
|
||||
defenseD30message = reroll.options.D30message
|
||||
@@ -753,6 +758,7 @@ Hooks.on("createChatMessage", async (message) => {
|
||||
canRerollAttack = false
|
||||
if (!reroll) continue
|
||||
attackRollFinal = reroll.options?.rollTotal || reroll.total || oldAttackRoll
|
||||
try {
|
||||
await createReactionMessage(attacker, {
|
||||
type: "mulligan",
|
||||
actorName: attackerName,
|
||||
@@ -763,6 +769,9 @@ Hooks.on("createChatMessage", async (message) => {
|
||||
D30result: reroll.options?.D30result,
|
||||
D30message: reroll.options?.D30message
|
||||
})
|
||||
} catch(e) {
|
||||
console.error("Mulligan message creation failed (non-fatal):", e)
|
||||
}
|
||||
// Apply new D30 result on the restart
|
||||
if (reroll.options?.D30message) {
|
||||
attackD30message = reroll.options.D30message
|
||||
@@ -821,6 +830,10 @@ Hooks.on("createChatMessage", async (message) => {
|
||||
mulliganRestart = true
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
console.error("Defense handler loop error (non-fatal):", e)
|
||||
mulliganRestart = false
|
||||
}
|
||||
} while (mulliganRestart)
|
||||
|
||||
const shieldDamageReduction = shieldBlocked ? shieldReaction?.damageReduction ?? 0 : 0
|
||||
|
||||
@@ -206,6 +206,7 @@ export async function handleAttackBoosted(msg) {
|
||||
if (!reroll) continue
|
||||
updatedDefenseRoll = reroll.options?.rollTotal || reroll.total || oldDefenseRoll
|
||||
let newD30message = reroll.options?.D30message || null
|
||||
try {
|
||||
const mulliganContent = await foundry.applications.handlebars.renderTemplate("systems/fvtt-lethal-fantasy/templates/chat/reaction-message.hbs", {
|
||||
type: "mulligan",
|
||||
actorName: defenderName,
|
||||
@@ -217,6 +218,9 @@ export async function handleAttackBoosted(msg) {
|
||||
D30message: newD30message
|
||||
})
|
||||
await ChatMessage.create({content: mulliganContent, speaker: ChatMessage.getSpeaker({actor: defender})})
|
||||
} catch(e) {
|
||||
console.error("Mulligan message creation failed (non-fatal):", e)
|
||||
}
|
||||
// Process new D30 bonus dice from the reroll
|
||||
if (newD30message) {
|
||||
defenseD30message = newD30message
|
||||
|
||||
Reference in New Issue
Block a user