diff --git a/Mage.Sets/src/mage/cards/o/OpportunisticDragon.java b/Mage.Sets/src/mage/cards/o/OpportunisticDragon.java index d4e9aa97462..60d557c2625 100644 --- a/Mage.Sets/src/mage/cards/o/OpportunisticDragon.java +++ b/Mage.Sets/src/mage/cards/o/OpportunisticDragon.java @@ -1,5 +1,6 @@ package mage.cards.o; +import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; @@ -19,10 +20,9 @@ import mage.filter.predicate.mageobject.CardTypePredicate; import mage.filter.predicate.mageobject.SubtypePredicate; import mage.filter.predicate.permanent.ControllerPredicate; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.target.TargetPermanent; -import java.util.UUID; - /** * @author TheElk801 */ @@ -48,7 +48,8 @@ public final class OpportunisticDragon extends CardImpl { // Flying this.addAbility(FlyingAbility.getInstance()); - // When Opportunistic Dragon enters the battlefield, choose target Human or artifact an opponent controls. For as long as Opportunistic Dragon remains on the battlefield, gain control of that permanent, it loses all abilities, and it can't attack or block. + // When Opportunistic Dragon enters the battlefield, choose target Human or artifact an opponent controls. + // For as long as Opportunistic Dragon remains on the battlefield, gain control of that permanent, it loses all abilities, and it can't attack or block. Ability ability = new EntersBattlefieldTriggeredAbility(new OpportunisticDragonControlEffect()); ability.addEffect(new OpportunisticDragonLoseAbilitiesEffect()); ability.addEffect(new OpportunisticDragonAttackBlockEffect()); @@ -70,8 +71,8 @@ class OpportunisticDragonControlEffect extends GainControlTargetEffect { OpportunisticDragonControlEffect() { super(Duration.Custom); - staticText = "choose target Human or artifact an opponent controls. " + - "For as long as {this} remains on the battlefield, gain control of that permanent,"; + staticText = "choose target Human or artifact an opponent controls. " + + "For as long as {this} remains on the battlefield, gain control of that permanent,"; } private OpportunisticDragonControlEffect(final OpportunisticDragonControlEffect effect) { @@ -136,11 +137,11 @@ class OpportunisticDragonAttackBlockEffect extends CantAttackBlockTargetEffect { } @Override - public boolean apply(Game game, Ability source) { + public boolean applies(Permanent permanent, Ability source, Game game) { if (source.getSourcePermanentIfItStillExists(game) == null) { discard(); return false; } - return super.apply(game, source); + return super.applies(permanent, source, game); //To change body of generated methods, choose Tools | Templates. } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java index 3458edce5d9..af517d7c5bd 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/restriction/CantAttackTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.restriction; import mage.constants.PhaseStep; @@ -140,56 +139,56 @@ public class CantAttackTest extends CardTestPlayerBase { assertTapped("Silvercoat Lion", false); assertPowerToughness(playerB, "Silvercoat Lion", 4, 4); } - + /* Reported bug: Medomai was able to attack on an extra turn when cheated into play. - */ + */ @Test public void testMedomaiShouldNotAttackOnExtraTurns() { - + /* Medomai the Ageless {4}{W}{U} Legendary Creature — Sphinx 4/4 Flying Whenever Medomai the Ageless deals combat damage to a player, take an extra turn after this one. Medomai the Ageless can't attack during extra turns. - */ + */ String medomai = "Medomai the Ageless"; - + /* Cauldron Dance {4}{B}{R} Instant Cast Cauldron Dance only during combat. Return target creature card from your graveyard to the battlefield. That creature gains haste. Return it to your hand at the beginning of the next end step. You may put a creature card from your hand onto the battlefield. That creature gains haste. Its controller sacrifices it at the beginning of the next end step. - */ + */ String cDance = "Cauldron Dance"; - String dBlade = "Doom Blade"; // {1}{B} instant destroy target creature + String dBlade = "Doom Blade"; // {1}{B} instant destroy target creature addCard(Zone.BATTLEFIELD, playerA, medomai); addCard(Zone.HAND, playerA, dBlade); addCard(Zone.HAND, playerA, cDance); addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); - + // attack with Medomai, connect, and destroy him after combat attack(1, playerA, medomai); castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, dBlade, medomai); - + // next turn granted, return Medomai to field with Cauldron and try to attack again castSpell(2, PhaseStep.BEGIN_COMBAT, playerA, cDance); addTarget(playerA, medomai); attack(2, playerA, medomai); - + // medomai should not have been allowed to attack, but returned to hand at beginning of next end step still setStopAt(2, PhaseStep.END_TURN); execute(); - + assertLife(playerB, 16); // one hit from medomai assertGraveyardCount(playerA, dBlade, 1); assertGraveyardCount(playerA, cDance, 1); assertGraveyardCount(playerA, medomai, 0); assertHandCount(playerA, medomai, 1); } - + @Test public void basicMedomaiTestForExtraTurn() { /* @@ -198,184 +197,248 @@ public class CantAttackTest extends CardTestPlayerBase { Flying Whenever Medomai the Ageless deals combat damage to a player, take an extra turn after this one. Medomai the Ageless can't attack during extra turns. - */ + */ String medomai = "Medomai the Ageless"; - + /* Exquisite Firecraft {1}{R}{R} Sorcery Exquisite Firecraft deals 4 damage to any target. - */ + */ String eFirecraft = "Exquisite Firecraft"; - + addCard(Zone.BATTLEFIELD, playerA, medomai); addCard(Zone.HAND, playerA, eFirecraft); addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); - + // attack with medomai, get extra turn, confirm cannot attack again with medomai and can cast sorcery attack(1, playerA, medomai); attack(2, playerA, medomai); // should not be allowed to castSpell(2, PhaseStep.POSTCOMBAT_MAIN, playerA, eFirecraft, playerB); - + setStopAt(2, PhaseStep.END_TURN); execute(); - + assertLife(playerB, 12); // 1 hit from medomai and firecraft = 8 damage assertGraveyardCount(playerA, eFirecraft, 1); assertPermanentCount(playerA, medomai, 1); } - + @Test - public void sphereOfSafetyPaidCostAllowsAttack() { + public void sphereOfSafetyPaidCostAllowsAttack() { /* Sphere of Safety {4}{W} Enchantment Creatures can't attack you or a planeswalker you control unless their controller pays {X} for each of those creatures, where X is the number of enchantments you control. - */ + */ String sphere = "Sphere of Safety"; String memnite = "Memnite"; - + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 addCard(Zone.BATTLEFIELD, playerB, sphere); addCard(Zone.BATTLEFIELD, playerA, "Forest"); - + attack(1, playerA, memnite); setChoice(playerA, "Yes"); - + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertPermanentCount(playerB, sphere, 1); assertLife(playerB, 19); // took the hit from memnite assertTapped("Forest", true); // forest had to be tapped } - + @Test public void sphereOfSafetyCostNotPaid_NoAttackAllowed() { /* Sphere of Safety {4}{W} Enchantment Creatures can't attack you or a planeswalker you control unless their controller pays {X} for each of those creatures, where X is the number of enchantments you control. - */ + */ String sphere = "Sphere of Safety"; String memnite = "Memnite"; - + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 addCard(Zone.BATTLEFIELD, playerB, sphere); addCard(Zone.BATTLEFIELD, playerA, "Forest"); - + attack(1, playerA, memnite); setChoice(playerA, "No"); - + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertPermanentCount(playerB, sphere, 1); assertLife(playerB, 20); // no damage went through, did not elect to pay assertTapped("Forest", false); // forest not tapped } - + @Test - public void collectiveResistanceCostPaid_AttackAllowed() - { + public void collectiveResistanceCostPaid_AttackAllowed() { /* Collective Restraint {3}{U} Enchantment Domain — Creatures can't attack you unless their controller pays {X} for each creature they control that's attacking you, where X is the number of basic land types among lands you control. - */ + */ String cRestraint = "Collective Restraint"; String memnite = "Memnite"; - + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 addCard(Zone.BATTLEFIELD, playerB, cRestraint); addCard(Zone.BATTLEFIELD, playerB, "Island"); // 1 basic land type = pay 1 to attack addCard(Zone.BATTLEFIELD, playerA, "Forest"); - + attack(1, playerA, memnite); setChoice(playerA, "Yes"); - + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertPermanentCount(playerB, cRestraint, 1); assertLife(playerB, 19); // took the hit from memnite assertTapped("Forest", true); // forest had to be tapped } - + @Test - public void collectiveResistanceCostNotPaid_NoAttackAllowed() - { + public void collectiveResistanceCostNotPaid_NoAttackAllowed() { /* Collective Restraint {3}{U} Enchantment Domain — Creatures can't attack you unless their controller pays {X} for each creature they control that's attacking you, where X is the number of basic land types among lands you control. - */ + */ String cRestraint = "Collective Restraint"; String memnite = "Memnite"; - + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 addCard(Zone.BATTLEFIELD, playerB, cRestraint); addCard(Zone.BATTLEFIELD, playerB, "Island"); // 1 basic land type = pay 1 to attack addCard(Zone.BATTLEFIELD, playerA, "Forest"); - + attack(1, playerA, memnite); setChoice(playerA, "No"); - + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertPermanentCount(playerB, cRestraint, 1); assertLife(playerB, 20); // no damage went through, did not elect to pay assertTapped("Forest", false); // forest not tapped } - + @Test - public void ghostlyPrison_PaidCost_AllowsAttack() { + public void ghostlyPrison_PaidCost_AllowsAttack() { /* Ghostly Prison {2}{W} Enchantment Creatures can't attack you unless their controller pays {2} for each creature they control that's attacking you. - */ + */ String gPrison = "Ghostly Prison"; String memnite = "Memnite"; - + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 addCard(Zone.BATTLEFIELD, playerB, gPrison); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); - + attack(1, playerA, memnite); setChoice(playerA, "Yes"); - + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertPermanentCount(playerB, gPrison, 1); assertLife(playerB, 19); // took the hit from memnite assertTappedCount("Forest", true, 2); // forests had to be tapped } - + @Test public void ghostlyPrison_CostNotPaid_NoAttackAllowed() { /* Ghostly Prison {2}{W} Enchantment Creatures can't attack you unless their controller pays {2} for each creature they control that's attacking you. - */ + */ String gPrison = "Ghostly Prison"; String memnite = "Memnite"; - + addCard(Zone.BATTLEFIELD, playerA, memnite); // {0} 1/1 addCard(Zone.BATTLEFIELD, playerB, gPrison); addCard(Zone.BATTLEFIELD, playerA, "Forest", 2); - + attack(1, playerA, memnite); setChoice(playerA, "No"); - + setStopAt(1, PhaseStep.POSTCOMBAT_MAIN); execute(); - + assertPermanentCount(playerB, gPrison, 1); assertLife(playerB, 20); // no damage went through, did not elect to pay assertTapped("Forest", false); // no forests tapped } + + @Test + public void OpportunisticDragon() { + // Flying + // When Opportunistic Dragon enters the battlefield, choose target Human or artifact an opponent controls. For as long as Opportunistic Dragon remains on the battlefield, gain control of that permanent, it loses all abilities, and it can't attack or block. + addCard(Zone.HAND, playerA, "Opportunistic Dragon"); // Creature {2}{R}{R} + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerA, "Desperate Castaways"); // Creature - Human Pirate 2/3 + + // Other Pirates you control get +1/+1. + // At the beginning of your end step, gain control of target nonland permanent controlled by a player who was dealt combat damage by three or more Pirates this turn. + addCard(Zone.BATTLEFIELD, playerB, "Admiral Beckett Brass"); // Creature {1}{B}{B}{R} + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Opportunistic Dragon"); + addTarget(playerA, "Admiral Beckett Brass"); + + attack(3, playerA, "Admiral Beckett Brass"); // Can't attack + + setStopAt(3, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertPermanentCount(playerA, "Opportunistic Dragon", 1); + assertPermanentCount(playerA, "Admiral Beckett Brass", 1); + assertPowerToughness(playerA, "Desperate Castaways", 2, 3); + + assertLife(playerA, 20); + assertLife(playerB, 20); + } + + /* Opportunistic Dragon - can't block/can't attack effect did not end when opportunistic dragon was exiled */ + @Test + public void OpportunisticDragonEndEffects() { + // Flying + // When Opportunistic Dragon enters the battlefield, choose target Human or artifact an opponent controls. For as long as Opportunistic Dragon remains on the battlefield, gain control of that permanent, it loses all abilities, and it can't attack or block. + addCard(Zone.HAND, playerA, "Opportunistic Dragon"); // Creature {2}{R}{R} + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4); + addCard(Zone.BATTLEFIELD, playerA, "Desperate Castaways"); // Creature - Human Pirate 2/3 + + // Other Pirates you control get +1/+1. + // At the beginning of your end step, gain control of target nonland permanent controlled by a player who was dealt combat damage by three or more Pirates this turn. + addCard(Zone.BATTLEFIELD, playerB, "Admiral Beckett Brass"); // Creature {1}{B}{B}{R} 3/3 + addCard(Zone.BATTLEFIELD, playerB, "Desperate Castaways"); // Creature - Human Pirate 2/3 + // Destroy target nonartifact, nonblack creature. It can't be regenerated. + addCard(Zone.HAND, playerB, "Terror"); // Instant {1}{B} + addCard(Zone.BATTLEFIELD, playerB, "Swamp", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Opportunistic Dragon"); + addTarget(playerA, "Admiral Beckett Brass"); + + attack(3, playerA, "Admiral Beckett Brass"); // Can't attack + castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerB, "Terror", "Opportunistic Dragon"); + + attack(4, playerB, "Admiral Beckett Brass"); // Can attack again + + setStopAt(4, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertGraveyardCount(playerB, "Terror", 1); + assertGraveyardCount(playerA, "Opportunistic Dragon", 1); + assertPermanentCount(playerB, "Admiral Beckett Brass", 1); + assertPowerToughness(playerB, "Desperate Castaways", 3, 4); + + assertLife(playerA, 17); + assertLife(playerB, 20); + } + }