From 507ddd871125d0d31fdf88329eb68ea18bf226ee Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 4 Sep 2016 17:14:27 +0200 Subject: [PATCH 1/3] * Necromancer's Magemark - Fixed replacement effect that was coded as triggered ability. --- .../sets/guildpact/NecromancersMagemark.java | 80 ++++++++++++++++--- .../KalitasTraitorOfGhet.java | 8 +- .../replacement/KalitasTraitorOfGhetTest.java | 55 ++++++++++--- 3 files changed, 119 insertions(+), 24 deletions(-) diff --git a/Mage.Sets/src/mage/sets/guildpact/NecromancersMagemark.java b/Mage.Sets/src/mage/sets/guildpact/NecromancersMagemark.java index 3b1a1d62470..ee646a5cf31 100644 --- a/Mage.Sets/src/mage/sets/guildpact/NecromancersMagemark.java +++ b/Mage.Sets/src/mage/sets/guildpact/NecromancersMagemark.java @@ -29,11 +29,9 @@ package mage.sets.guildpact; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.Effect; +import mage.abilities.effects.ReplacementEffectImpl; import mage.abilities.effects.common.AttachEffect; -import mage.abilities.effects.common.ReturnToHandSourceEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; @@ -46,6 +44,11 @@ import mage.constants.Zone; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerPredicate; import mage.filter.predicate.permanent.EnchantedPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.events.ZoneChangeEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCreaturePermanent; @@ -55,12 +58,13 @@ import mage.target.common.TargetCreaturePermanent; */ public class NecromancersMagemark extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Creatures you control that are enchanted"); + private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures you control that are enchanted"); + static { filter.add(new EnchantedPredicate()); filter.add(new ControllerPredicate(TargetController.YOU)); } - + public NecromancersMagemark(UUID ownerId) { super(ownerId, 53, "Necromancer's Magemark", Rarity.COMMON, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); this.expansionSetCode = "GPT"; @@ -72,13 +76,13 @@ public class NecromancersMagemark extends CardImpl { this.getSpellAbility().addEffect(new AttachEffect(Outcome.AddAbility)); Ability ability = new EnchantAbility(auraTarget.getTargetName()); this.addAbility(ability); + // Creatures you control that are enchanted get +1/+1. - ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1,1, Duration.WhileOnBattlefield, filter, false)); + ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostAllEffect(1, 1, Duration.WhileOnBattlefield, filter, false)); this.addAbility(ability); + // If a creature you control that's enchanted would die, return it to its owner's hand instead. - Effect effect = new ReturnToHandSourceEffect(); - ability = new DiesCreatureTriggeredAbility(effect,false); - this.addAbility(ability); + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new NecromancersMagemarkEffect())); } public NecromancersMagemark(final NecromancersMagemark card) { @@ -90,3 +94,61 @@ public class NecromancersMagemark extends CardImpl { return new NecromancersMagemark(this); } } + +class NecromancersMagemarkEffect extends ReplacementEffectImpl { + + public NecromancersMagemarkEffect() { + super(Duration.WhileOnBattlefield, Outcome.Benefit); + staticText = "If a creature you control that's enchanted would die, return it to its owner's hand instead"; + } + + public NecromancersMagemarkEffect(final NecromancersMagemarkEffect effect) { + super(effect); + } + + @Override + public NecromancersMagemarkEffect copy() { + return new NecromancersMagemarkEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + return true; + } + + @Override + public boolean replaceEvent(GameEvent event, Ability source, Game game) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller != null) { + Permanent permanent = ((ZoneChangeEvent) event).getTarget(); + if (permanent != null) { + controller.moveCards(permanent, Zone.HAND, source, game); + return true; + } + } + return false; + } + + @Override + public boolean checksEventType(GameEvent event, Game game) { + return event.getType().equals(GameEvent.EventType.ZONE_CHANGE); + } + + @Override + public boolean applies(GameEvent event, Ability source, Game game) { + ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (zEvent.getFromZone().equals(Zone.BATTLEFIELD) && zEvent.getToZone().equals(Zone.GRAVEYARD)) { + Permanent permanent = ((ZoneChangeEvent) event).getTarget(); + if (permanent != null && permanent.getControllerId().equals(source.getControllerId())) { + for (UUID attachmentId : permanent.getAttachments()) { + Permanent attachment = game.getPermanentOrLKIBattlefield(attachmentId); + if (attachment != null && attachment.getSubtype(game).contains("Aura")) { + return true; + } + } + } + } + return false; + } + +} diff --git a/Mage.Sets/src/mage/sets/oathofthegatewatch/KalitasTraitorOfGhet.java b/Mage.Sets/src/mage/sets/oathofthegatewatch/KalitasTraitorOfGhet.java index 45033a33995..2e21ba1e903 100644 --- a/Mage.Sets/src/mage/sets/oathofthegatewatch/KalitasTraitorOfGhet.java +++ b/Mage.Sets/src/mage/sets/oathofthegatewatch/KalitasTraitorOfGhet.java @@ -63,7 +63,7 @@ import mage.target.common.TargetControlledCreaturePermanent; * @author fireshoes */ public class KalitasTraitorOfGhet extends CardImpl { - + private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("another Vampire or Zombie"); static { @@ -83,10 +83,10 @@ public class KalitasTraitorOfGhet extends CardImpl { // Lifelink this.addAbility(LifelinkAbility.getInstance()); - + // If a nontoken creature an opponent controls would die, instead exile that card and put a 2/2 black Zombie creature token onto the battlefield. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new KalitasTraitorOfGhetEffect())); - + // {2}{B}, Sacrifice another Vampire or Zombie: Put two +1/+1 counters on Kalitas, Traitor of Ghet. Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AddCountersSourceEffect(CounterType.P1P1.createInstance(2)), new ManaCostsImpl("{2}{B}")); ability.addCost(new SacrificeTargetCost(new TargetControlledCreaturePermanent(filter))); @@ -131,7 +131,7 @@ class KalitasTraitorOfGhetEffect extends ReplacementEffectImpl { if (((ZoneChangeEvent) event).getFromZone().equals(Zone.BATTLEFIELD)) { Permanent permanent = ((ZoneChangeEvent) event).getTarget(); if (permanent != null) { - controller.moveCardToExileWithInfo(permanent, null, null, source.getSourceId(), game, Zone.BATTLEFIELD, true); + controller.moveCards(permanent, Zone.EXILED, source, game); new CreateTokenEffect(new ZombieToken()).apply(game, source); return true; } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java index 5191c1ae612..427ab5bfb53 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/replacement/KalitasTraitorOfGhetTest.java @@ -15,41 +15,74 @@ import org.mage.test.serverside.base.CardTestPlayerBase; * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public class KalitasTraitorOfGhetTest extends CardTestPlayerBase { - + /* * Reported bug: Damnation with Kalitas, Traitor of Ghet on my side and 3 opponent creatures, it only exiled 1 creature giving me only 1 zombie instead of 3. - */ + */ @Test public void testDamnation() { - + /* Kalitas, Traitor of Ghet {2}{B}{B} 3/4 lifelink - Legendary Vampire If a nontoken creature an opponent controls would die, instead exile that card and put a 2/2 black Zombie creature token onto the battlefield. - */ + */ addCard(Zone.BATTLEFIELD, playerA, "Kalitas, Traitor of Ghet", 1); /* Damnation {2}{B}{B} - Sorcery Destroy all creatures. They can't be regenerated. - */ + */ addCard(Zone.HAND, playerA, "Damnation", 1); - + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); - + addCard(Zone.BATTLEFIELD, playerB, "Bronze Sable", 1); addCard(Zone.BATTLEFIELD, playerB, "Wall of Roots", 1); addCard(Zone.BATTLEFIELD, playerB, "Sigiled Starfish", 1); - + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Damnation"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); - + assertGraveyardCount(playerA, "Kalitas, Traitor of Ghet", 1); assertGraveyardCount(playerA, "Damnation", 1); assertExileCount("Bronze Sable", 1); assertExileCount("Wall of Roots", 1); - assertExileCount("Sigiled Starfish", 1); + assertExileCount("Sigiled Starfish", 1); assertGraveyardCount(playerB, 0); // all 3 creatures of playerB should be exiled not in graveyard - assertExileCount("Kalitas, Traitor of Ghet", 0); // player controlled, not opponent so not exiled + assertExileCount("Kalitas, Traitor of Ghet", 0); // player controlled, not opponent so not exiled assertPermanentCount(playerA, "Zombie", 3); // 3 tokens generated from exiling 3 opponent's creatures } + + @Test + public void testDamnationGraveyard() { + + /* + Kalitas, Traitor of Ghet {2}{B}{B} 3/4 lifelink - Legendary Vampire + If a nontoken creature an opponent controls would die, instead exile that card and put a 2/2 black Zombie creature token onto the battlefield. + */ + addCard(Zone.GRAVEYARD, playerA, "Kalitas, Traitor of Ghet", 1); + /* + Damnation {2}{B}{B} - Sorcery + Destroy all creatures. They can't be regenerated. + */ + addCard(Zone.HAND, playerA, "Damnation", 1); + + addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); + + addCard(Zone.BATTLEFIELD, playerB, "Bronze Sable", 1); + addCard(Zone.BATTLEFIELD, playerB, "Wall of Roots", 1); + addCard(Zone.BATTLEFIELD, playerB, "Sigiled Starfish", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Damnation"); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Kalitas, Traitor of Ghet", 1); + assertGraveyardCount(playerA, "Damnation", 1); + assertGraveyardCount(playerB, "Bronze Sable", 1); + assertGraveyardCount(playerB, "Wall of Roots", 1); + assertGraveyardCount(playerB, "Sigiled Starfish", 1); + assertPermanentCount(playerA, "Zombie", 0); // 3 tokens generated from exiling 3 opponent's creatures + } + } From 133f0434114b73a39d7915b930cd9b0c57f83324 Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 4 Sep 2016 17:17:34 +0200 Subject: [PATCH 2/3] * Orcish Spy - Fixed that the activated ability did not work. --- Mage.Sets/src/mage/sets/fallenempires/OrcishSpy1.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mage.Sets/src/mage/sets/fallenempires/OrcishSpy1.java b/Mage.Sets/src/mage/sets/fallenempires/OrcishSpy1.java index cc6aed47697..27f7b40f698 100644 --- a/Mage.Sets/src/mage/sets/fallenempires/OrcishSpy1.java +++ b/Mage.Sets/src/mage/sets/fallenempires/OrcishSpy1.java @@ -52,8 +52,8 @@ public class OrcishSpy1 extends CardImpl { this.power = new MageInt(1); this.toughness = new MageInt(1); - // {tap}: Look at the top three cards of target player's library. - Ability ability = new SimpleActivatedAbility(Zone.LIBRARY, new LookLibraryTopCardTargetPlayerEffect(3), new TapSourceCost()); + // {T}: Look at the top three cards of target player's library. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new LookLibraryTopCardTargetPlayerEffect(3), new TapSourceCost()); this.addAbility(ability); } From 3d19637e8565d75291adc8c4e9339e8a939d774d Mon Sep 17 00:00:00 2001 From: LevelX2 Date: Sun, 4 Sep 2016 17:41:33 +0200 Subject: [PATCH 3/3] Added test for Oracle of Dust activated ability. --- .../activated/PutToGraveyardTest.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java index dbb7b582684..1c3ab43a882 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/activated/PutToGraveyardTest.java @@ -72,4 +72,32 @@ public class PutToGraveyardTest extends CardTestPlayerBase { } + /** + * Oracle of Dust does not seem to actually move cards from exile into the + * opponent's graveyard, even though every other part of the ability works + * just fine. + */ + @Test + public void testExileToGraveyard2() { + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + // Devoid + // {2}, Put a card an opponent owns from exile into that player's graveyard: Draw a card, then discard a card. + addCard(Zone.BATTLEFIELD, playerA, "Oracle of Dust", 1); // {4}{U} + + addCard(Zone.BATTLEFIELD, playerB, "Silvercoat Lion"); + // Exile target creature. Its controller gains life equal to its power. + addCard(Zone.HAND, playerA, "Swords to Plowshares"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Swords to Plowshares", "Silvercoat Lion"); + + activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "{2}"); + + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertGraveyardCount(playerA, "Swords to Plowshares", 1); + assertGraveyardCount(playerB, "Silvercoat Lion", 1); + assertGraveyardCount(playerA, 2); + + } }