Files
uberwald 1ea1a4b4b7
Release Creation / build (release) Successful in 2m19s
FIx mulligan rolls
2026-07-01 10:38:19 +02:00

88 lines
6.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Lethal Fantasy FoundryVTT System — Session Context
## Current Goal
Fix Grit/Luck defense reaction dialog UX (stacking dialogs, multiple clicks, revert on close) and cross-client sync of defense bonuses. Fix monster defense mulligan reroll button missing cross-client.
## Accomplished
### Pass 1 — Critical Issues
- **Telemetry removed** from system.json
- **globalThis side effects** moved from top-level to `init` hook
- **console.log → log()** helper guarded by setting
- **Stale Tenebris refs** → LETHALFANTASY
### Pass 2 — V1/V2 Mixing, Fire-and-Forget
- V1 sheet registrations, activateListeners/jQuery, FilePicker paths fixed
- Fire-and-forget Promises now awaited
- Misnamed `LethalFantasySkill``LethalFantasyWeapon`
### Pass 3 — Code Review Fixes
- Duplicated dialogs fixed via `_onRender` bindings
- renderChatMessage reverted to HTML hook
- All review awaits confirmed
### Pass 4 — D30 Dialog Removal & Dead Code Audit
- **D30 choice dialog removed** — auto-rolls bonus dice; special strike/defense reported as `specialEffect: "flag"` (informational)
- **Spell calamity choice restored** — catch-all for non-standard choices uses `specialEffect: "flag"`
- **Dead `specialEffect === "auto"` branches removed** from `chat-reaction.mjs` (×2), `combat.mjs` (×1), `reaction-message.hbs`
- **Deleted `d30-special-choice.hbs` and `_buildSpecialLabel()`**
- **Dead code audit** — 2 runtime bugs fixed, ~20 dead exports/methods, 33 unused i18n keys, 2 unused templates
- **3 critical bugs fixed**: `SYSTEM.ROLL_TYPE`, `SYSTEM.EQUIPMENT_CATEGORIES`, missing imports in `applications/combat.mjs`
- **`isPrimaryController` consolidated** to local function
- **Aether/Grace deduction merged** via `_deductResourceOnCast()`
- **`nextDefenseData` deduped** via `_storeNextDefenseData()`
- **`buildDefenseReactionButtons` extracted** from `combat.mjs`; fixes stale Grit/Luck snapshots
- **HP HUD toggling extracted** to `helpers.mjs`
- **`node --check` passes all 55 `.mjs` files**
### Pass 5 — Live Verification
- **D30=30 auto-roll verified** — Club attack shows D30=30 flag
- **Defense request dialog verified** — Monster defense dialog with weapon dropdown
- **Defense reaction dialog verified** — Luck spent, bonus die added, combat result correct
- **AZA→Monster attack flow tested end-to-end**: Club attack (D20=16, D30=6) → Monster defense (D20=1) → defense reactions (Continue) → D30 attack bonus processed (+2, total 18)
- **BUG FOUND & FIXED: `d30ChangedAttack` infinite loop** — `chat-reaction.mjs:452-455` do-while reset block missing `d30ChangedAttack = false`; added at line 456
- **BUG FIX CONFIRMED**: Re-tested full flow — AZA Club attack (13, D30=12) → defense dialog → Monster defense (2, D30=24) → reaction dialog (only 1 show!) → Continue → "AZA hits Monster!" combat result → damage roll (1d6=2, total 3) → Apply Damage button. No infinite loop. Full E2E success.
### Pass 6 — Cross-Client Mulligan Reroll Fix
- **BUG FIX: `handleAttackBoosted` hardcoded `canRerollDefense: false`** — `utils/combat.mjs:142` now computes `canRerollDefense` from `defenseD30message` via `hasD30Reroll()`. Also passes `d30message` to dialog template (was `null`).
- **BUG FIX: Missing `defenseRerollContext` in socket data** — added `defenseRerollContext` to `attackBoosted` socket message at `chat-reaction.mjs:773`, and added `rerollDefense` handler in `handleAttackBoosted` at `utils/combat.mjs:203-240` so the mulligan reroll works cross-client.
- **BUG FIX: Cross-client mulligan reroll now processes new D30 bonus dice** — after reroll, calls `processD30BonusDice` on the new D30 message to apply bonus dice, flags, and DR multipliers (was silently ignored).
- **Import `hasD30Reroll` added** to `utils/combat.mjs`
- **`bleed` top-level type handler added** to `processD30BonusDice` in `d30.mjs:79-81` — returns `specialEffect: "bleed"` same as combo path, so ranged attack bleed (values 5,10,15) creates reaction message and sets damage button bleed flag.
## Key Decisions
- **Auto-roll bonus dice without dialog** — matches existing D30=27 (d6E) flow
- **`buildDefenseReactionButtons` extracts only button-building** — defense while-loop structures differ between same-client and cross-client; merging loops risks behavioral divergence
- **Inline grit/luck deduction uses live actor values**
- **Aether/Grace helper uses `costFn` parameter**
- **Cross-client mulligan reroll sends full `defenseRerollContext`** via socket so the defender can re-roll the same configured roll on their client
## Next Steps
1. Test defense request dialogs (character/monster/save) — more variants
2. Test all reaction message variants (shield block/fail, d30Bonus/Flag, grit, luck, etc.)
3. Create Player user in Foundry for cross-client socket testing (includes mulligan reroll)
4. Prune dead code: unused exports (~20), unused i18n keys (33), unused templates (2)
## Critical Context
- **Chat buttons not interactive via DevTools snapshot** — need JS fallback: `document.querySelectorAll('button').forEach(b => { if (...) b.click(); })`
- **Defense flow**: Attack card → target button (`.request-defense-btn`) → defense dialog → defense roll → defense reactions dialog → combat result card with Damage button → damage roll dialog → Apply Damage → HP application
- **Clicking "Damage" directly bypasses defense** — rolls unapplied damage to chat
- **Same-owner guard** (`chat-reaction.mjs:180-182`) — skips defense when GM owns both, unless `!defenderIsMonster`
- **`d30ChangedAttack` infinite loop** — variable wasn't reset in do-while block; fix at `chat-reaction.mjs:456`
- **Cross-client mulligan fix**: `handleAttackBoosted` now shows reroll button and handles the reroll action. Requires `defenseRerollContext` in socket data (added).
- **Deserialized weapon object** — `weapon.name` works, `weapon.id` undefined, `weapon._id` works
- **Fvtt server**: port 31000, foundrydata-dev
- **No player user configured** — cannot test cross-client socket flow
## Relevant Files
- `module/hooks/chat-reaction.mjs` — all 7 hook registrations; defense do-while loop; **d30ChangedAttack fix (line 456)**; socket data includes `defenseRerollContext` (line 773)
- `module/utils/combat.mjs``buildDefenseReactionButtons`; **`handleAttackBoosted` mulligan fix (lines 142, 154, 227-249)**; imports `hasD30Reroll`
- `module/utils/d30.mjs``processD30BonusDice`: auto-roll, flag reporting, no dialog; `hasD30Reroll` checks `type === "mulligan"`
- `module/utils/helpers.mjs``_toggleHudWraps`/`_disableHudWraps`
- `module/utils.mjs` — barrel re-exporting 23 static methods
- `module/models/equipment.mjs``EQUIPMENT_CATEGORY` fix
- `module/applications/combat.mjs` — added `import { SYSTEM }` and `import { log }`
- `templates/chat/reaction-message.hbs``d30Flag` text changed; `d30Auto` branch removed
- `templates/dialogs/d30-special-choice.hbs` — deleted
- `lang/en.json` — 33 unused i18n keys remain