Let the AI use Goblin Welder - #11499
Conversation
4171132 to
57002e5
Compare
|
Rebased onto master and reworked. Two things changed the shape of this:
|
The card was AI:RemoveDeck:All, which is not only a deckbuilding flag: AiController.chooseSpellAbilityToPlay strips every ability of a flagged card from the candidate list, so the AI never activated it and no PumpAi code ran. Lifting the flag on its own is worse than leaving it. The ability targets both the artifact that gets sacrificed and the graveyard card that replaces it, and with no AILogic the generic pump targeting takes the most expensive artifact on the board regardless of who owns it. With only the flag removed it sacrificed a Sol Ring to get a Wurmcoil Engine back, welded a Sol Ring away for an Ornithopter when that was all our graveyard held, and - given an opponent holding the biggest artifact - sacrificed theirs to hand them a Blightsteel Colossus and two Wurm tokens. AILogic$ Weld picks the pair as one trade. Ours: something already marked expendable through the existing SacCost preference, otherwise the worst artifact we control, swapped for the best card in our graveyard. An opponent's: their best board artifact for the cheapest card in their graveyard, which turns the gift above into removal. The pair taken is the one with the largest mana value delta, and a positive delta is the whole go/no-go test - evaluatePermanentList values a non-creature permanent at CMC + 1, and ZoneExchangeAi gates its cross-zone swap on the same comparison. The sub-ability carries the tag too, because pumpTgtAI resets targets before it dispatches and the generic path would then take the opponent's best graveyard card. Timing goes through the shared AtOppEOT rule. AI:RemoveDeck:Random goes as well, since DeckGeneratorBase.AI_CAN_PLAY needs both flags clear and leaving it would keep the Welder out of every AI-generated deck. DeckNeeds:Type$Artifact replaces it. Only this card carries the new AILogic, so nothing else that goes through PumpAi changes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Plays until the AI welds of its own accord at the opponent's end step and checks what it chose. Two cases fail without the fix: our own worst artifact swapped up into the best one in our graveyard, and an opponent's artifact traded down for the junk in theirs. Two more caught earlier versions of this logic - an opponent graveyard holding both a bomb and junk, which needs the tag on the sub-ability, and a board offering our own upgrade alongside a larger swing against an opponent, which needs the search to weigh every pair rather than stop at the first profitable one. The last two guard the branch that declines when no trade gains anything. Drop this commit if you would rather not carry the test. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
57002e5 to
21d25a9
Compare
|
Rebased onto master — I also ran this in real games rather than only unit tests: 20 headless mirror matches with a mono-red artifact deck. The AI chose to weld 49 times — 22 upgrading its own board (Ichor Wellspring → Sundering Titan, Pyrite Spellbomb → Wurmcoil Engine), 27 against opponents (their Blightsteel Colossus → their Mind Stone). No exceptions. That run found a bug in my own logic, now fixed in the first commit: the sub-ability's targets weren't cleared on entry and the chosen pair was re-derived after the scan, so 2 of 30 decisions committed to a different card than the one they were scored on. It now keeps the pair it scored — 0 divergences in 49. Cost: the Limit the run also exposed: the go/no-go is mana value, so a cheap-but-strong artifact is undervalued (it will trade a Sol Ring for a Mind Stone) and a token's 0 counts as 0. That's Forge's shared permanent valuation rather than anything specific to this card — happy to address it here if you'd prefer, but I didn't want to change the global model in this PR. |
Goblin Welder was
AI:RemoveDeck:All, which is not only a deckbuilding flag:AiController.chooseSpellAbilityToPlaystrips every ability of a flagged card from the candidatelist, so on master the AI never activates it and no
PumpAicode runs.Lifting the flag alone is worse than leaving it. It targets both the artifact sacrificed and the
graveyard card replacing it; with no
AILogicthe generic pump targeting takes the most expensiveartifact on the board regardless of owner. With only the flag removed:
AILogic$ Weldpicks the pair as one trade, delegating each choice to what already exists:getCardPreference(… "SacCost" …), elsegetWorstAI. That keeps Sol Ringover Chromatic Star, which carries
SVar:SacMe:1.getBestRemovalTargetAI; welding against an opponent is removal.pumpMandatoryTarget: best from our graveyard, cheapest from theirs. Thesub-ability needs the tag too —
pumpTgtAIresets targets before dispatching, and the generic pathwould take their best.
evaluatePermanentListvalues a non-creature permanent atCMC + 1;ZoneExchangeAigates itsswap the same way. A point off an opponent counts as a point to us, as
GameStateEvaluatordoesfor board presence.
AtOppEOTrule.Only this card carries the
AILogic, so nothing else throughPumpAichanges.AI:RemoveDeck:Randomgoes too, sinceAI_CAN_PLAYneeds both flags clear;DeckNeeds:Type$Artifactreplaces it.Reasoned, not measured: the opponent's end step over acting earlier. Known limit: one candidate pair
per player, not every combination.
Six tests, second commit, droppable alone: two fail without the fix, two caught earlier versions of
this logic, two guard the "no trade" branch. Full desktop suite: 363 tests, 0 failures, 6 skipped.
Written with Claude Opus 5 (also recorded in the commit co-authors).