Clean up the ability when a cast is rolled back via snapshot - #11418
Clean up the ability when a cast is rolled back via snapshot#11418cuinhellcat wants to merge 1 commit into
Conversation
…rge#10049, Card-Forge#8762) rollbackAbility returns as soon as the snapshot has been restored, on the grounds that the manual rollback would double up on it. That holds for the cards, their zones and the mana pool — restoring those twice would refund mana the snapshot already put back — but not for everything the early return skips. The ability object is not part of a snapshot. Its announced values, the X it was cast for, chosen modes and targets, and the once-resolved flag all survive the rollback, as do castSA and castFrom on the card and the frozen stack with its waiting triggers. That leaves the card in a state where the next cast uses stale values or is refused outright, which is what Card-Forge#10049 describes (March of the Otherworldly Light can no longer be cast after cancelling with an invalid number), and it leaves the stack frozen, which matches the freeze on cancel in Card-Forge#8762. Do that part of the cleanup in both paths, still without the refund and without touching zones. The values reset here are the ones the manual path already resets; they are pulled into two helpers so both paths stay in step. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Hmn? |
|
Different directions of the snapshot. Taking one builds new cards, so their abilities are fresh. Restoring one builds nothing: Unmodified master — stash, set The manual path already resets exactly this, a few lines below the early return: Concretely: announce X=4 on Fireball, cancel at the mana prompt. With undo restore on, the card is back in hand still carrying X=4 and its target, and the stack stays frozen — #10049 and #8762 from the outside. Refund and zone handling stay skipped, since the snapshot covers those. |
Addresses #10049 and, most likely, #8762.
Problem
GameActionUtil.rollbackAbilityreturns as soon as the snapshot has been restored:That is right for the cards, their zones and the mana pool —
copyManaPoolalready puts the mana back, sopayment.refundPayment()on top of it would hand out the mana twice. It is not right for everything else the early return skips:ability.setXManaCostPaid(null),setSpendPhyrexianMana(false),clearPipsToReduce(),setPaidLife(0)and theAnnounceSVarsability.clearTargets(), the Charm mode chain,resetOnceResolved()oldCard.setCastSA(null)andsetCastFrom(null)game.getStack().clearFrozen()andgetTriggerHandler().clearWaitingTriggers()A
SpellAbilityis not part of a snapshot, and neither is the frozen stack. So after cancelling a cast with undo restore enabled, the card keeps the announced value and targets from the attempt that was called off, still believes it is being cast, and the stack stays frozen.That is what the two reports look like from the outside:
Hanmacalready pointed atGameSnapshotin that thread, and the reporter was told to turn undo restore off.Fix
Do the ability-level cleanup in both paths — still no refund, still no zone handling. The values reset in the snapshot path are the same ones the manual path resets, pulled into two small helpers so the paths cannot drift apart.
Reproduction
At engine level: enable snapshots, stash, then set
xManaCostPaid,castSA,castFromand freeze the stack the way a cast does, and callrollbackAbility. Before the change the announced X, the cast markers and the frozen stack all survive; after it they are gone. I could not drive the actual GUI cancel headlessly, so I have not confirmed the two reports end to end — the mechanism matches what they describe.Notes
AI disclosure
Written with Claude Code (Claude Opus 5), as requested in CONTRIBUTING; the agent is also recorded as co-author on the commit.