Compare commits

...
1 Commits
Author SHA1 Message Date
uberwald 0228f351c7 fix(combat): prevent double dice rolls in handleAttackBoosted
Release Creation / build (release) Successful in 52s
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.
2026-08-08 20:39:38 +02:00
+16
View File
@@ -105,8 +105,24 @@ export async function handleAttackBoosted(msg) {
} = msg
const defender = game.actors.get(defenderId)
const attacker = game.actors.get(attackerId)
if (!defender) return
// When the attacker is GM-owned (not a PC on another client), the createChatMessage
// hook on the defender's client already handles everything: D30 bonus dice, defense
// reaction dialog (grit/luck/shield/mulligan), and the comparison message. Running
// handleAttackBoosted too would double-roll all dice and show duplicate dialogs.
// Only proceed when the hook is suppressed (attacker is a PC on another client).
const attackerHasNonGMOwner = attacker && game.users.some(u => u.active && !u.isGM && attacker.testUserPermission(u, "OWNER"))
const _isPrimaryController = actor => {
if (!actor) return false
const activePlayerOwners = game.users.filter(u => u.active && !u.isGM && actor.testUserPermission(u, "OWNER"))
if (activePlayerOwners.length > 0) return activePlayerOwners[0].id === game.user.id
return game.user.isGM
}
const attackerIsCrossClient = attackerHasNonGMOwner && !_isPrimaryController(attacker)
if (!attackerIsCrossClient) return
let updatedDefenseRoll = defenseRoll
let shieldBlocked = false
let shieldReaction = null