Skip to content

Commit

Permalink
Update HideawayPlay and Arcane Bombardment to not ask if you want to …
Browse files Browse the repository at this point in the history
…play the cards you chose.

Update tests, add tests for
- Select the order in which to play cards
- Attempt to play two lands with only one land drop available, only the first land enters play
- Play two lands with extra land drops available.
  • Loading branch information
Grath committed Oct 18, 2024
1 parent 4adf847 commit 811e5ba
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 17 deletions.
10 changes: 4 additions & 6 deletions Mage.Sets/src/mage/cards/a/ArcaneBombardment.java
Original file line number Diff line number Diff line change
Expand Up @@ -116,18 +116,16 @@ public boolean apply(Game game, Ability source) {

// Allow player to choose the order and cast the copies
if (!copies.isEmpty()) {
TargetCard target = new TargetCard(0, copies.size(), Zone.EXILED, new FilterCard("copies to cast"));
TargetCard target = new TargetCard(0, copies.size(), Zone.EXILED, new FilterCard("copies to cast (in order they're chosen)"));
player.choose(Outcome.PlayForFree, copies, target, source, game);
List<UUID> targets = target.getTargets();

for (UUID targetId : targets) {
Card copiedCard = game.getCard(targetId);
if (copiedCard != null && copiedCard.getSpellAbility() != null) {
if (player.chooseUse(Outcome.PlayForFree, "Cast the copy of " + copiedCard.getLogName() + "?", source, game)) {
game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE);
player.cast(player.chooseAbilityForCast(copiedCard, game, true), game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null);
}
game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), Boolean.TRUE);
player.cast(player.chooseAbilityForCast(copiedCard, game, true), game, true, new ApprovingObject(source, game));
game.getState().setValue("PlayFromNotOwnHandZone" + copiedCard.getId(), null);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public void testMosswortBridge() {
setChoice(playerA, "Ulamog, the Ceaseless Hunger");

activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{G},");
setChoice(playerA, true); // play Ghost Quarter
setChoice(playerA, "Ulamog, the Ceaseless Hunger"); // play Ulamog

addTarget(playerA, "Dross Crocodile^Dross Crocodile");

Expand Down Expand Up @@ -124,7 +124,7 @@ public void testCannotPlayLandIfPlayedLand() {
attack(3, playerA, "Auriok Champion");

activateAbility(3, PhaseStep.DECLARE_BLOCKERS, playerA, "{W},");
setChoice(playerA, true); // play Ghost Quarter
setChoice(playerA, "Ghost Quarter"); // play Ghost Quarter

setStopAt(3, PhaseStep.END_COMBAT);

Expand Down Expand Up @@ -155,7 +155,7 @@ public void testCannotPlayLandIfNotOwnTurn() {
setChoice(playerA, "Ghost Quarter");

activateAbility(4, PhaseStep.PRECOMBAT_MAIN, playerA, "{G},");
setChoice(playerA, true);
setChoice(playerA, "Ghost Quarter");

setStopAt(4, PhaseStep.BEGIN_COMBAT);

Expand All @@ -182,7 +182,7 @@ public void testCanPlayLandIfNotPlayedLand() {
attack(3, playerA, "Auriok Champion");

activateAbility(3, PhaseStep.DECLARE_BLOCKERS, playerA, "{W},");
setChoice(playerA, true); // play Ghost Quarter
setChoice(playerA, "Ghost Quarter"); // play Ghost Quarter

setStopAt(3, PhaseStep.END_COMBAT);

Expand Down Expand Up @@ -215,7 +215,7 @@ public void testCanPlayMoreLandsIfAble() {
attack(3, playerA, "Auriok Champion");

activateAbility(3, PhaseStep.DECLARE_BLOCKERS, playerA, "{W},");
setChoice(playerA, true); // play Ghost Quarter
setChoice(playerA, "Ghost Quarter"); // play Ghost Quarter

setStopAt(3, PhaseStep.END_COMBAT);

Expand Down Expand Up @@ -254,7 +254,7 @@ public void testShelldockIsleHideawayConditionOwnLibrary() {
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, sIsle);
setChoice(playerA, ulamog);
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}");
setChoice(playerA, true); // play Ulamog's Crusher
setChoice(playerA, ulamog); // play Ulamog's Crusher

setStopAt(3, PhaseStep.BEGIN_COMBAT);

Expand Down Expand Up @@ -298,7 +298,7 @@ public void testShelldockIsleHideawayConditionOpponentsLibrary() {
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, sIsle);
setChoice(playerA, ulamog);
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}");
setChoice(playerA, true); // play Ulamog's Crusher
setChoice(playerA, ulamog); // play Ulamog's Crusher

setStopAt(3, PhaseStep.BEGIN_COMBAT);
execute();
Expand All @@ -309,6 +309,115 @@ public void testShelldockIsleHideawayConditionOpponentsLibrary() {
assertPermanentCount(playerA, ulamog, 1);
}

/**
* Rule 607.3 - if Hideaway trigger is copied, "the exiled card" refers to each card exiled by Hideaway abilities.
*/
@Test
public void testMultipleHideawayTriggers() {
addCard(Zone.HAND, playerA, "Windbrisk Heights");
addCard(Zone.LIBRARY, playerA, "Llanowar Elves", 4);
addCard(Zone.LIBRARY, playerA, "Auriok Champion", 4);
skipInitShuffling();

addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerA, "Auriok Glaivemaster", 2);
addCard(Zone.BATTLEFIELD, playerA, "Elesh Norn, Mother of Machines");

playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Windbrisk Heights");
setChoice(playerA, "Hideaway 4"); // Order Hideaway triggers
setChoice(playerA, "Auriok Champion");
setChoice(playerA, "Llanowar Elves");

attack(3, playerA, "Auriok Glaivemaster");
attack(3, playerA, "Auriok Glaivemaster");
attack(3, playerA, "Elesh Norn, Mother of Machines");

activateAbility(3, PhaseStep.DECLARE_BLOCKERS, playerA, "{W},");
setChoice(playerA, "Llanowar Elves^Auriok Champion"); // play Llanowar Elves, then Auriok Champion (goes on stack second, resolves first)
setChoice(playerA, "Whenever"); // Order Auriok Champion's two gain life triggers thanks to Elesh Norn
setChoice(playerA, true); // Gain life
setChoice(playerA, true); // Gain life

setStopAt(3, PhaseStep.END_COMBAT);

setStrictChooseMode(true);
execute();

assertPermanentCount(playerA, "Llanowar Elves", 1);
assertPermanentCount(playerA, "Auriok Champion", 1);
assertLife(playerA, 22); // Gained a life from Auriok Champion resolving first.
assertTapped("Windbrisk Heights", true);
}

/**
* Hideaway two lands, attempt to play both exiled lands, only the first one succeeds.
*/
@Test
public void testMultipleHideawayTriggersPlayOneLand() {
addCard(Zone.HAND, playerA, "Windbrisk Heights");
addCard(Zone.LIBRARY, playerA, "Field of the Dead", 4);
addCard(Zone.LIBRARY, playerA, "Ghost Quarter", 4);
skipInitShuffling();

addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerA, "Auriok Champion", 3);
addCard(Zone.BATTLEFIELD, playerA, "Elesh Norn, Mother of Machines");

playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Windbrisk Heights");
setChoice(playerA, "Hideaway 4"); // Order Hideaway triggers
setChoice(playerA, "Ghost Quarter");
setChoice(playerA, "Field of the Dead");

attack(3, playerA, "Auriok Champion");
attack(3, playerA, "Auriok Champion");
attack(3, playerA, "Auriok Champion");

activateAbility(3, PhaseStep.DECLARE_BLOCKERS, playerA, "{W},");
setChoice(playerA, "Ghost Quarter^Field of the Dead"); // play Ghost Quarter, attempt to play Field of the Dead

setStopAt(3, PhaseStep.END_COMBAT);

setStrictChooseMode(true);
execute();

assertPermanentCount(playerA, "Ghost Quarter", 1);
assertTapped("Windbrisk Heights", true);
assertExileCount(playerA, 1);
Assert.assertEquals(1, playerA.getLandsPlayed());
}

@Test
public void testMultipleHideawayTriggersPlayMultipleLands() {
addCard(Zone.HAND, playerA, "Windbrisk Heights");
addCard(Zone.LIBRARY, playerA, "Ghost Quarter", 5);
skipInitShuffling();

addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.BATTLEFIELD, playerA, "Auriok Champion", 3);
addCard(Zone.BATTLEFIELD, playerA, "Elesh Norn, Mother of Machines");
addCard(Zone.BATTLEFIELD, playerA, "Fastbond", 1);

playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Windbrisk Heights");
setChoice(playerA, "Hideaway 4"); // Order Hideaway triggers
setChoice(playerA, "Ghost Quarter", 2);

attack(3, playerA, "Auriok Champion");
attack(3, playerA, "Auriok Champion");
attack(3, playerA, "Auriok Champion");

activateAbility(3, PhaseStep.DECLARE_BLOCKERS, playerA, "{W},");
setChoice(playerA, "Ghost Quarter^Ghost Quarter"); // play Ghost Quarter

setStopAt(3, PhaseStep.END_COMBAT);

setStrictChooseMode(true);
execute();

assertPermanentCount(playerA, "Ghost Quarter", 2);
assertTapped("Windbrisk Heights", true);
Assert.assertEquals(2, playerA.getLandsPlayed());
}

/**
* Watcher for tomorrow - Watcher of Tomorrow not working when been blinked
* by any source, like Ephemerate or Soulherder, still working if dies
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,27 @@
*/
public class HideawayPlayEffect extends OneShotEffect {

private final boolean playOne;

public HideawayPlayEffect() {
super(Outcome.Benefit);
this.playOne = false;
staticText = "you may play the exiled card without paying its mana cost";
}

public HideawayPlayEffect(boolean playOne) {
super(Outcome.Benefit);
this.playOne = playOne;
if (playOne) {
staticText = "if there are cards exiled with it, you may play one of them without paying its mana cost";
} else {
staticText = "you may play the exiled card without paying its mana cost";
}
}

protected HideawayPlayEffect(final HideawayPlayEffect effect) {
super(effect);
this.playOne = effect.playOne;
}

@Override
Expand All @@ -46,7 +60,8 @@ public boolean apply(Game game, Ability source) {
CardsImpl cards = new CardsImpl(zone.getCards(game));

boolean cardPlayed = false;
TargetCard target = new TargetCard(0, cards.size(), Zone.EXILED, new FilterCard("cards to play"));
int maxChoices = (this.playOne) ? 1 : cards.size();
TargetCard target = new TargetCard(0, maxChoices, Zone.EXILED, new FilterCard("cards to play (in order they're chosen)"));
controller.choose(Outcome.PlayForFree, cards, target, source, game);
List<UUID> targets = target.getTargets();

Expand All @@ -64,9 +79,6 @@ public boolean apply(Game game, Ability source) {
}
}

if (!controller.chooseUse(Outcome.PlayForFree, "Play " + card.getIdName() + " for free?", source, game)) {
continue;
}
card.setFaceDown(false, game);
int zcc = card.getZoneChangeCounter(game);

Expand Down

0 comments on commit 811e5ba

Please sign in to comment.