Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion forge-ai/src/main/java/forge/ai/SpellApiToAi.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public enum SpellApiToAi {
.put(ApiType.Regenerate, RegenerateAi.class)
.put(ApiType.Regeneration, AlwaysPlayAi.class)
.put(ApiType.RemoveCounter, CountersRemoveAi.class)
.put(ApiType.RemoveCounterAll, CannotPlayAi.class)
.put(ApiType.RemoveCounterAll, CountersRemoveAllAi.class)
.put(ApiType.RemoveFromCombat, RemoveFromCombatAi.class)
.put(ApiType.RemoveFromGame, AlwaysPlayAi.class)
.put(ApiType.RemoveFromMatch, AlwaysPlayAi.class)
Expand Down
26 changes: 26 additions & 0 deletions forge-ai/src/main/java/forge/ai/ability/CountersRemoveAllAi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package forge.ai.ability;

import forge.ai.AiAbilityDecision;
import forge.ai.AiPlayDecision;
import forge.ai.SpellAbilityAi;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;

/**
* The AI has no logic for choosing to remove all counters of a kind, so it still will not activate
* one on purpose. As a sub-ability it is a consequence of an effect the AI has already decided it
* wants - usually bookkeeping, like Oblivion Stone clearing the fate counters it just checked - so
* it must not veto its own parent.
*/
public class CountersRemoveAllAi extends SpellAbilityAi {

@Override
protected AiAbilityDecision canPlay(Player aiPlayer, SpellAbility sa) {
return new AiAbilityDecision(0, AiPlayDecision.CantPlayAi);
}

@Override
public AiAbilityDecision chkDrawback(Player aiPlayer, SpellAbility sa) {
return new AiAbilityDecision(100, AiPlayDecision.WillPlay);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package forge.ai.ability;

import forge.ai.AITest;
import forge.game.Game;
import forge.game.phase.PhaseType;
import forge.game.player.Player;
import forge.game.zone.ZoneType;
import org.testng.annotations.Test;

import static junit.framework.Assert.assertEquals;

/**
* RemoveCounterAll has no AI, so as a sub-ability it used to refuse and take its parent down with
* it. Oblivion Stone's wipe ends by clearing the fate counters it just checked, which meant the
* wipe itself could never be activated.
*/
public class RemoveCounterAllDrawbackTest extends AITest {

@Test
public void bookkeepingSubAbilityDoesNotVetoTheWipe() {
Game game = initAndCreateGame();
Player ai = game.getPlayers().get(1);
Player opp = game.getPlayers().get(0);
ai.setTeam(0);
opp.setTeam(1);

for (int i = 0; i < 8; i++) {
addCard("Wastes", ai);
}
fillLibrary(ai, 15);
fillLibrary(opp, 15);
// nothing of the AI's own is in range, so the wipe is pure upside
addCard("Grizzly Bears", opp);
addCard("Grizzly Bears", opp);
addCard("Grizzly Bears", opp);
addCard("Oblivion Stone", ai);

game.getPhaseHandler().devModeSet(PhaseType.MAIN2, ai);
game.getAction().checkStateEffects(true);
playUntilNextTurn(game);

assertEquals("it sacrificed Oblivion Stone to wipe", 1,
countCardsWithName(game, "Oblivion Stone", ZoneType.Graveyard));
assertEquals("the opponent's board is gone", 0,
countCardsWithName(game, "Grizzly Bears", ZoneType.Battlefield));
}
}
3 changes: 1 addition & 2 deletions forge-gui/res/cardsfolder/o/oblivion_stone.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
Name:Oblivion Stone
ManaCost:3
Types:Artifact
A:AB$ PutCounter | Cost$ 4 T | ValidTgts$ Permanent | CounterType$ FATE | CounterNum$ 1 | SpellDescription$ Put a fate counter on target permanent.
A:AB$ PutCounter | Cost$ 4 T | ValidTgts$ Permanent | CounterType$ FATE | CounterNum$ 1 | AILogic$ AtOppEOT | AITgts$ Permanent.YouCtrl+Other+nonLand | SpellDescription$ Put a fate counter on target permanent.
A:AB$ DestroyAll | Cost$ 5 T Sac<1/CARDNAME> | ValidCards$ Permanent.nonLand+counters_LT1_FATE | SubAbility$ DBRemove | SpellDescription$ Destroy each nonland permanent without a fate counter on it, then remove all fate counters from all permanents.
SVar:DBRemove:DB$ RemoveCounterAll | ValidCards$ Permanent | CounterType$ FATE | AllCounters$ True
AI:RemoveDeck:All
Oracle:{4}, {T}: Put a fate counter on target permanent.\n{5}, {T}, Sacrifice Oblivion Stone: Destroy each nonland permanent without a fate counter on it, then remove all fate counters from all permanents.