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

6.9 KiB
Raw Permalink Blame History

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 LethalFantasySkillLethalFantasyWeapon

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 loopchat-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: falseutils/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 objectweapon.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.mjsbuildDefenseReactionButtons; handleAttackBoosted mulligan fix (lines 142, 154, 227-249); imports hasD30Reroll
  • module/utils/d30.mjsprocessD30BonusDice: 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.mjsEQUIPMENT_CATEGORY fix
  • module/applications/combat.mjs — added import { SYSTEM } and import { log }
  • templates/chat/reaction-message.hbsd30Flag text changed; d30Auto branch removed
  • templates/dialogs/d30-special-choice.hbs — deleted
  • lang/en.json — 33 unused i18n keys remain