Skip to content

AI: don't let a RemoveCounterAll sub-ability veto its own parent - #11491

Open
liamiak wants to merge 3 commits into
Card-Forge:masterfrom
liamiak:ai-oblivion-stone
Open

AI: don't let a RemoveCounterAll sub-ability veto its own parent#11491
liamiak wants to merge 3 commits into
Card-Forge:masterfrom
liamiak:ai-oblivion-stone

Conversation

@liamiak

@liamiak liamiak commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

ApiType.RemoveCounterAll maps to CannotPlayAi, which refuses in chkDrawback as well as
canPlay. chkDrawbackWithSubs bails on any unwilling sub-ability, so a RemoveCounterAll sub
takes its parent down with it.

Oblivion Stone's wipe ends by clearing the fate counters it just checked. DestroyAllAi correctly
said play it; the bookkeeping step said no, and the ability was unreachable. Alaundo the Seer's
{T} is dead the same way — it ends by ticking time counters on suspended cards — and it is
unflagged.

17 of the 19 cards reaching this API use it as a sub-ability, and all sixteen distinct ones are a
consequence of their parent rather than a decision: clear the FATE counters just checked, reset your
own +1/+1s, tick TIME counters on suspended cards, remove a -1/-1 from your own creature. Only
Aether Snap and Thief of Blood use it as a main ability, where refusing is coherent — canPlay
still refuses, so nothing gains a new main ability.

Most of the other 15 are triggers, so for those this rests on reading the scripts rather than on
measurement.

Fate counters

Both abilities cost {T}, so seeding on the AI's own turn costs it the wipe. AILogic$ AtOppEOT
moves it to the opponent's end step, where the tap is free and the mana is spare. AITgts keeps it
off the Stone itself — sacrificed as a cost, so gone before the wipe checks fate counters — and off
lands, which the wipe does not destroy. Without that filter the AI protected the Stone 6/6; with it,
its Colossal Dreadmaw 6/6.

Unflags Oblivion Stone.

Not addressed: the wipe is instant speed but probes WillPlay at every phase of both turns, so
it fires at the first opportunity rather than the last responsible moment. That is shared
DestroyAllAi timing affecting every instant-speed mass removal, so it wants its own change.

Test fails without the change — the AI never activates the wipe. 337 tests, 0 failures.

🤖 Implemented with the assistance of Claude Code (Opus 5).

liamiak1 and others added 3 commits August 2, 2026 10:50
RemoveCounterAll maps to CannotPlayAi, which refuses in chkDrawback too. As a
sub-ability that takes the parent down with it: Oblivion Stone's wipe ends by
clearing the fate counters it just checked, so DestroyAllAi said play it and
the bookkeeping step said no. Alaundo the Seer's tap ability is dead the same
way, and it is unflagged.

17 of the 19 cards reaching this API use it as a sub-ability, and each is a
consequence of its parent rather than a decision. canPlay still refuses, so
nothing gains a new main ability.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Both abilities cost {T}, so seeding on the AI's own turn costs it the wipe. At
the opponent's end step the tap is free - the AI untaps first - and the mana is
spare by then.

AITgts keeps it off the Stone itself, which is sacrificed as a cost and gone
before the wipe checks fate counters, and off lands, which the wipe does not
destroy. Without it the AI protected the Stone 6/6.

Unflags Oblivion Stone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants