[GTC] updated implementation of Bane Alley Broker

This commit is contained in:
Evan Kranzler 2021-02-19 14:47:47 -05:00
parent 22ac79c325
commit a8bda04daf
3 changed files with 99 additions and 98 deletions

View file

@ -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)
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* 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.
*
* <p>
* 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<UUID> possibleTargets(UUID sourceId, UUID sourceControllerId, Game game) {
Set<UUID> 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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}