- Fix handleAttackBoosted guard: replaced attackerIsCrossClient check
with defenderIsMine so the socket handler runs whenever the current
user controls the defender. Previously, when a GM-controlled monster
attacked with a D30 special result (damage multiplier, bleed, DR
multiplier, mulligan), the createChatMessage hook was suppressed
(d30PendingFromGM) but handleAttackBoosted returned early because
the attacker wasn't a cross-client PC, so nobody created the
comparison message.
- Remove map auto-pan on target/damage button hover (mouseenter/mouseleave
handlers on .request-defense-btn and .apply-wounds-btn).
- Filter defeated combatants and dead monster tokens from the target
selection list. Characters at 0 HP are still selectable (death saves).
- Restore 3D dice animation for damage rolls (lethal-fantasy.mjs,
character-sheet.mjs).
- Allow negative bonuses on weapon items (damaged weapons).
- Allow negative HP for characters (death saving throws).
- Fix D30Roll.convertToInternalType guard to warn on missing weapon
regardless of isRanged flag.
- Fix ranged weapon loading comparison (<= to <).
- Add isRangedAttack to rollTarget for consistent ranged detection.
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
When a GM-owned attacker attacks a player character, both the
createChatMessage hook and handleAttackBoosted ran on the player's
client — rolling D30 bonus dice, grit, luck, shield, and mulligan
dice twice. Now handleAttackBoosted early-returns when the attacker
is not cross-client (GM-owned), leaving the hook as the sole handler.
Even with the partial correctly registered, a template rendering failure
should not abort the entire reroll handler. Without try/catch, the
exception propagates out of the do-while loop and prevents combat result
creation. The reroll value was applied but nothing else happened.
D30 bonus dice now rolled at defense request time, not in defense handler.
Sends boosted attackRoll + d30AttackEffects in socket/nextDefenseData
so both clients agree on the value. Adds stale flag for mulligan rerolls
to bypass stale pre-computed effects and process the new D30 fresh.