The combat loop correctly skipped defeated combatants, but their token
IDs were absent from existingTokenIds, so the scene token loop re-added
them. Now building a defeatedTokenIds set from defeated combatants and
checking it in the scene token loop. Also switched from
game.actors.get() to token.actor for the monster HP check so unlinked
monster tokens (synthetic actors) are covered.
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
- 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>