diff --git a/lethal-fantasy.mjs b/lethal-fantasy.mjs index e56587c..b14e835 100644 --- a/lethal-fantasy.mjs +++ b/lethal-fantasy.mjs @@ -873,6 +873,7 @@ Hooks.on("createChatMessage", async (message) => { // ── D30 bonus dice (attack) — resolved before grit/luck ──────────────── if (attackD30message && !attackD30Processed) { + const preD30AttackRoll = attackRollFinal const canDialog = isPrimaryController(attacker) const d30Result = await LethalFantasyUtils.processD30BonusDice(attackD30message, "attack", attackNaturalRoll, attacker, canDialog) if (d30Result.modifier) { @@ -913,10 +914,17 @@ Hooks.on("createChatMessage", async (message) => { } } attackD30Processed = true + // If D30 boosted attack past defense, restart so defender can react. + // Only restart when D30 actually changed the outcome (pre-D30 defender was + // winning or tied, post-D30 defender is losing). + if (defender && preD30AttackRoll <= defenseRoll && defenseRoll < attackRollFinal) { + mulliganRestart = true + continue + } } // ── Attack reaction loop ─────────────────────────────────────────────── - if (!defenderHandledBonus && attacker && attackRollFinal <= defenseRoll && isPrimaryController(attacker)) { + if (attacker && attackRollFinal <= defenseRoll && isPrimaryController(attacker)) { while (attackRollFinal <= defenseRoll) { const currentGrit = Number(attacker.system?.grit?.current) || 0 const buttons = []