mirror of
https://github.com/correl/mage.git
synced 2024-11-15 03:00:16 +00:00
[GTC] updated implementation of Bane Alley Broker
This commit is contained in:
parent
22ac79c325
commit
a8bda04daf
3 changed files with 99 additions and 98 deletions
|
@ -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
|
||||
|
@ -68,17 +66,15 @@ public final class BaneAlleyBroker extends CardImpl {
|
|||
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,34 +89,38 @@ 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) {
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
controller.drawCards(1, source, game);
|
||||
Target target = new TargetCardInHand(new FilterCard("card to exile"));
|
||||
if (controller.chooseTarget(outcome, target, 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 = game.getObject(source.getSourceId());
|
||||
if (card != null && sourceObject != null) {
|
||||
if (card.moveToExile(CardUtil.getCardExileZoneId(game, source), sourceObject.getName(), source, game)) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaneAlleyBrokerDrawExileEffect copy() {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
return possibleTargets;
|
||||
public BaneAlleyBrokerReturnToHandEffect copy() {
|
||||
return new BaneAlleyBrokerReturnToHandEffect(this);
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
}
|
||||
ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source));
|
||||
if (exile == null || exile.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TargetCardInBaneAlleyBrokerExile copy() {
|
||||
return new TargetCardInBaneAlleyBrokerExile(this);
|
||||
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 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())) {
|
||||
if (!source.isControlledBy(affectedControllerId)) {
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source));
|
||||
return card != null && exile != null && exile.getCards(game).contains(card);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue