mirror of
https://github.com/correl/mage.git
synced 2025-03-07 20:53:18 -10:00
* Opportunistic Dragon - Fixed that the can't attack effect was not discarded if the Opportunistic Dragon left the battlefield.
This commit is contained in:
parent
133cc7342d
commit
1977e7f986
2 changed files with 133 additions and 69 deletions
|
@ -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.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue