Pushing explosion dice to DieTerm.results made the for loop
condition (j < results.length) grow mid-iteration, re-processing
the explosion result as a normal die. This produced spurious
entries like `1D6 → 4` alongside the correct `1D6-1 → 3`.
Fixes prompt() (for loop) and rollSpellDamageToMessage()
(for...of) by caching result count / snapshotting the array
before iterating.
Explosion rolls were evaluated as separate Roll instances but never
added to the original DieTerm's results array. Dice So Nice reads
DieTerm.results to render 3D dice, so explosions were invisible.
Now each explosion result is pushed into the DieTerm's results array
({result, active:true}), letting DSN render explosion dice in the
correct chronological order alongside the main die.
Applies to prompt(), promptRangedDefense(), promptRangedAttack(),
and rollSpellDamageToMessage().
saving_throws was redundant — all saves in this system are
vs spells. Removed SAVING_THROWS constant; all save rollType
lookups use ARCANE_SPELL_DEFENSE. D30=1 arcane_spell_defense
blank (no special result). Added miracle types to ARCANE_SPELL_ATTACK
mapping so they get D30 results instead of null.
delete on game.lethalFantasy.spellDefense was breaking roll flow
on Foundry's proxied game object. Use try/finally with
assignment to false instead, which is safe on any object type.
Initialize saveSpell local var from one-shot flag so D30
chart lookup correctly uses arcane_spell_defense for spell saves
without requiring user to click the pre-checked checkbox.
Bug: saveSpell local var initialized to false (line 142), while
dialog checkbox was pre-checked via dialogContext.saveSpell =
game.lethalFantasy.spellDefense. If user didn't click the checkbox,
D30 call used SAVING_THROWS chart instead of ARCANE_SPELL_DEFENSE.
Also: game.lethalFantasy.spellDefense was set true before spell
defense rolls but never cleared, leaking to subsequent non-spell saves.
Fix: initialize saveSpell from the one-shot flag and delete it
immediately. Dialog context now uses the local saveSpell variable
instead of re-reading the deleted flag.
V2 renderTokenHUD passes (hud, html, data) where data is a render
context object — not a TokenDocument. data.actor was undefined,
and data?.token?.actor was also undefined. Use hud.token.actor
(or hud.object.actor) instead, which is the real PlaceableObject
with proper actor resolution.
Also fix html.find() → html.querySelector() for V2 HTMLElement.
- Replace Knockback with Internal Injury on D30 (5, 10, 15); remove Shield Bash from D30 counter-attacks
- Eliminate small weapon damage: keep only medium damage labelled Damage in sheets, rolls, and chat
- D30 bonus dice (20, 27, 30) auto-resolved before grit/luck/shield decisions; choice dialogs for special strikes
- D30 combat effects: bleeding wounds, damage ×2/×3 before DR, DR ×2/×3 with component picker dialog
- Add hp.wounds to monster schema for bleeding support
- Show Save against spell? checkbox for all save rolls (not just magic users)
- Fix mulligan restart: persistent D30 process flags prevent double-application and allow both sides to react
- For Dice So Nice, show main roll animation before explosion dice for correct ordering
- Spell tier selection: force Standard/Overpowered choice at cast time, tier-specific aether cost, only chosen damage button shown
- Add +1/−1 luck and grit controls to Token HUD
- Fix inconsistent indentation, remove duplicate i18n key, remove unused includesShield return