diff --git a/Mage.Sets/src/mage/cards/n/NetherTraitor.java b/Mage.Sets/src/mage/cards/n/NetherTraitor.java index 3b4f04d605d..b14e3bb93be 100644 --- a/Mage.Sets/src/mage/cards/n/NetherTraitor.java +++ b/Mage.Sets/src/mage/cards/n/NetherTraitor.java @@ -1,11 +1,8 @@ - package mage.cards.n; -import java.util.UUID; import mage.MageInt; -import mage.MageObject; -import mage.abilities.TriggeredAbilityImpl; -import mage.abilities.costs.mana.ColoredManaCost; +import mage.abilities.common.DiesCreatureTriggeredAbility; +import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.common.DoIfCostPaid; import mage.abilities.effects.common.ReturnSourceFromGraveyardToBattlefieldEffect; import mage.abilities.keyword.HasteAbility; @@ -14,11 +11,12 @@ import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.ColoredManaSymbol; +import mage.constants.TargetController; import mage.constants.Zone; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.ZoneChangeEvent; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.AnotherPredicate; + +import java.util.UUID; /** * @@ -26,6 +24,12 @@ import mage.game.events.ZoneChangeEvent; */ public final class NetherTraitor extends CardImpl { + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(); + static { + filter.add(AnotherPredicate.instance); + filter.add(TargetController.YOU.getOwnerPredicate()); + } + public NetherTraitor(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{B}{B}"); this.subtype.add(SubType.SPIRIT); @@ -39,7 +43,11 @@ public final class NetherTraitor extends CardImpl { this.addAbility(ShadowAbility.getInstance()); // Whenever another creature is put into your graveyard from the battlefield, you may pay {B}. If you do, return Nether Traitor from your graveyard to the battlefield. - this.addAbility(new NetherTraitorTriggeredAbility()); + this.addAbility(new DiesCreatureTriggeredAbility(Zone.GRAVEYARD, new DoIfCostPaid( + new ReturnSourceFromGraveyardToBattlefieldEffect(), + new ManaCostsImpl<>("{B}") + ), false, filter, false + ).setTriggerPhrase("Whenever another creature is put into your graveyard from the battlefield, ")); } private NetherTraitor(final NetherTraitor card) { @@ -52,53 +60,3 @@ public final class NetherTraitor extends CardImpl { } } -class NetherTraitorTriggeredAbility extends TriggeredAbilityImpl { - - NetherTraitorTriggeredAbility(){ - super(Zone.GRAVEYARD, new DoIfCostPaid(new ReturnSourceFromGraveyardToBattlefieldEffect(), new ColoredManaCost(ColoredManaSymbol.B))); - setLeavesTheBattlefieldTrigger(true); - } - - private NetherTraitorTriggeredAbility(final NetherTraitorTriggeredAbility ability) { - super(ability); - } - - @Override - public NetherTraitorTriggeredAbility copy(){ - return new NetherTraitorTriggeredAbility(this); - } - - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - for (Zone z : Zone.values()) { - if (game.checkShortLivingLKI(sourceId, z) && z != Zone.GRAVEYARD) { - return false; - } - } - if (zEvent.isDiesEvent()) { - if (zEvent.getTarget() != null && - zEvent.getTarget().isOwnedBy(this.getControllerId()) && - zEvent.getTarget().isCreature(game)&& - !zEvent.getTarget().getId().equals(this.getSourceId())) { - return true; - } - } - return false; - } - - @Override - public String getRule() { - return "Whenever another creature is put into your graveyard from the battlefield, you may pay {B}. If you do, return {this} from your graveyard to the battlefield."; - } - - @Override - public boolean isInUseableZone(Game game, MageObject sourceObject, GameEvent event) { - return TriggeredAbilityImpl.isInUseableZoneDiesTrigger(this, sourceObject, event, game); - } -} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/NetherTraitorTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/NetherTraitorTest.java new file mode 100644 index 00000000000..330b83237e2 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/tsp/NetherTraitorTest.java @@ -0,0 +1,118 @@ +package org.mage.test.cards.single.tsp; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author xenohedron + */ +public class NetherTraitorTest extends CardTestPlayerBase { + + private static final String nt = "Nether Traitor"; + /* Haste; shadow + Whenever another creature is put into your graveyard from the battlefield, you may pay {B}. + If you do, return this card from your graveyard to the battlefield. + */ + private static final String gb = "Goblin Bombardment"; // Sacrifice a creature: 1 damage to any target + private static final String wg = "Warpath Ghoul"; // 3/2 + + @Test + public void testNetherTraitorBattlefieldGhoulDies() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp"); + addCard(Zone.BATTLEFIELD, playerA, nt); + addCard(Zone.BATTLEFIELD, playerA, gb); + addCard(Zone.BATTLEFIELD, playerA, wg); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice"); + setChoice(playerA, wg); // to sac + addTarget(playerA, playerB); // 1 damage + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + assertGraveyardCount(playerA, wg, 1); + assertPermanentCount(playerA, nt, 1); + assertTapped("Swamp", false); + } + + @Test + public void testNetherTraitorBattlefieldAndDies() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp"); + addCard(Zone.BATTLEFIELD, playerA, nt); + addCard(Zone.BATTLEFIELD, playerA, gb); + addCard(Zone.BATTLEFIELD, playerA, wg); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice"); + setChoice(playerA, nt); // to sac + addTarget(playerA, playerB); // 1 damage + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + assertGraveyardCount(playerA, nt, 1); + assertPermanentCount(playerA, wg, 1); + assertTapped("Swamp", false); + } + + @Test + public void testNetherTraitorGraveyardGhoulDies() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp"); + addCard(Zone.GRAVEYARD, playerA, nt); + addCard(Zone.BATTLEFIELD, playerA, gb); + addCard(Zone.BATTLEFIELD, playerA, wg); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice"); + setChoice(playerA, wg); // to sac + addTarget(playerA, playerB); // 1 damage + setChoice(playerA, true); // yes to pay B and return + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 19); + assertGraveyardCount(playerA, wg, 1); + assertPermanentCount(playerA, nt, 1); + assertTapped("Swamp", true); + } + + /* Ruling: + If Nether Traitor and another creature are put into your graveyard at the same time, + Nether Traitor's ability won't trigger. + This is because it must be in your graveyard before the creature dies in order for its ability + that returns it to the battlefield to trigger. + */ + + @Test + public void testNetherTraitorGhoulBothDie() { + addCard(Zone.BATTLEFIELD, playerA, "Swamp"); + addCard(Zone.BATTLEFIELD, playerA, nt); + addCard(Zone.BATTLEFIELD, playerA, "Tooth and Claw"); + // Sacrifice two creatures: Create a 3/1 red Beast creature token named Carnivore. + addCard(Zone.BATTLEFIELD, playerA, wg); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sacrifice two"); + setChoice(playerA, wg + "^" + nt); // to sac + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertLife(playerA, 20); + assertLife(playerB, 20); + assertPermanentCount(playerA, "Carnivore", 1); + assertGraveyardCount(playerA, wg, 1); + assertGraveyardCount(playerA, nt, 1); + assertTapped("Swamp", false); + } + +} diff --git a/Mage/src/main/java/mage/game/permanent/token/CarnivoreToken.java b/Mage/src/main/java/mage/game/permanent/token/CarnivoreToken.java index 2b5f57ae67f..cb0d03f0146 100644 --- a/Mage/src/main/java/mage/game/permanent/token/CarnivoreToken.java +++ b/Mage/src/main/java/mage/game/permanent/token/CarnivoreToken.java @@ -10,7 +10,7 @@ import mage.constants.SubType; public final class CarnivoreToken extends TokenImpl { public CarnivoreToken() { - super("Carnivore Token", "3/1 red Beast creature token"); + super("Carnivore", "3/1 red Beast creature token"); cardType.add(CardType.CREATURE); color.setRed(true); subtype.add(SubType.BEAST);