diff --git a/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java b/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java index 43bafd5abc1..d7b330c09bb 100644 --- a/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java +++ b/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java @@ -1,9 +1,5 @@ - package mage.cards.b; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; import mage.MageInt; import mage.MageObject; import mage.abilities.Ability; @@ -13,44 +9,46 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ReturnToHandTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterCard; +import mage.filter.StaticFilters; import mage.game.ExileZone; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; -import mage.target.Target; +import mage.target.TargetCard; import mage.target.common.TargetCardInExile; import mage.target.common.TargetCardInHand; import mage.util.CardUtil; +import java.util.UUID; + /** * Gatecrash FAQ (01.2013) - * + *

* If Bane Alley Broker's first ability resolves when you have no cards in your * hand, you'll draw a card and then exile it. You won't have the opportunity to * cast that card (or do anything else with it) before exiling it. - * + *

* Due to a recent rules change, once you are allowed to look at a face-down * card in exile, you are allowed to look at that card as long as it's exiled. * If you no longer control Bane Alley Broker when its last ability resolves, * you can continue to look at the relevant cards in exile to choose one to * return. - * + *

* Bane Alley Broker's second and third abilities apply to cards exiled with * that specific Bane Alley Broker, not any other creature named Bane Alley * Broker. You should keep cards exiled by different Bane Alley Brokers * separate. - * + *

* If Bane Alley Broker leaves the battlefield, the cards exiled with it will be * exiled indefinitely. If it later returns to the battlefield, it will be a new * object with no connection to the cards exiled with it in its previous * existence. You won't be able to use the "new" Bane Alley Broker to return * cards exiled with the "old" one. - * + *

* Even if not all players can look at the exiled cards, each card's owner is * still known. It is advisable to keep cards owned by different players in * distinct piles in case another player gains control of Bane Alley Broker and @@ -61,24 +59,22 @@ import mage.util.CardUtil; public final class BaneAlleyBroker extends CardImpl { public BaneAlleyBroker(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}"); this.subtype.add(SubType.HUMAN, SubType.ROGUE); this.power = new MageInt(0); this.toughness = new MageInt(3); // {tap}: Draw a card, then exile a card from your hand face down. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BaneAlleyBrokerDrawExileEffect(), new TapSourceCost())); + this.addAbility(new SimpleActivatedAbility(new BaneAlleyBrokerDrawExileEffect(), new TapSourceCost())); // You may look at cards exiled with Bane Alley Broker. - this.addAbility(new SimpleStaticAbility(Zone.ALL, new BaneAlleyBrokerLookAtCardEffect())); + this.addAbility(new SimpleStaticAbility(new BaneAlleyBrokerLookAtCardEffect())); // {U}{B}, {tap}: Return a card exiled with Bane Alley Broker to its owner's hand. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ReturnToHandTargetEffect(), new ManaCostsImpl("{U}{B}")); + Ability ability = new SimpleActivatedAbility(new BaneAlleyBrokerReturnToHandEffect(), new ManaCostsImpl("{U}{B}")); ability.addCost(new TapSourceCost()); - ability.addTarget(new TargetCardInBaneAlleyBrokerExile(this.getId())); this.addAbility(ability); - } private BaneAlleyBroker(final BaneAlleyBroker card) { @@ -93,33 +89,37 @@ public final class BaneAlleyBroker extends CardImpl { class BaneAlleyBrokerDrawExileEffect extends OneShotEffect { - public BaneAlleyBrokerDrawExileEffect() { + BaneAlleyBrokerDrawExileEffect() { super(Outcome.DrawCard); staticText = "Draw a card, then exile a card from your hand face down"; } - public BaneAlleyBrokerDrawExileEffect(final BaneAlleyBrokerDrawExileEffect effect) { + private BaneAlleyBrokerDrawExileEffect(final BaneAlleyBrokerDrawExileEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.drawCards(1, source, game); - Target target = new TargetCardInHand(new FilterCard("card to exile")); - if (controller.chooseTarget(outcome, target, source, game)) { - Card card = game.getCard(target.getFirstTarget()); - MageObject sourceObject = game.getObject(source.getSourceId()); - if (card != null && sourceObject != null) { - if (card.moveToExile(CardUtil.getCardExileZoneId(game, source), sourceObject.getName(), source, game)) { - card.setFaceDown(true, game); - return true; - } - } - } + if (controller == null) { + return false; } - return false; + controller.drawCards(1, source, game); + if (controller.getHand().isEmpty()) { + return false; + } + TargetCard target = new TargetCardInHand().withChooseHint("to exile"); + controller.chooseTarget(outcome, controller.getHand(), target, source, game); + Card card = game.getCard(target.getFirstTarget()); + MageObject sourceObject = source.getSourcePermanentOrLKI(game); + if (card == null || sourceObject == null) { + return false; + } + if (!card.moveToExile(CardUtil.getExileZoneId(game, source), sourceObject.getName(), source, game)) { + return false; + } + card.setFaceDown(true, game); + return true; } @Override @@ -128,74 +128,52 @@ class BaneAlleyBrokerDrawExileEffect extends OneShotEffect { } } -class TargetCardInBaneAlleyBrokerExile extends TargetCardInExile { +class BaneAlleyBrokerReturnToHandEffect extends OneShotEffect { - public TargetCardInBaneAlleyBrokerExile(UUID cardId) { - super(1, 1, new FilterCard("card exiled with Bane Alley Broker"), null); + BaneAlleyBrokerReturnToHandEffect() { + super(Outcome.Benefit); + staticText = "return a card exiled with {this} to its owner's hand"; } - public TargetCardInBaneAlleyBrokerExile(final TargetCardInBaneAlleyBrokerExile target) { - super(target); + private BaneAlleyBrokerReturnToHandEffect(final BaneAlleyBrokerReturnToHandEffect effect) { + super(effect); } @Override - public Set possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) { - Set possibleTargets = new HashSet<>(); - Card sourceCard = game.getCard(sourceId); - if (sourceCard != null) { - UUID exileId = CardUtil.getCardExileZoneId(game, sourceId); - ExileZone exile = game.getExile().getExileZone(exileId); - if (exile != null && !exile.isEmpty()) { - possibleTargets.addAll(exile); - } + public BaneAlleyBrokerReturnToHandEffect copy() { + return new BaneAlleyBrokerReturnToHandEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + Permanent permanent = source.getSourcePermanentOrLKI(game); + if (player == null || permanent == null) { + return false; } - return possibleTargets; - } - - @Override - public boolean canChoose(UUID sourceId, UUID sourceControllerId, Game game) { - Card sourceCard = game.getCard(sourceId); - if (sourceCard != null) { - UUID exileId = CardUtil.getCardExileZoneId(game, sourceId); - ExileZone exile = game.getExile().getExileZone(exileId); - if (exile != null && !exile.isEmpty()) { - return true; - } + ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + if (exile == null || exile.isEmpty()) { + return false; } - return false; - } - - @Override - public boolean canTarget(UUID id, Ability source, Game game) { - Card card = game.getCard(id); - if (card != null && game.getState().getZone(card.getId()) == Zone.EXILED) { - ExileZone exile = null; - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null) { - UUID exileId = CardUtil.getCardExileZoneId(game, source); - exile = game.getExile().getExileZone(exileId); - } - if (exile != null && exile.contains(id)) { - return filter.match(card, source.getControllerId(), game); - } + TargetCardInExile target = new TargetCardInExile(StaticFilters.FILTER_CARD, exile.getId()); + target.setNotTarget(true); + player.chooseTarget(outcome, exile,target, source, game); + Card card = game.getCard(target.getFirstTarget()); + if (card == null) { + return false; } - return false; - } - - @Override - public TargetCardInBaneAlleyBrokerExile copy() { - return new TargetCardInBaneAlleyBrokerExile(this); + return card != null && player.moveCards(card, Zone.HAND, source, game); } } class BaneAlleyBrokerLookAtCardEffect extends AsThoughEffectImpl { - public BaneAlleyBrokerLookAtCardEffect() { + BaneAlleyBrokerLookAtCardEffect() { super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.Benefit); staticText = "You may look at cards exiled with {this}"; } - public BaneAlleyBrokerLookAtCardEffect(final BaneAlleyBrokerLookAtCardEffect effect) { + private BaneAlleyBrokerLookAtCardEffect(final BaneAlleyBrokerLookAtCardEffect effect) { super(effect); } @@ -211,19 +189,12 @@ class BaneAlleyBrokerLookAtCardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getControllerId())) { - Card card = game.getCard(objectId); - if (card != null) { - MageObject sourceObject = game.getObject(source.getSourceId()); - if (sourceObject == null) { - return false; - } - UUID exileId = CardUtil.getCardExileZoneId(game, source); - ExileZone exile = game.getExile().getExileZone(exileId); - return exile != null && exile.contains(objectId); - } + if (!source.isControlledBy(affectedControllerId)) { + return false; } - return false; + Card card = game.getCard(objectId); + ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); + return card != null && exile != null && exile.getCards(game).contains(card); } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/BaneAlleyBrokerTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/BaneAlleyBrokerTest.java index d8f254f899e..d02e0584609 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/facedown/BaneAlleyBrokerTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/facedown/BaneAlleyBrokerTest.java @@ -17,7 +17,6 @@ public class BaneAlleyBrokerTest extends CardTestPlayerBase { * then exile a card from your hand face down. You may look at cards exiled * with Bane Alley Broker. {U}{B}, {T}: Return a card exiled with Bane Alley * Broker to its owner's hand. - * */ // test that cards exiled using Bane Alley Broker are face down @Test @@ -28,11 +27,13 @@ public class BaneAlleyBrokerTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Island"); addCard(Zone.BATTLEFIELD, playerA, "Swamp"); - activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Draw a card, then exile a card from your hand face down."); + setStrictChooseMode(true); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}"); addTarget(playerA, "Goblin Roughrider"); setStopAt(1, PhaseStep.BEGIN_COMBAT); execute(); + assertAllCommandsUsed(); assertHandCount(playerA, 2); assertHandCount(playerA, "Sejiri Merfolk", 1); @@ -45,7 +46,32 @@ public class BaneAlleyBrokerTest extends CardTestPlayerBase { Assert.assertTrue("Exiled card is not face down", card.isFaceDown(currentGame)); } } + } + @Test + public void testBaneAlleyBrokerReturn() { + addCard(Zone.BATTLEFIELD, playerA, "Bane Alley Broker"); + addCard(Zone.HAND, playerA, "Goblin Roughrider"); + addCard(Zone.HAND, playerA, "Sejiri Merfolk"); + addCard(Zone.BATTLEFIELD, playerA, "Island"); + addCard(Zone.BATTLEFIELD, playerA, "Swamp"); + + setStrictChooseMode(true); + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}"); + addTarget(playerA, "Goblin Roughrider"); + + activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "{U}{B}"); + addTarget(playerA, "Goblin Roughrider"); + + setStopAt(3, PhaseStep.BEGIN_COMBAT); + execute(); + assertAllCommandsUsed(); + + assertHandCount(playerA, 4); + assertHandCount(playerA, "Sejiri Merfolk", 1); + assertHandCount(playerA, "Goblin Roughrider", 1); + + assertExileCount("Goblin Roughrider", 0); } } diff --git a/Mage/src/main/java/mage/util/CardUtil.java b/Mage/src/main/java/mage/util/CardUtil.java index 4c90db152d7..946d519edd9 100644 --- a/Mage/src/main/java/mage/util/CardUtil.java +++ b/Mage/src/main/java/mage/util/CardUtil.java @@ -586,6 +586,10 @@ public final class CardUtil { return getExileZoneId(getCardZoneString(SOURCE_EXILE_ZONE_TEXT, sourceId, game, previous), game); } + public static UUID getExileZoneId(Game game, Ability source) { + return getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); + } + public static UUID getExileZoneId(Game game, UUID objectId, int zoneChangeCounter) { return getExileZoneId(getObjectZoneString(SOURCE_EXILE_ZONE_TEXT, objectId, game, zoneChangeCounter, false), game); }