From 6a7b2e80ac90d5d67012c32551d7be41b6156319 Mon Sep 17 00:00:00 2001 From: Alex Vasile <48962821+Alex-Vasile@users.noreply.github.com> Date: Tue, 15 Mar 2022 17:57:16 -0400 Subject: [PATCH] Refactoring + Fix of several cards (#8699) * Simplified Azorius Aethermage * - Flattened the if statements - Renamed the custom effects and abilities to be more readable - Changed certain functiosn to be private * Flatten Thieves Auction * Flatten Possibility Storm * Flatten Aminatous Augury * Minor refactoring * Flattening and adjusting access modifiers * Aetherspouts should have been using getPlayersInRange. Current implementation was affecting all players * Simplified Akoum Hellkite * Simplified Ali From Cairo * Flattened An-Havva Constable * Flattened Aura Finesse and Autum Willow * Fixed All Hallow's Eve since it didn't work. * Several small simplifications * Flattening/Simplification of several classes * Added test for Azorius Aethermage * Added test for Abandoned Sarcophagus * Updated test with docstring instead of comment * Update AzoriusAethermageTest.java * Update BattlegateMimic.java * Update AetherworksMarvel.java * Update AetherworksMarvel.java * Update AzoriusAethermageTest.java * Update AzoriusAethermageTest.java Co-authored-by: Jeff Wadsworth --- Mage.Sets/src/mage/cards/a/AbandonReason.java | 2 +- .../mage/cards/a/AbandonedSarcophagus.java | 96 +++++--- .../src/mage/cards/a/ActOfAuthority.java | 43 ++-- .../src/mage/cards/a/AdarkarValkyrie.java | 30 +-- .../src/mage/cards/a/AdmiralBeckettBrass.java | 2 +- .../src/mage/cards/a/AerialSurveyor.java | 2 +- Mage.Sets/src/mage/cards/a/Aetherspouts.java | 198 +++++++-------- .../src/mage/cards/a/AgelessSentinels.java | 56 ++--- Mage.Sets/src/mage/cards/a/AkoumHellkite.java | 56 ++--- Mage.Sets/src/mage/cards/a/AkroanHorse.java | 24 +- .../mage/cards/a/AkromaVisionOfIxidor.java | 2 +- Mage.Sets/src/mage/cards/a/AliFromCairo.java | 31 ++- .../mage/cards/a/AlignedHedronNetwork.java | 24 +- Mage.Sets/src/mage/cards/a/AllHallowsEve.java | 49 ++-- .../src/mage/cards/a/AltarOfTheLost.java | 4 +- .../src/mage/cards/a/AminatousAugury.java | 156 ++++++------ .../src/mage/cards/a/AnHavvaConstable.java | 23 +- .../src/mage/cards/a/ArcaneAdaptation.java | 3 +- .../src/mage/cards/a/AtemsisAllSeeing.java | 5 +- Mage.Sets/src/mage/cards/a/AuraFinesse.java | 34 +-- .../src/mage/cards/a/AuriokEdgewright.java | 2 +- Mage.Sets/src/mage/cards/a/AutumnWillow.java | 13 +- Mage.Sets/src/mage/cards/a/AvatarOfWoe.java | 5 +- .../src/mage/cards/a/AzoriusAethermage.java | 61 ++--- Mage.Sets/src/mage/cards/a/AzorsGateway.java | 56 +++-- .../src/mage/cards/b/BaneAlleyBroker.java | 2 +- Mage.Sets/src/mage/cards/b/Banefire.java | 29 +-- Mage.Sets/src/mage/cards/b/BanthaHerd.java | 10 +- Mage.Sets/src/mage/cards/b/BatheInLight.java | 71 +++--- .../mage/cards/b/BattlefieldThaumaturge.java | 4 +- .../src/mage/cards/b/BehemothSledge.java | 4 +- Mage.Sets/src/mage/cards/b/BendOrBreak.java | 227 +++++++++--------- .../src/mage/cards/b/BenevolentOffering.java | 51 ++-- .../src/mage/cards/b/BenthicExplorers.java | 87 +++---- Mage.Sets/src/mage/cards/b/Berserk.java | 38 +-- .../src/mage/cards/b/BiomanticMastery.java | 20 +- Mage.Sets/src/mage/cards/b/BitterFeud.java | 118 ++++----- .../src/mage/cards/b/BlasphemousAct.java | 12 +- Mage.Sets/src/mage/cards/b/BlazingEffigy.java | 19 +- .../src/mage/cards/b/BlinkmothInfusion.java | 13 +- .../src/mage/cards/b/BloodBaronOfVizkopa.java | 69 +++--- .../src/mage/cards/b/BloodlineShaman.java | 41 ++-- Mage.Sets/src/mage/cards/b/Blustersquall.java | 11 +- .../src/mage/cards/b/BoneyardScourge.java | 13 +- .../src/mage/cards/b/BoonweaverGiant.java | 26 +- Mage.Sets/src/mage/cards/b/BosiumStrip.java | 36 +-- .../src/mage/cards/b/BountyOfTheLuxa.java | 44 ++-- .../src/mage/cards/b/BraceForImpact.java | 29 ++- .../src/mage/cards/b/BridgeFromBelow.java | 16 +- Mage.Sets/src/mage/cards/b/Brightflame.java | 28 +-- .../src/mage/cards/b/BrimazKingOfOreskos.java | 47 ++-- Mage.Sets/src/mage/cards/b/BrineHag.java | 35 +-- .../src/mage/cards/b/BroodhatchNantuko.java | 16 +- .../src/mage/cards/b/BroodmateDragon.java | 2 +- .../mage/cards/b/BrunaLightOfAlabaster.java | 86 +++---- .../src/mage/cards/b/BudokaGardener.java | 11 +- Mage.Sets/src/mage/cards/b/BullElephant.java | 10 +- .../src/mage/cards/b/BurnFromWithin.java | 45 ++-- .../BurningCinderFuryOfCrimsonChaosFire.java | 2 +- .../src/mage/cards/b/BurningOfXinye.java | 18 +- Mage.Sets/src/mage/cards/k/KnowledgePool.java | 151 ++++++------ .../src/mage/cards/p/PossibilityStorm.java | 80 +++--- .../src/mage/cards/t/ThievesAuction.java | 69 +++--- .../single/dis/AzoriusAethermageTest.java | 54 +++++ .../single/hou/AbandonedSarcophagusTest.java | 108 +++++++++ 65 files changed, 1471 insertions(+), 1258 deletions(-) create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/dis/AzoriusAethermageTest.java create mode 100644 Mage.Tests/src/test/java/org/mage/test/cards/single/hou/AbandonedSarcophagusTest.java diff --git a/Mage.Sets/src/mage/cards/a/AbandonReason.java b/Mage.Sets/src/mage/cards/a/AbandonReason.java index 63e6f1bd47..21247f12db 100644 --- a/Mage.Sets/src/mage/cards/a/AbandonReason.java +++ b/Mage.Sets/src/mage/cards/a/AbandonReason.java @@ -34,7 +34,7 @@ public final class AbandonReason extends CardImpl { this.getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2)); // Madness {1}{R} - this.addAbility(new MadnessAbility(this, new ManaCostsImpl("{1}{R}"))); + this.addAbility(new MadnessAbility(this, new ManaCostsImpl<>("{1}{R}"))); } private AbandonReason(final AbandonReason card) { diff --git a/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java b/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java index fc4253b964..1c1bb693c2 100644 --- a/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java +++ b/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java @@ -3,6 +3,7 @@ package mage.cards.a; import java.util.HashMap; import java.util.Map; import java.util.UUID; + import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; @@ -25,13 +26,17 @@ import mage.watchers.Watcher; */ public final class AbandonedSarcophagus extends CardImpl { + private static final FilterCard filter = new FilterCard("nonland cards with cycling"); + + static { + filter.add(Predicates.not(CardType.LAND.getPredicate())); + filter.add(new AbilityPredicate(CyclingAbility.class)); + } + public AbandonedSarcophagus(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // You may cast nonland cards with cycling from your graveyard. - FilterCard filter = new FilterCard("nonland cards with cycling"); - filter.add(Predicates.not(CardType.LAND.getPredicate())); - filter.add(new AbilityPredicate(CyclingAbility.class)); this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayFromNotOwnHandZoneAllEffect(filter, Zone.GRAVEYARD, true, TargetController.YOU, Duration.WhileOnBattlefield) @@ -77,16 +82,20 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null) { - return controller.moveCards(permanent, Zone.EXILED, source, game); - } - Card card = game.getCard(event.getTargetId()); - if (card != null) { - return controller.moveCards(card, Zone.EXILED, source, game); - } + if (controller == null) { + return false; } + + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent != null) { + return controller.moveCards(permanent, Zone.EXILED, source, game); + } + + Card card = game.getCard(event.getTargetId()); + if (card != null) { + return controller.moveCards(card, Zone.EXILED, source, game); + } + return false; } @@ -97,32 +106,46 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - boolean cardWasCycledThisTurn = false; - boolean cardHasCycling = false; if (!(((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD)) { return false; } + Player controller = game.getPlayer(source.getControllerId()); - AbandonedSarcophagusWatcher watcher = game.getState().getWatcher(AbandonedSarcophagusWatcher.class); - Card card = game.getCard(event.getTargetId()); - if (card == null - || controller == null - || watcher == null - || !card.isOwnedBy(controller.getId())) { + if (controller == null) { return false; } + + Card card = game.getCard(event.getTargetId()); + if (card == null) { + return false; + } + if (!card.isOwnedBy(controller.getId())) { + return false; + } + + AbandonedSarcophagusWatcher watcher = game.getState().getWatcher(AbandonedSarcophagusWatcher.class); + if (watcher == null) { + return false; + } + + boolean cardHasCycling = false; for (Ability ability : card.getAbilities(game)) { if (ability instanceof CyclingAbility) { cardHasCycling = true; + break; } } + Cards cards = watcher.getCardsCycledThisTurn(controller.getId()); - for (Card c : cards.getCards(game)) { - if (c == card) { + boolean cardWasCycledThisTurn = false; + + for (Card cardCycledThisTurn : cards.getCards(game)) { + if (cardCycledThisTurn == card) { cardWasCycledThisTurn = true; watcher.getCardsCycledThisTurn(controller.getId()).remove(card); //remove reference to the card as it is no longer needed } } + return !cardWasCycledThisTurn && cardHasCycling; } } @@ -137,17 +160,26 @@ class AbandonedSarcophagusWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.CYCLE_CARD) { - Card card = game.getCard(event.getSourceId()); - Player controller = game.getPlayer(event.getPlayerId()); - if (card != null - && controller != null - && card.isOwnedBy(controller.getId())) { - Cards c = getCardsCycledThisTurn(event.getPlayerId()); - c.add(card); - cycledCardsThisTurn.put(event.getPlayerId(), c); - } + if (event.getType() != GameEvent.EventType.CYCLE_CARD) { + return; } + + Card card = game.getCard(event.getSourceId()); + if (card == null) { + return; + } + + Player controller = game.getPlayer(event.getPlayerId()); + if (controller == null) { + return; + } + if (!card.isOwnedBy(controller.getId())) { + return; + } + + Cards c = getCardsCycledThisTurn(event.getPlayerId()); + c.add(card); + cycledCardsThisTurn.put(event.getPlayerId(), c); } public Cards getCardsCycledThisTurn(UUID playerId) { diff --git a/Mage.Sets/src/mage/cards/a/ActOfAuthority.java b/Mage.Sets/src/mage/cards/a/ActOfAuthority.java index 0001376bc5..d288540ba9 100644 --- a/Mage.Sets/src/mage/cards/a/ActOfAuthority.java +++ b/Mage.Sets/src/mage/cards/a/ActOfAuthority.java @@ -54,7 +54,7 @@ class ActOfAuthorityEffect extends OneShotEffect { this.staticText = "you may exile target artifact or enchantment. If you do, its controller gains control of {this}"; } - public ActOfAuthorityEffect(final ActOfAuthorityEffect effect) { + private ActOfAuthorityEffect(final ActOfAuthorityEffect effect) { super(effect); } @@ -66,29 +66,32 @@ class ActOfAuthorityEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent targetPermanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (targetPermanent != null && new ExileTargetEffect().apply(game, source)) { - Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); - if (sourcePermanent != null) { - ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId()); - effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); - game.addEffect(effect, source); - } - return true; - } - return false; + if (targetPermanent == null) { return false; } + + ExileTargetEffect exileTargetEffect = new ExileTargetEffect(); + if (!exileTargetEffect.apply(game, source)) { return false; } + + Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game); + if (sourcePermanent == null) { return true; } + + ContinuousEffect effect = new ActOfAuthorityGainControlEffect(Duration.Custom, targetPermanent.getControllerId()); + effect.setTargetPointer(new FixedTarget(sourcePermanent, game)); + game.addEffect(effect, source); + return true; } } +// TODO: These and it's duplicates can probably be replaced by a gain control of effect class ActOfAuthorityGainControlEffect extends ContinuousEffectImpl { - UUID controller; + private final UUID controller; public ActOfAuthorityGainControlEffect(Duration duration, UUID controller) { super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); this.controller = controller; } - public ActOfAuthorityGainControlEffect(final ActOfAuthorityGainControlEffect effect) { + private ActOfAuthorityGainControlEffect(final ActOfAuthorityGainControlEffect effect) { super(effect); this.controller = effect.controller; } @@ -100,14 +103,16 @@ class ActOfAuthorityGainControlEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (targetPointer != null) { + Permanent permanent; + if (targetPointer == null) { + permanent = game.getPermanent(source.getFirstTarget()); + } else { permanent = game.getPermanent(targetPointer.getFirst(game, source)); } - if (permanent != null) { - return permanent.changeControllerId(controller, game, source); - } - return false; + + if (permanent == null) { return false; } + + return permanent.changeControllerId(controller, game, source); } @Override diff --git a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java index beded6f827..b7efc2fde8 100644 --- a/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java +++ b/Mage.Sets/src/mage/cards/a/AdarkarValkyrie.java @@ -84,18 +84,17 @@ class AdarkarValkyrieEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null) { - DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new MageObjectReference(permanent, game)); - game.addDelayedTriggeredAbility(delayedAbility, source); - return true; - } - return false; + if (permanent == null) { return false; } + + DelayedTriggeredAbility delayedAbility = new AdarkarValkyrieDelayedTriggeredAbility(new MageObjectReference(permanent, game)); + game.addDelayedTriggeredAbility(delayedAbility, source); + return true; } } class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility { - protected MageObjectReference mor; + private final MageObjectReference mor; public AdarkarValkyrieDelayedTriggeredAbility(MageObjectReference mor) { super(new ReturnToBattlefieldUnderYourControlTargetEffect(), Duration.EndOfTurn); @@ -119,14 +118,17 @@ class AdarkarValkyrieDelayedTriggeredAbility extends DelayedTriggeredAbility { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (((ZoneChangeEvent) event).isDiesEvent() - && mor.refersTo(((ZoneChangeEvent) event).getTarget(), game) - && game.getState().getZone(event.getTargetId()) == Zone.GRAVEYARD) { // must be in the graveyard - getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); - return true; + if (!((ZoneChangeEvent) event).isDiesEvent()) { return false; } - } - return false; + if (!mor.refersTo(((ZoneChangeEvent) event).getTarget(), game)) { return false; } + + // TODO: Must it? Why? + // Must be in the graveyard + if (game.getState().getZone(event.getTargetId()) != Zone.GRAVEYARD) { return false; } + + getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); + + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java b/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java index f2f120e694..0cc9aac12e 100644 --- a/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java +++ b/Mage.Sets/src/mage/cards/a/AdmiralBeckettBrass.java @@ -91,7 +91,7 @@ class DamagedByPiratesWatcher extends Watcher { } public boolean damagedByEnoughPirates(UUID sourceId) { - return damageSourceIds.keySet().contains(sourceId) && damageSourceIds.get(sourceId).size() > 2; + return damageSourceIds.containsKey(sourceId) && damageSourceIds.get(sourceId).size() > 2; } @Override diff --git a/Mage.Sets/src/mage/cards/a/AerialSurveyor.java b/Mage.Sets/src/mage/cards/a/AerialSurveyor.java index 6e66cb5d67..34b53bc318 100644 --- a/Mage.Sets/src/mage/cards/a/AerialSurveyor.java +++ b/Mage.Sets/src/mage/cards/a/AerialSurveyor.java @@ -110,6 +110,6 @@ enum AerialSurveyorHint implements Hint { @Override public AerialSurveyorHint copy() { - return this; + return instance; } } diff --git a/Mage.Sets/src/mage/cards/a/Aetherspouts.java b/Mage.Sets/src/mage/cards/a/Aetherspouts.java index 6d8a9d0941..db3a7e1120 100644 --- a/Mage.Sets/src/mage/cards/a/Aetherspouts.java +++ b/Mage.Sets/src/mage/cards/a/Aetherspouts.java @@ -44,11 +44,13 @@ public final class Aetherspouts extends CardImpl { /* 7/18/2014 The owner of each attacking creature chooses whether to put it on the top or bottom - of their library. The active player (the player whose turn it is) makes all of - their choices first, followed by each other player in turn order. + of their library. + The active player (the player whose turn it is) makes all of their choices first, + followed by each other player in turn order. + 7/18/2014 If an effect puts two or more cards on the top or bottom of a library at the same time, - the owner of those cards may arrange them in any order. That library's owner doesn't reveal - the order in which the cards go into their library. + the owner of those cards may arrange them in any order. + That library's owner doesn't reveal the order in which the cards go into their library. */ class AetherspoutsEffect extends OneShotEffect { @@ -57,7 +59,7 @@ class AetherspoutsEffect extends OneShotEffect { this.staticText = "For each attacking creature, its owner puts it on the top or bottom of their library"; } - public AetherspoutsEffect(final AetherspoutsEffect effect) { + private AetherspoutsEffect(final AetherspoutsEffect effect) { super(effect); } @@ -70,107 +72,107 @@ class AetherspoutsEffect extends OneShotEffect { public boolean apply(Game game, Ability source) { game.getPlayerList(); Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - PlayerList playerList = game.getPlayerList().copy(); - playerList.setCurrent(game.getActivePlayerId()); - Player player = game.getPlayer(game.getActivePlayerId()); - Player activePlayer = player; - do { - List permanentsToTop = new ArrayList<>(); - List permanentsToBottom = new ArrayList<>(); - for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source.getSourceId(), game)) { - if (permanent.isOwnedBy(player.getId())) { - if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", source, game)) { - permanentsToTop.add(permanent); - game.informPlayers(permanent.getLogName() + " goes to the top of " + player.getLogName() + "'s library"); - } else { - permanentsToBottom.add(permanent); - game.informPlayers(permanent.getLogName() + " goes to the bottom of " + player.getLogName() + "'s library"); - } - } - } - // cards to top - Cards cards = new CardsImpl(); - List toLibrary = new ArrayList<>(); - for (Permanent permanent : permanentsToTop) { - if (permanent instanceof PermanentToken) { - toLibrary.add(permanent); - } else { - Card card = game.getCard(permanent.getId()); - if (card != null) { - cards.add(card); - } - } - } - TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on the top of library (last choosen will be the top most)")); - while (cards.size() > 1) { - if (!player.canRespond()) { - return false; - } - player.choose(Outcome.Neutral, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - toLibrary.add(permanent); - } - } - target.clearChosen(); - } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - toLibrary.add(permanent); - } - } - // move all permanents to lib at the same time - for (Permanent permanent : toLibrary) { - player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, true, false); - } - // cards to bottom - cards.clear(); - toLibrary.clear(); - for (Permanent permanent : permanentsToBottom) { - if (permanent instanceof PermanentToken) { - toLibrary.add(permanent); - } else { - Card card = game.getCard(permanent.getId()); - if (card != null) { - cards.add(card); - } - } - } - target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on bottom of library (last choosen will be bottommost card)")); - while (player.canRespond() && cards.size() > 1) { - player.choose(Outcome.Neutral, cards, target, game); + if (controller == null) { return false; } - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - Permanent permanent = game.getPermanent(card.getId()); - if (permanent != null) { - toLibrary.add(permanent); - } + PlayerList playerList = game.getState().getPlayersInRange(controller.getId(), game); + playerList.setCurrent(game.getActivePlayerId()); + Player player = game.getPlayer(game.getActivePlayerId()); + Player activePlayer = player; + do { + List permanentsToTop = new ArrayList<>(); + List permanentsToBottom = new ArrayList<>(); + for (Permanent permanent : game.getState().getBattlefield().getActivePermanents(new FilterAttackingCreature(), player.getId(), source.getSourceId(), game)) { + if (permanent.isOwnedBy(player.getId())) { + if (player.chooseUse(outcome, "Put " + permanent.getLogName() + " to the top? (else it goes to bottom)", source, game)) { + permanentsToTop.add(permanent); + game.informPlayers(permanent.getLogName() + " goes to the top of " + player.getLogName() + "'s library"); + } else { + permanentsToBottom.add(permanent); + game.informPlayers(permanent.getLogName() + " goes to the bottom of " + player.getLogName() + "'s library"); } - target.clearChosen(); } - if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); + } + // cards to top + Cards cards = new CardsImpl(); + List toLibrary = new ArrayList<>(); + for (Permanent permanent : permanentsToTop) { + if (permanent instanceof PermanentToken) { + toLibrary.add(permanent); + } else { + Card card = game.getCard(permanent.getId()); + if (card != null) { + cards.add(card); + } + } + } + TargetCard target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on the top of library (last choosen will be the top most)")); + while (cards.size() > 1) { + if (!player.canRespond()) { + return false; + } + player.choose(Outcome.Neutral, cards, target, game); + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); Permanent permanent = game.getPermanent(card.getId()); if (permanent != null) { toLibrary.add(permanent); } } - // move all permanents to lib at the same time - for (Permanent permanent : toLibrary) { - player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, false, false); + target.clearChosen(); + } + if (cards.size() == 1) { + Card card = cards.get(cards.iterator().next(), game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + toLibrary.add(permanent); } - player = playerList.getNext(game, false); - } while (player != null && !player.getId().equals(game.getActivePlayerId()) && activePlayer.canRespond()); - return true; - } - return false; + } + // move all permanents to lib at the same time + for (Permanent permanent : toLibrary) { + player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, true, false); + } + // cards to bottom + cards.clear(); + toLibrary.clear(); + for (Permanent permanent : permanentsToBottom) { + if (permanent instanceof PermanentToken) { + toLibrary.add(permanent); + } else { + Card card = game.getCard(permanent.getId()); + if (card != null) { + cards.add(card); + } + } + } + target = new TargetCard(Zone.BATTLEFIELD, new FilterCard("order to put on bottom of library (last choosen will be bottommost card)")); + while (player.canRespond() && cards.size() > 1) { + player.choose(Outcome.Neutral, cards, target, game); + + Card card = cards.get(target.getFirstTarget(), game); + if (card != null) { + cards.remove(card); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + toLibrary.add(permanent); + } + } + target.clearChosen(); + } + if (cards.size() == 1) { + Card card = cards.get(cards.iterator().next(), game); + Permanent permanent = game.getPermanent(card.getId()); + if (permanent != null) { + toLibrary.add(permanent); + } + } + // move all permanents to lib at the same time + for (Permanent permanent : toLibrary) { + player.moveCardToLibraryWithInfo(permanent, source, game, Zone.BATTLEFIELD, false, false); + } + player = playerList.getNext(game, false); + } while (player != null && !player.getId().equals(game.getActivePlayerId()) && activePlayer.canRespond()); + + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AgelessSentinels.java b/Mage.Sets/src/mage/cards/a/AgelessSentinels.java index 341854f825..45cc00c963 100644 --- a/Mage.Sets/src/mage/cards/a/AgelessSentinels.java +++ b/Mage.Sets/src/mage/cards/a/AgelessSentinels.java @@ -50,37 +50,37 @@ public final class AgelessSentinels extends CardImpl { public AgelessSentinels copy() { return new AgelessSentinels(this); } +} - private class AgelessSentinelsEffect extends ContinuousEffectImpl { +class AgelessSentinelsEffect extends ContinuousEffectImpl { - public AgelessSentinelsEffect() { - super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.BecomeCreature); - staticText = "it becomes a Bird Giant"; + public AgelessSentinelsEffect() { + super(Duration.WhileOnBattlefield, Layer.TypeChangingEffects_4, SubLayer.NA, Outcome.BecomeCreature); + staticText = "it becomes a Bird Giant"; + } + + private AgelessSentinelsEffect(final AgelessSentinelsEffect effect) { + super(effect); + } + + @Override + public AgelessSentinelsEffect copy() { + return new AgelessSentinelsEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { + return false; } + permanent.removeAllCreatureTypes(game); + permanent.addSubType(game, SubType.BIRD, SubType.GIANT); + return true; + } - public AgelessSentinelsEffect(final AgelessSentinelsEffect effect) { - super(effect); - } - - @Override - public AgelessSentinelsEffect copy() { - return new AgelessSentinelsEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent == null) { - return false; - } - permanent.removeAllCreatureTypes(game); - permanent.addSubType(game, SubType.BIRD, SubType.GIANT); - return true; - } - - @Override - public boolean hasLayer(Layer layer) { - return layer == Layer.TypeChangingEffects_4; - } + @Override + public boolean hasLayer(Layer layer) { + return layer == Layer.TypeChangingEffects_4; } } diff --git a/Mage.Sets/src/mage/cards/a/AkoumHellkite.java b/Mage.Sets/src/mage/cards/a/AkoumHellkite.java index 9c61c25c58..2d3cdfd685 100644 --- a/Mage.Sets/src/mage/cards/a/AkoumHellkite.java +++ b/Mage.Sets/src/mage/cards/a/AkoumHellkite.java @@ -58,7 +58,7 @@ class AkoumHellkiteTriggeredAbility extends TriggeredAbilityImpl { super(Zone.BATTLEFIELD, new AkoumHellkiteDamageEffect()); } - public AkoumHellkiteTriggeredAbility(final AkoumHellkiteTriggeredAbility ability) { + private AkoumHellkiteTriggeredAbility(final AkoumHellkiteTriggeredAbility ability) { super(ability); } @@ -75,19 +75,21 @@ class AkoumHellkiteTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null - && permanent.isLand(game) - && permanent.isControlledBy(getControllerId())) { - Permanent sourcePermanent = game.getPermanent(getSourceId()); - if (sourcePermanent != null) { - for (Effect effect : getEffects()) { - if (effect instanceof AkoumHellkiteDamageEffect) { - effect.setTargetPointer(new FixedTarget(permanent, game)); - } - return true; - } + if (permanent == null) { return false; } + + if (!permanent.isLand(game) || !permanent.isControlledBy(getControllerId())) { return false; } + + Permanent sourcePermanent = game.getPermanent(getSourceId()); + if (sourcePermanent == null) { return false; } + + for (Effect effect : getEffects()) { + if (effect instanceof AkoumHellkiteDamageEffect) { + effect.setTargetPointer(new FixedTarget(permanent, game)); + return true; } + } + // The Hellkit somehow lost it's damage effect but not it's landfall ability return false; } @@ -116,24 +118,22 @@ class AkoumHellkiteDamageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Permanent land = getTargetPointer().getFirstTargetPermanentOrLKI(game, source); + if (land == null) { return false; } + + int damage = land.hasSubtype(SubType.MOUNTAIN, game) ? 2 : 1; + + // Get target for damange Player player = game.getPlayer(source.getFirstTarget()); - if (land != null && player != null) { - if (land.hasSubtype(SubType.MOUNTAIN, game)) { - player.damage(2, source.getSourceId(), source, game); - } else { - player.damage(1, source.getSourceId(), source, game); - } - return true; - } Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (land != null && permanent != null) { - if (land.hasSubtype(SubType.MOUNTAIN, game)) { - permanent.damage(2, source.getSourceId(), source, game); - } else { - permanent.damage(1, source.getSourceId(), source, game); - } - return true; + if (player == null && permanent == null) { return false; } + + if (player != null) { + // Target is a player + player.damage(damage, source.getSourceId(), source, game); + } else { + // Target is a permanent + permanent.damage(damage, source.getSourceId(), source, game); } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AkroanHorse.java b/Mage.Sets/src/mage/cards/a/AkroanHorse.java index ea9789aebe..2e741b5ea8 100644 --- a/Mage.Sets/src/mage/cards/a/AkroanHorse.java +++ b/Mage.Sets/src/mage/cards/a/AkroanHorse.java @@ -37,8 +37,10 @@ public final class AkroanHorse extends CardImpl { // Defender this.addAbility(DefenderAbility.getInstance()); + // When Akroan Horse enters the battlefield, an opponent gains control of it. this.addAbility(new EntersBattlefieldTriggeredAbility(new AkroanHorseChangeControlEffect(), false)); + // At the beginning of your upkeep, each opponent create a 1/1 white Soldier creature token. this.addAbility(new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new AkroanHorseCreateTokenEffect(), TargetController.YOU, false)); } @@ -60,7 +62,7 @@ class AkroanHorseChangeControlEffect extends OneShotEffect { this.staticText = "an opponent gains control of it"; } - public AkroanHorseChangeControlEffect(final AkroanHorseChangeControlEffect effect) { + private AkroanHorseChangeControlEffect(final AkroanHorseChangeControlEffect effect) { super(effect); } @@ -88,7 +90,7 @@ class AkroanHorseChangeControlEffect extends OneShotEffect { class AkroanHorseGainControlEffect extends ContinuousEffectImpl { - UUID controller; + private final UUID controller; public AkroanHorseGainControlEffect(Duration duration, UUID controller) { super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); @@ -107,14 +109,18 @@ class AkroanHorseGainControlEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { - Permanent permanent = game.getPermanent(source.getFirstTarget()); - if (targetPointer != null) { + Permanent permanent; + + if (targetPointer == null) { + permanent = game.getPermanent(source.getFirstTarget()); + } else { permanent = game.getPermanent(targetPointer.getFirst(game, source)); } - if (permanent != null) { - return permanent.changeControllerId(controller, game, source); - } - return false; + + if (permanent == null) { return false; } + + return permanent.changeControllerId(controller, game, source); + } @Override @@ -130,7 +136,7 @@ class AkroanHorseCreateTokenEffect extends OneShotEffect { this.staticText = "each opponent creates a 1/1 white Soldier creature token"; } - public AkroanHorseCreateTokenEffect(final AkroanHorseCreateTokenEffect effect) { + private AkroanHorseCreateTokenEffect(final AkroanHorseCreateTokenEffect effect) { super(effect); } diff --git a/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java b/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java index b3f27fa3cd..d61412fa39 100644 --- a/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java +++ b/Mage.Sets/src/mage/cards/a/AkromaVisionOfIxidor.java @@ -106,7 +106,7 @@ class AkromaVisionOfIxidorEffect extends OneShotEffect { StaticFilters.FILTER_CONTROLLED_ANOTHER_CREATURE, source.getControllerId(), source.getSourceId(), game )) { - Abilities abilities = permanent.getAbilities(game); + Abilities abilities = permanent.getAbilities(game); int count = classes .stream() .map(clazz -> abilities.stream().anyMatch(clazz::isInstance)) diff --git a/Mage.Sets/src/mage/cards/a/AliFromCairo.java b/Mage.Sets/src/mage/cards/a/AliFromCairo.java index 2957af4ef7..310a6b6428 100644 --- a/Mage.Sets/src/mage/cards/a/AliFromCairo.java +++ b/Mage.Sets/src/mage/cards/a/AliFromCairo.java @@ -65,27 +65,26 @@ class AliFromCairoReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { Permanent permanent = game.getPermanent(source.getSourceId()); - if (permanent != null) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null - && (controller.getLife() > 0) &&(controller.getLife() - event.getAmount()) < 1 - && event.getPlayerId().equals(controller.getId()) - ) { - return true; - } - } - return false; + if (permanent == null) { return false; } + + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + + return (controller.getLife() > 0) && (controller.getLife() - event.getAmount()) < 1 + && event.getPlayerId().equals(controller.getId()); } @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - // 10/1/2008: The ability doesn't change how much damage is dealt; - // it just changes how much life that damage makes you lose. - // An effect such as Spirit Link will see the full amount of damage being dealt. - event.setAmount(controller.getLife() - 1); - } + if (controller == null) { return false; } + + // 10/1/2008: The ability doesn't change how much damage is dealt; + // it just changes how much life that damage makes you lose. + // An effect such as Spirit Link will see the full amount of damage being dealt. + event.setAmount(controller.getLife() - 1); + + // TODO: Is this supposed to be false? Seem suspicious return false; } } diff --git a/Mage.Sets/src/mage/cards/a/AlignedHedronNetwork.java b/Mage.Sets/src/mage/cards/a/AlignedHedronNetwork.java index cfde81c407..08a0cbe0a9 100644 --- a/Mage.Sets/src/mage/cards/a/AlignedHedronNetwork.java +++ b/Mage.Sets/src/mage/cards/a/AlignedHedronNetwork.java @@ -70,20 +70,20 @@ class AlignedHedronNetworkExileEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false;} + Permanent permanent = game.getPermanent(source.getSourceId()); + if (permanent == null) { return false; } + // If Whale leaves the battlefield before its triggered ability resolves, // the target creature won't be exiled. - if (controller != null && permanent != null) { - Set toExile = new LinkedHashSet<>(); - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game)) { - toExile.add(creature); - } - if (!toExile.isEmpty()) { - controller.moveCardsToExile(toExile, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName()); - new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility()).apply(game, source); - } - return true; - } - return false; + Set toExile = new LinkedHashSet<>(game.getBattlefield().getActivePermanents(filter, controller.getId(), source.getSourceId(), game)); + if (toExile.isEmpty()) { return false; } + + controller.moveCardsToExile(toExile, source, game, true, CardUtil.getCardExileZoneId(game, source), permanent.getIdName()); + new CreateDelayedTriggeredAbilityEffect(new OnLeaveReturnExiledToBattlefieldAbility()).apply(game, source); + + return true; + } } diff --git a/Mage.Sets/src/mage/cards/a/AllHallowsEve.java b/Mage.Sets/src/mage/cards/a/AllHallowsEve.java index eb9db02f15..1b6e2b1249 100644 --- a/Mage.Sets/src/mage/cards/a/AllHallowsEve.java +++ b/Mage.Sets/src/mage/cards/a/AllHallowsEve.java @@ -9,6 +9,7 @@ import mage.abilities.dynamicvalue.common.StaticValue; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.ExileSpellEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect; +import mage.abilities.effects.common.counter.RemoveCounterSourceEffect; import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; @@ -34,10 +35,18 @@ public final class AllHallowsEve extends CardImpl { this.getSpellAbility().addEffect(new ExileSpellEffect()); this.getSpellAbility().addEffect(new AddCountersSourceEffect( CounterType.SCREAM.createInstance(), StaticValue.get(2), true, true - ).setText("with 2 scream counters on it")); + ).setText("with two scream counters on it")); - // At the beginning of your upkeep, if All Hallow's Eve is exiled with a scream counter on it, remove a scream counter from it. If there are no more scream counters on it, put it into your graveyard and each player returns all creature cards from their graveyard to the battlefield. - this.addAbility(new ConditionalInterveningIfTriggeredAbility(new BeginningOfUpkeepTriggeredAbility(Zone.EXILED, new AllHallowsEveEffect(), TargetController.YOU, false), AllHallowsEveCondition.instance, "At the beginning of your upkeep, if {this} is exiled with a scream counter on it, remove a scream counter from it. If there are no more scream counters on it, put it into your graveyard and each player returns all creature cards from their graveyard to the battlefield.")); + // At the beginning of your upkeep, if All Hallow's Eve is exiled with a scream counter on it, remove a scream counter from it. + // If there are no more scream counters on it, put it into your graveyard and each player returns all creature cards from their graveyard to the battlefield. + Ability ability = new BeginningOfUpkeepTriggeredAbility( + Zone.EXILED, + new RemoveCounterSourceEffect(CounterType.SCREAM.createInstance(1)), + TargetController.YOU, + false + ); + ability.addEffect(new AllHallowsEveEffect()); + this.addAbility(ability); } private AllHallowsEve(final AllHallowsEve card) { @@ -50,23 +59,12 @@ public final class AllHallowsEve extends CardImpl { } } -enum AllHallowsEveCondition implements Condition { - instance; - - @Override - public boolean apply(Game game, Ability source) { - MageObject sourceObject = source.getSourceObjectIfItStillExists(game); - return sourceObject != null - && game.getState().getZone(source.getSourceId()) == Zone.EXILED - && sourceObject instanceof Card - && ((Card) sourceObject).getMainCard().getCounters(game).getCount(CounterType.SCREAM) > 0; - } -} - class AllHallowsEveEffect extends OneShotEffect { AllHallowsEveEffect() { super(Outcome.PutCreatureInPlay); + staticText = "If there are no more scream counters on it, put it into your graveyard " + + "and each player returns all creature cards from their graveyard to the battlefield."; } private AllHallowsEveEffect(final AllHallowsEveEffect effect) { @@ -80,13 +78,15 @@ class AllHallowsEveEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card card = (Card) source.getSourceObject(game); + Card allHallowsEveCard = (Card) source.getSourceObject(game); + if (allHallowsEveCard == null) { return false; } Player controller = game.getPlayer(source.getControllerId()); - if (card == null || controller == null) { - return false; - } - controller.moveCards(card, Zone.GRAVEYARD, source, game); - Cards cards = new CardsImpl(); + if (controller == null) { return false; } + + if (allHallowsEveCard.getCounters(game).getCount(CounterType.SCREAM) > 0) { return false; } + + controller.moveCards(allHallowsEveCard, Zone.GRAVEYARD, source, game); + Cards allCreatureCardsInGraveyards = new CardsImpl(); game.getState() .getPlayersInRange(source.getControllerId(), game) .stream() @@ -96,8 +96,9 @@ class AllHallowsEveEffect extends OneShotEffect { .map(g -> g.getCards(game)) .flatMap(Collection::stream) .filter(card1 -> card1.isCreature(game)) - .forEach(cards::add); - controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null); + .forEach(allCreatureCardsInGraveyards::add); + + controller.moveCards(allCreatureCardsInGraveyards.getCards(game), Zone.BATTLEFIELD, source, game, false, false, true, null); return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AltarOfTheLost.java b/Mage.Sets/src/mage/cards/a/AltarOfTheLost.java index 8b674e5c8e..a014e2343e 100644 --- a/Mage.Sets/src/mage/cards/a/AltarOfTheLost.java +++ b/Mage.Sets/src/mage/cards/a/AltarOfTheLost.java @@ -71,8 +71,8 @@ class AltarOfTheLostManaCondition implements Condition { @Override public boolean apply(Game game, Ability source) { MageObject object = game.getObject(source.getSourceId()); - if (game != null && game.inCheckPlayableState()) { - if (object instanceof Card && game.getState().getZone(source.getSourceId()).equals(Zone.GRAVEYARD)) { + if (game.inCheckPlayableState()) { + if (object instanceof Card && game.getState().getZone(source.getSourceId()) == Zone.GRAVEYARD) { for (Ability ability : ((Card) object).getAbilities(game)) { if (ability instanceof FlashbackAbility) { return true; diff --git a/Mage.Sets/src/mage/cards/a/AminatousAugury.java b/Mage.Sets/src/mage/cards/a/AminatousAugury.java index 53f6bb3a63..25cb90a5c7 100644 --- a/Mage.Sets/src/mage/cards/a/AminatousAugury.java +++ b/Mage.Sets/src/mage/cards/a/AminatousAugury.java @@ -37,7 +37,8 @@ public class AminatousAugury extends CardImpl { public AminatousAugury(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{6}{U}{U}"); - // Exile the top eight cards of your library. You may put a land card from among them onto the battlefield. + // Exile the top eight cards of your library. + // You may put a land card from among them onto the battlefield. // Until end of turn, for each nonland card type, you may cast a card of that type from among the exiled cards // without paying its mana cost. this.getSpellAbility().addEffect(new AminatousAuguryEffect()); @@ -58,9 +59,10 @@ class AminatousAuguryEffect extends OneShotEffect { public AminatousAuguryEffect() { super(Outcome.PlayForFree); - staticText = "Exile the top eight cards of your library. You may put a land card from among them onto the" - + " battlefield. Until end of turn, for each nonland card type, you may cast a card of that type from" - + " among the exiled cards without paying its mana cost."; + staticText = "Exile the top eight cards of your library. " + + "You may put a land card from among them onto the battlefield. " + + "Until end of turn, for each nonland card type, " + + "you may cast a card of that type from among the exiled cards without paying its mana cost."; } public AminatousAuguryEffect(final AminatousAuguryEffect effect) { @@ -74,41 +76,42 @@ class AminatousAuguryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - // move cards from library to exile - controller.moveCardsToExile(controller.getLibrary().getTopCards(game, 8), source, game, true, source.getSourceId(), CardUtil.createObjectRealtedWindowTitle(source, game, null)); - ExileZone auguryExileZone = game.getExile().getExileZone(source.getSourceId()); - if (auguryExileZone == null) { - return true; - } - Cards cardsToCast = new CardsImpl(); - cardsToCast.addAll(auguryExileZone.getCards(game)); - // put a land card from among them onto the battlefield - TargetCard target = new TargetCard( - Zone.EXILED, - StaticFilters.FILTER_CARD_LAND_A - ); - if (cardsToCast.count(StaticFilters.FILTER_CARD_LAND, game) > 0) { - if (controller.chooseUse(Outcome.PutLandInPlay, "Put a land from among the exiled cards into play?", source, game)) { - if (controller.choose(Outcome.PutLandInPlay, cardsToCast, target, game)) { - Card card = cardsToCast.get(target.getFirstTarget(), game); - if (card != null) { - cardsToCast.remove(card); - controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null); - } - } + if (sourceObject == null) { return false; } + + // move cards from library to exile + controller.moveCardsToExile(controller.getLibrary().getTopCards(game, 8), source, game, true, source.getSourceId(), CardUtil.createObjectRealtedWindowTitle(source, game, null)); + ExileZone auguryExileZone = game.getExile().getExileZone(source.getSourceId()); + if (auguryExileZone == null) { return true; } + + Cards cardsToCast = new CardsImpl(); + cardsToCast.addAll(auguryExileZone.getCards(game)); + + // put a land card from among them onto the battlefield + TargetCard target = new TargetCard(Zone.EXILED, StaticFilters.FILTER_CARD_LAND_A); + + if (cardsToCast.count(StaticFilters.FILTER_CARD_LAND, game) == 0) { return true; } + + if (controller.chooseUse(Outcome.PutLandInPlay, "Put a land from among the exiled cards into play?", source, game)) { + if (controller.choose(Outcome.PutLandInPlay, cardsToCast, target, game)) { + Card card = cardsToCast.get(target.getFirstTarget(), game); + if (card != null) { + cardsToCast.remove(card); + controller.moveCards(card, Zone.BATTLEFIELD, source, game, false, false, true, null); } } - for (Card card : cardsToCast.getCards(StaticFilters.FILTER_CARD_NON_LAND, game)) { - AminatousAuguryCastFromExileEffect effect = new AminatousAuguryCastFromExileEffect(); - effect.setTargetPointer(new FixedTarget(card, game)); - game.addEffect(effect, source); - } } - return false; + + for (Card card : cardsToCast.getCards(StaticFilters.FILTER_CARD_NON_LAND, game)) { + AminatousAuguryCastFromExileEffect effect = new AminatousAuguryCastFromExileEffect(); + effect.setTargetPointer(new FixedTarget(card, game)); + game.addEffect(effect, source); + } + // TODO: I think this should be returning true + return true; } } @@ -136,51 +139,54 @@ class AminatousAuguryCastFromExileEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { Player player = game.getPlayer(affectedControllerId); - EnumSet usedCardTypes = EnumSet.noneOf(CardType.class); + if (player == null) { return false; } - if (game.getState().getValue(source.getSourceId().toString() + "cardTypes") != null) { + if (!affectedControllerId.equals(source.getControllerId())) { return false; } + + EnumSet usedCardTypes; + if (game.getState().getValue(source.getSourceId().toString() + "cardTypes") == null) { + // The effect has not been applied fully yet, so there are no previously cast times + usedCardTypes = EnumSet.noneOf(CardType.class); + } else { usedCardTypes = (EnumSet) game.getState().getValue(source.getSourceId().toString() + "cardTypes"); } - if (player != null - && objectId != null - && objectId.equals(getTargetPointer().getFirst(game, source)) - && affectedControllerId.equals(source.getControllerId())) { - Card card = game.getCard(objectId); - if (card != null - && game.getState().getZone(objectId) == Zone.EXILED) { - EnumSet unusedCardTypes = EnumSet.noneOf(CardType.class); - for (CardType cardT : card.getCardType(game)) { - if (!usedCardTypes.contains(cardT)) { - unusedCardTypes.add(cardT); - } - } - if (!unusedCardTypes.isEmpty()) { - if (!game.inCheckPlayableState()) { // some actions may not be done while the game only checks if a card can be cast - // Select the card type to consume and remove all not seleczted card types - if (unusedCardTypes.size() > 1) { - Choice choice = new ChoiceImpl(true); - choice.setMessage("Which card type do you want to consume?"); - Set choices = choice.getChoices(); - for (CardType cardType : unusedCardTypes) { - choices.add(cardType.toString()); - } - player.choose(Outcome.Detriment, choice, game); - for (Iterator iterator = unusedCardTypes.iterator(); iterator.hasNext();) { - CardType next = iterator.next(); - if (!next.toString().equals(choice.getChoice())) { - iterator.remove(); - } - } - usedCardTypes.add(CardType.fromString(choice.getChoice())); - } - usedCardTypes.addAll(unusedCardTypes); - game.getState().setValue(source.getSourceId().toString() + "cardTypes", usedCardTypes); - } - player.setCastSourceIdWithAlternateMana(objectId, null, card.getSpellAbility().getCosts()); - return true; - } + + if (objectId == null || !objectId.equals(getTargetPointer().getFirst(game, source))) { return false; } + + if (game.getState().getZone(objectId) != Zone.EXILED) { return false; } + + Card card = game.getCard(objectId); + if (card == null) { return false; } + + // Figure out which of the current card's types have not been cast before + EnumSet unusedCardTypes = EnumSet.noneOf(CardType.class); + for (CardType cardT : card.getCardType(game)) { + if (!usedCardTypes.contains(cardT)) { + unusedCardTypes.add(cardT); } } - return false; + + // The current card has only card types that have been cast before, so it can't be cast + if (unusedCardTypes.isEmpty()) { return false; } + + // some actions may not be done while the game only checks if a card can be cast + if (!game.inCheckPlayableState()) { + // Select the card type to consume and remove all not selected card types + if (unusedCardTypes.size() > 1) { + Choice choice = new ChoiceImpl(true); + choice.setMessage("Which card type do you want to consume?"); + Set choices = choice.getChoices(); + for (CardType cardType : unusedCardTypes) { + choices.add(cardType.toString()); + } + player.choose(Outcome.Detriment, choice, game); + unusedCardTypes.removeIf(next -> !next.toString().equals(choice.getChoice())); + usedCardTypes.add(CardType.fromString(choice.getChoice())); + } + usedCardTypes.addAll(unusedCardTypes); + game.getState().setValue(source.getSourceId().toString() + "cardTypes", usedCardTypes); + } + player.setCastSourceIdWithAlternateMana(objectId, null, card.getSpellAbility().getCosts()); + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AnHavvaConstable.java b/Mage.Sets/src/mage/cards/a/AnHavvaConstable.java index 1daa50c513..515be187f3 100644 --- a/Mage.Sets/src/mage/cards/a/AnHavvaConstable.java +++ b/Mage.Sets/src/mage/cards/a/AnHavvaConstable.java @@ -61,16 +61,17 @@ class AnHavvaConstableEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - MageObject mageObject = game.getObject(source.getSourceId()); - if (mageObject != null) { - FilterCreaturePermanent filter = new FilterCreaturePermanent("green creatures"); - filter.add(new ColorPredicate(ObjectColor.GREEN)); - int number = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); - mageObject.getToughness().setValue(number + 1); - return true; - } - } - return false; + if (controller == null) { return false; } + + MageObject mageObject = game.getObject(source.getSourceId()); + if (mageObject == null) { return false; } + + FilterCreaturePermanent filter = new FilterCreaturePermanent("green creatures"); + filter.add(new ColorPredicate(ObjectColor.GREEN)); + int numberOfGreenCreatures = game.getBattlefield().count(filter, source.getSourceId(), source.getControllerId(), game); + + mageObject.getToughness().setValue(1 + numberOfGreenCreatures); + + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java index 5b05457012..f9a6967e80 100644 --- a/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java +++ b/Mage.Sets/src/mage/cards/a/ArcaneAdaptation.java @@ -102,13 +102,14 @@ class ArcaneAdaptationEffect extends ContinuousEffectImpl { // commander in command zone for (CommandObject commandObject : game.getState().getCommand()) { if (commandObject instanceof Commander) { - Card card = game.getCard(((Commander) commandObject).getId()); + Card card = game.getCard((commandObject).getId()); if (card != null && card.isOwnedBy(controller.getId()) && card.isCreature(game) && !card.hasSubtype(subType, game)) { game.getState().getCreateMageObjectAttribute(card, game).getSubtype().add(subType); } } } + // TODO: Why is this not using the for-in loop like all the others? // creature spells you control for (Iterator iterator = game.getStack().iterator(); iterator.hasNext(); ) { StackObject stackObject = iterator.next(); diff --git a/Mage.Sets/src/mage/cards/a/AtemsisAllSeeing.java b/Mage.Sets/src/mage/cards/a/AtemsisAllSeeing.java index 7f110b7c05..465e9eca16 100644 --- a/Mage.Sets/src/mage/cards/a/AtemsisAllSeeing.java +++ b/Mage.Sets/src/mage/cards/a/AtemsisAllSeeing.java @@ -1,6 +1,7 @@ package mage.cards.a; import mage.MageInt; +import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.DealsDamageToOpponentTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; @@ -38,7 +39,7 @@ public final class AtemsisAllSeeing extends CardImpl { // {2}{U}, {T}: Draw two cards, then discard a card. Ability ability = new SimpleActivatedAbility( - new DrawDiscardControllerEffect(2, 1), new ManaCostsImpl("{2}{U}") + new DrawDiscardControllerEffect(2, 1), new ManaCostsImpl<>("{2}{U}") ); ability.addCost(new TapSourceCost()); this.addAbility(ability); @@ -88,7 +89,7 @@ class AtemsisAllSeeingEffect extends OneShotEffect { .getHand() .getCards(game) .stream() - .map(card -> card.getManaValue()) + .map(MageObject::getManaValue) .distinct() .count() > 5) { opponent.lost(game); diff --git a/Mage.Sets/src/mage/cards/a/AuraFinesse.java b/Mage.Sets/src/mage/cards/a/AuraFinesse.java index 2494b9a830..8e5416f8c0 100644 --- a/Mage.Sets/src/mage/cards/a/AuraFinesse.java +++ b/Mage.Sets/src/mage/cards/a/AuraFinesse.java @@ -35,11 +35,11 @@ public final class AuraFinesse extends CardImpl { public AuraFinesse(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{U}"); - // Attach target Aura you control to target creature. this.getSpellAbility().addEffect(new AuraFinesseEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + // Draw a card. this.getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).concatBy("
")); } @@ -70,26 +70,28 @@ class AuraFinesseEffect extends OneShotEffect { return new AuraFinesseEffect(this); } + // 15/06/2010 As Aura Finesse resolves, if either target is illegal, + // the spell resolves but the Aura doesn’t move. You still draw a card. + // If both targets are illegal, Aura Finesse doesn’t resolve and you don’t draw a card. @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent aura = game.getPermanent(source.getFirstTarget()); - Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); - if (aura != null && creature != null) { - Permanent oldCreature = game.getPermanent(aura.getAttachedTo()); - if (oldCreature != null && !oldCreature.equals(creature)) { - Target auraTarget = aura.getSpellAbility().getTargets().get(0); - if (!auraTarget.canTarget(creature.getId(), game)) { - game.informPlayers(aura.getLogName() + " was not attched to " +creature.getLogName() + " because it's no legal target for the aura" ); - } else if (oldCreature.removeAttachment(aura.getId(), source, game)) { - game.informPlayers(aura.getLogName() + " was unattached from " + oldCreature.getLogName() + " and attached to " + creature.getLogName()); - creature.addAttachment(aura.getId(), source, game); - } + if (controller == null) { return false; } + + Permanent aura = game.getPermanent(source.getFirstTarget()); + Permanent creature = game.getPermanent(source.getTargets().get(1).getFirstTarget()); + if (aura != null && creature != null) { + Permanent oldCreature = game.getPermanent(aura.getAttachedTo()); + if (oldCreature != null && !oldCreature.equals(creature)) { + Target auraTarget = aura.getSpellAbility().getTargets().get(0); + if (!auraTarget.canTarget(creature.getId(), game)) { + game.informPlayers(aura.getLogName() + " was not attched to " +creature.getLogName() + " because it's no legal target for the aura" ); + } else if (oldCreature.removeAttachment(aura.getId(), source, game)) { + game.informPlayers(aura.getLogName() + " was unattached from " + oldCreature.getLogName() + " and attached to " + creature.getLogName()); + creature.addAttachment(aura.getId(), source, game); } } - return true; } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java b/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java index 87522791a9..8c1c5861c9 100644 --- a/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java +++ b/Mage.Sets/src/mage/cards/a/AuriokEdgewright.java @@ -19,7 +19,7 @@ import java.util.UUID; */ public final class AuriokEdgewright extends CardImpl { - protected static String effectText = "Metalcraft — Auriok Edgewright has double strike as long as you control three or more artifacts."; + private static final String effectText = "Metalcraft — Auriok Edgewright has double strike as long as you control three or more artifacts."; public AuriokEdgewright(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}"); diff --git a/Mage.Sets/src/mage/cards/a/AutumnWillow.java b/Mage.Sets/src/mage/cards/a/AutumnWillow.java index 8ee5b02cfd..e7bd1c7ba3 100644 --- a/Mage.Sets/src/mage/cards/a/AutumnWillow.java +++ b/Mage.Sets/src/mage/cards/a/AutumnWillow.java @@ -70,14 +70,9 @@ class AutumnWillowEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID sourceId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getFirstTarget())) { - Permanent creature = game.getPermanent(sourceId); - if (creature != null) { - if (sourceId.equals(source.getSourceId())) { - return true; - } - } - } - return false; + if (!affectedControllerId.equals(source.getFirstTarget())) { return false; } + Permanent creature = game.getPermanent(sourceId); + + return creature != null &&sourceId.equals(source.getSourceId()); } } diff --git a/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java b/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java index 47e4137ed2..31a47150ab 100644 --- a/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java +++ b/Mage.Sets/src/mage/cards/a/AvatarOfWoe.java @@ -66,9 +66,6 @@ class AvatarOfWoeCondition implements Condition { @Override public boolean apply(Game game, Ability source) { - if (AvatarOfWoe.graveyardCount.calculate(game, source, null) >= 10) { - return true; - } - return false; + return AvatarOfWoe.graveyardCount.calculate(game, source, null) >= 10; } } diff --git a/Mage.Sets/src/mage/cards/a/AzoriusAethermage.java b/Mage.Sets/src/mage/cards/a/AzoriusAethermage.java index 333f7855d9..75c3de932e 100644 --- a/Mage.Sets/src/mage/cards/a/AzoriusAethermage.java +++ b/Mage.Sets/src/mage/cards/a/AzoriusAethermage.java @@ -11,7 +11,7 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; import mage.game.Game; import mage.game.events.GameEvent; import mage.game.events.ZoneChangeEvent; @@ -24,8 +24,6 @@ import java.util.UUID; */ public final class AzoriusAethermage extends CardImpl { - private static final String rule = "Whenever a permanent is returned to your hand, "; - public AzoriusAethermage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{U}"); @@ -35,8 +33,8 @@ public final class AzoriusAethermage extends CardImpl { this.toughness = new MageInt(1); // Whenever a permanent is returned to your hand, you may pay {1}. If you do, draw a card. - Effect effect = new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl("{1}")); - this.addAbility(new AzoriusAEthermageAbility(Zone.BATTLEFIELD, Zone.BATTLEFIELD, Zone.HAND, effect, new FilterPermanent(), rule, false)); + Effect effect = new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new ManaCostsImpl<>("{1}")); + this.addAbility(new AzoriusAEthermageAbility(effect)); } private AzoriusAethermage(final AzoriusAethermage card) { @@ -51,25 +49,14 @@ public final class AzoriusAethermage extends CardImpl { class AzoriusAEthermageAbility extends TriggeredAbilityImpl { - protected FilterPermanent filter; - protected Zone fromZone; - protected Zone toZone; - protected String rule; + private static final String rule = "Whenever a permanent is returned to your hand, "; - public AzoriusAEthermageAbility(Zone zone, Zone fromZone, Zone toZone, Effect effect, FilterPermanent filter, String rule, boolean optional) { - super(zone, effect, optional); - this.fromZone = fromZone; - this.toZone = toZone; - this.rule = rule; - this.filter = filter; + public AzoriusAEthermageAbility(Effect effect) { + super(Zone.BATTLEFIELD, effect, false); } - public AzoriusAEthermageAbility(final AzoriusAEthermageAbility ability) { + private AzoriusAEthermageAbility(final AzoriusAEthermageAbility ability) { super(ability); - this.fromZone = ability.fromZone; - this.toZone = ability.toZone; - this.rule = ability.rule; - this.filter = ability.filter; } @Override @@ -80,35 +67,29 @@ class AzoriusAEthermageAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if ((fromZone == null || zEvent.getFromZone() == fromZone) - && (toZone == null || zEvent.getToZone() == toZone)) { - Permanent permanentThatMoved = null; - if (zEvent.getTarget() != null) { - permanentThatMoved = zEvent.getTarget(); - } - //The controller's hand is where the permanent moved to. - return permanentThatMoved != null - && filter.match(permanentThatMoved, sourceId, controllerId, game) - && zEvent.getPlayerId().equals(controllerId); + if (zEvent.getFromZone() != Zone.BATTLEFIELD || zEvent.getToZone() != Zone.HAND) { + return false; } - return false; + + if (!zEvent.getPlayerId().equals(controllerId)) { + return false; + } + + Permanent permanentThatMoved = zEvent.getTarget(); + if (permanentThatMoved == null) { + return false; + } + + return StaticFilters.FILTER_PERMANENT_CREATURE.match(permanentThatMoved, sourceId, controllerId, game); } @Override public String getTriggerPhrase() { - return rule ; + return rule; } @Override public AzoriusAEthermageAbility copy() { return new AzoriusAEthermageAbility(this); } - - public Zone getFromZone() { - return fromZone; - } - - public Zone getToZone() { - return toZone; - } } diff --git a/Mage.Sets/src/mage/cards/a/AzorsGateway.java b/Mage.Sets/src/mage/cards/a/AzorsGateway.java index 9e97185af0..c43cb154c9 100644 --- a/Mage.Sets/src/mage/cards/a/AzorsGateway.java +++ b/Mage.Sets/src/mage/cards/a/AzorsGateway.java @@ -38,7 +38,9 @@ public final class AzorsGateway extends CardImpl { this.addSuperType(SuperType.LEGENDARY); this.secondSideCardClazz = mage.cards.s.SanctumOfTheSun.class; - // {1}, {T}: Draw a card, then exile a card from your hand. If cards with five or more different converted mana costs are exiled with Azor's Gateway, you gain 5 life, untap Azor's Gateway, and transform it. + // {1}, {T}: Draw a card, then exile a card from your hand. + // If cards with five or more different converted mana costs are exiled with Azor's Gateway, + // you gain 5 life, untap Azor's Gateway, and transform it. this.addAbility(new TransformAbility()); Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new AzorsGatewayEffect(), new GenericManaCost(1)); ability.addCost(new TapSourceCost()); @@ -59,7 +61,9 @@ class AzorsGatewayEffect extends OneShotEffect { public AzorsGatewayEffect() { super(Outcome.Benefit); - this.staticText = "Draw a card, then exile a card from your hand. If cards with five or more different mana values are exiled with {this}, you gain 5 life, untap Azor's Gateway, and transform it"; + this.staticText = "Draw a card, then exile a card from your hand. " + + "If cards with five or more different mana values are exiled with {this}, " + + "you gain 5 life, untap Azor's Gateway, and transform it"; } public AzorsGatewayEffect(final AzorsGatewayEffect effect) { @@ -74,30 +78,32 @@ class AzorsGatewayEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - UUID exileId = CardUtil.getCardExileZoneId(game, source); + if (controller == null) { return false; } + MageObject sourceObject = source.getSourceObject(game); - if (controller != null && exileId != null && sourceObject != null) { - controller.drawCards(1, source, game); - TargetCardInHand target = new TargetCardInHand(); - controller.choose(outcome, target, source.getSourceId(), game); - Card cardToExile = game.getCard(target.getFirstTarget()); - if (cardToExile != null) { - controller.moveCardsToExile(cardToExile, source, game, true, exileId, sourceObject.getIdName()); - } - Set usedCMC = new HashSet<>(); - ExileZone exileZone = game.getExile().getExileZone(exileId); - if (exileZone != null) { - for (Card card : exileZone.getCards(game)) { - usedCMC.add(card.getManaValue()); - } - if (usedCMC.size() > 4) { - controller.gainLife(4, game, source); - new UntapSourceEffect().apply(game, source); - new TransformSourceEffect().apply(game, source); - } - } - return true; + if (sourceObject == null) { return false; } + + UUID exileId = CardUtil.getCardExileZoneId(game, source); + + controller.drawCards(1, source, game); + TargetCardInHand target = new TargetCardInHand(); + controller.choose(outcome, target, source.getSourceId(), game); + Card cardToExile = game.getCard(target.getFirstTarget()); + if (cardToExile != null) { + controller.moveCardsToExile(cardToExile, source, game, true, exileId, sourceObject.getIdName()); } - return false; + Set usedCMC = new HashSet<>(); + ExileZone exileZone = game.getExile().getExileZone(exileId); + if (exileZone != null) { + for (Card card : exileZone.getCards(game)) { + usedCMC.add(card.getManaValue()); + } + if (usedCMC.size() > 4) { + controller.gainLife(4, game, source); + new UntapSourceEffect().apply(game, source); + new TransformSourceEffect().apply(game, source); + } + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java b/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java index 26b383bded..f90e667e36 100644 --- a/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java +++ b/Mage.Sets/src/mage/cards/b/BaneAlleyBroker.java @@ -162,7 +162,7 @@ class BaneAlleyBrokerReturnToHandEffect extends OneShotEffect { if (card == null) { return false; } - return card != null && player.moveCards(card, Zone.HAND, source, game); + return player.moveCards(card, Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/b/Banefire.java b/Mage.Sets/src/mage/cards/b/Banefire.java index ccf67d35f2..8c3657e360 100644 --- a/Mage.Sets/src/mage/cards/b/Banefire.java +++ b/Mage.Sets/src/mage/cards/b/Banefire.java @@ -34,6 +34,7 @@ public final class Banefire extends CardImpl { // Banefire deals X damage to any target. this.getSpellAbility().addEffect(new BaneFireEffect()); this.getSpellAbility().addTarget(new TargetAnyTarget()); + // If X is 5 or more, Banefire can't be countered and the damage can't be prevented. this.addAbility(new SimpleStaticAbility(Zone.STACK, new BanefireCantCounterEffect())); } @@ -50,8 +51,8 @@ public final class Banefire extends CardImpl { class testCondition implements Condition { - private DynamicValue xValue; - private int limit; + private final DynamicValue xValue; + private final int limit; public testCondition(DynamicValue xValue, int limit) { this.xValue = xValue; @@ -105,7 +106,7 @@ class BaneFireEffect extends OneShotEffect { class BanefireCantCounterEffect extends ContinuousRuleModifyingEffectImpl { - Condition condition = new testCondition(ManacostVariableValue.REGULAR, 5); + private Condition condition = new testCondition(ManacostVariableValue.REGULAR, 5); public BanefireCantCounterEffect() { super(Duration.WhileOnStack, Outcome.Benefit); @@ -129,18 +130,14 @@ class BanefireCantCounterEffect extends ContinuousRuleModifyingEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (event.getType() == GameEvent.EventType.COUNTER) { - Card card = game.getCard(source.getSourceId()); - if (card != null) { - UUID spellId = card.getSpellAbility().getId(); - if (event.getTargetId().equals(spellId)) { - if (condition.apply(game, source)) { - return true; - } - } - } - } - return false; - } + if (event.getType() != GameEvent.EventType.COUNTER) { return false; } + Card card = game.getCard(source.getSourceId()); + if (card == null) { return false; } + + UUID spellId = card.getSpellAbility().getId(); + if (!event.getTargetId().equals(spellId)) { return false; } + + return condition.apply(game, source); + } } diff --git a/Mage.Sets/src/mage/cards/b/BanthaHerd.java b/Mage.Sets/src/mage/cards/b/BanthaHerd.java index a20e4be969..0e06b46df1 100644 --- a/Mage.Sets/src/mage/cards/b/BanthaHerd.java +++ b/Mage.Sets/src/mage/cards/b/BanthaHerd.java @@ -65,10 +65,10 @@ class BathaHerdEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - int xValue = ((BecomesMonstrousSourceTriggeredAbility) source).getMonstrosityValue(); - return new CreateTokenEffect(new TuskenRaiderToken(), xValue).apply(game, source); - } - return false; + if (controller == null) { return false; } + + int xValue = ((BecomesMonstrousSourceTriggeredAbility) source).getMonstrosityValue(); + + return new CreateTokenEffect(new TuskenRaiderToken(), xValue).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/b/BatheInLight.java b/Mage.Sets/src/mage/cards/b/BatheInLight.java index 1c5ea0c9a7..32050ff30a 100644 --- a/Mage.Sets/src/mage/cards/b/BatheInLight.java +++ b/Mage.Sets/src/mage/cards/b/BatheInLight.java @@ -70,34 +70,32 @@ class BatheInLightEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (target != null) { - ChoiceColor colorChoice = new ChoiceColor(); - if (!controller.choose(Outcome.Benefit, colorChoice, game)) { - return false; - } - game.informPlayers(target.getName() + ": " + controller.getLogName() + " has chosen " + colorChoice.getChoice()); - game.getState().setValue(target.getId() + "_color", colorChoice.getColor()); + if (controller == null) { return false; } - ObjectColor protectColor = (ObjectColor) game.getState().getValue(target.getId() + "_color"); - if (protectColor != null) { - ContinuousEffect effect = new ProtectionChosenColorTargetEffect(); - game.addEffect(effect, source); - ObjectColor color = target.getColor(game); - for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { - if (!permanent.getId().equals(target.getId()) && permanent.getColor(game).shares(color)) { - game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor()); - effect.setTargetPointer(new FixedTarget(permanent, game)); - game.addEffect(effect, source); - } - } + Permanent target = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (target == null) { return false; } - } - return true; + ChoiceColor colorChoice = new ChoiceColor(); + if (!controller.choose(Outcome.Benefit, colorChoice, game)) { return false; } + + game.informPlayers(target.getName() + ": " + controller.getLogName() + " has chosen " + colorChoice.getChoice()); + game.getState().setValue(target.getId() + "_color", colorChoice.getColor()); + + ObjectColor protectColor = (ObjectColor) game.getState().getValue(target.getId() + "_color"); + if (protectColor == null) { return true; } + + ContinuousEffect effect = new ProtectionChosenColorTargetEffect(); + game.addEffect(effect, source); + ObjectColor color = target.getColor(game); + for (Permanent permanent : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, source.getControllerId(), source.getSourceId(), game)) { + if (!permanent.getId().equals(target.getId()) && permanent.getColor(game).shares(color)) { + game.getState().setValue(permanent.getId() + "_color", colorChoice.getColor()); + effect.setTargetPointer(new FixedTarget(permanent, game)); + game.addEffect(effect, source); } } - return false; + + return true; } } @@ -128,19 +126,20 @@ class ProtectionChosenColorTargetEffect extends ContinuousEffectImpl { @Override public boolean apply(Game game, Ability source) { Permanent permanent = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (permanent != null) { - ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); - if (color != null && (protectionAbility == null || !color.equals(chosenColor))) { - chosenColor = color; - FilterObject protectionFilter = new FilterObject(chosenColor.getDescription()); - protectionFilter.add(new ColorPredicate(chosenColor)); - protectionAbility = new ProtectionAbility(protectionFilter); - } - if (protectionAbility != null) { - permanent.addAbility(protectionAbility, source.getSourceId(), game); - return true; - } + if (permanent == null) { return false; } + + ObjectColor color = (ObjectColor) game.getState().getValue(permanent.getId() + "_color"); + if (color != null && (protectionAbility == null || !color.equals(chosenColor))) { + chosenColor = color; + FilterObject protectionFilter = new FilterObject<>(chosenColor.getDescription()); + protectionFilter.add(new ColorPredicate(chosenColor)); + protectionAbility = new ProtectionAbility(protectionFilter); } + if (protectionAbility != null) { + permanent.addAbility(protectionAbility, source.getSourceId(), game); + return true; + } + return false; } } diff --git a/Mage.Sets/src/mage/cards/b/BattlefieldThaumaturge.java b/Mage.Sets/src/mage/cards/b/BattlefieldThaumaturge.java index c911bd92af..9f6b3fdca8 100644 --- a/Mage.Sets/src/mage/cards/b/BattlefieldThaumaturge.java +++ b/Mage.Sets/src/mage/cards/b/BattlefieldThaumaturge.java @@ -66,7 +66,7 @@ class BattlefieldThaumaturgeSpellsCostReductionEffect extends CostModificationEf @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { - int reduceAmount = 0; + int reduceAmount; if (game.inCheckPlayableState()) { // checking state (search max possible targets) reduceAmount = getMaxPossibleTargetCreatures(abilityToModify, game); @@ -117,7 +117,7 @@ class BattlefieldThaumaturgeSpellsCostReductionEffect extends CostModificationEf && abilityToModify.isControlledBy(source.getControllerId())) { Spell spell = (Spell) game.getStack().getStackObject(abilityToModify.getId()); if (spell != null) { - return spell != null && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(spell, game); + return StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(spell, game); } else { Card sourceCard = game.getCard(abilityToModify.getSourceId()); return sourceCard != null && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(sourceCard, game); diff --git a/Mage.Sets/src/mage/cards/b/BehemothSledge.java b/Mage.Sets/src/mage/cards/b/BehemothSledge.java index f92bc30bad..db4db6ca3a 100644 --- a/Mage.Sets/src/mage/cards/b/BehemothSledge.java +++ b/Mage.Sets/src/mage/cards/b/BehemothSledge.java @@ -24,15 +24,17 @@ public final class BehemothSledge extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{G}{W}"); this.subtype.add(SubType.EQUIPMENT); + // Equipped creature gets +2/+2 and has trample and lifelink. Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new BoostEquippedEffect(2, 2)); ability.addEffect(new GainAbilityAttachedEffect(TrampleAbility.getInstance(), AttachmentType.EQUIPMENT).setText("and has trample")); ability.addEffect(new GainAbilityAttachedEffect(LifelinkAbility.getInstance(), AttachmentType.EQUIPMENT).setText("and lifelink")); this.addAbility(ability); + // Equip {3} this.addAbility(new EquipAbility(Outcome.AddAbility, new GenericManaCost(3))); } - protected BehemothSledge(BehemothSledge me) { + private BehemothSledge(BehemothSledge me) { super(me); } diff --git a/Mage.Sets/src/mage/cards/b/BendOrBreak.java b/Mage.Sets/src/mage/cards/b/BendOrBreak.java index 18018f38b2..43026084be 100644 --- a/Mage.Sets/src/mage/cards/b/BendOrBreak.java +++ b/Mage.Sets/src/mage/cards/b/BendOrBreak.java @@ -64,122 +64,123 @@ class BendOrBreakEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { + if (controller == null) { return false; } - // Map of players and their piles - Map>> playerPermanents = new LinkedHashMap<>(); + // Map of players and their piles + Map>> playerPermanents = new LinkedHashMap<>(); - PlayerList playerList = game.getState().getPlayerList().copy(); - while (!playerList.get().equals(source.getControllerId()) && controller.canRespond()) { - playerList.getNext(); - } - Player currentPlayer = game.getPlayer(playerList.get()); - Player nextPlayer; - UUID firstNextPlayer = null; - - while (!getNextPlayerInDirection(true, playerList).equals(firstNextPlayer) && controller.canRespond()) { - nextPlayer = game.getPlayer(playerList.get()); - if (nextPlayer == null) { - return false; - } - if (firstNextPlayer == null) { - firstNextPlayer = nextPlayer.getId(); - } - if (!nextPlayer.canRespond()) { - continue; - } - // Each player separates all nontoken lands they control into two piles - if (currentPlayer != null && game.getState().getPlayersInRange(controller.getId(), game).contains(currentPlayer.getId())) { - List firstPile = new ArrayList<>(); - List secondPile = new ArrayList<>(); - FilterControlledLandPermanent filter = new FilterControlledLandPermanent("lands you control to assign to the first pile (lands not chosen will be assigned to the second pile)"); - TargetPermanent target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); - if (target.canChoose(source.getSourceId(), currentPlayer.getId(), game)) { - // TODO: add support for AI (50/50), need AI hints mechanic here - currentPlayer.chooseTarget(Outcome.Neutral, target, source, game); - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, currentPlayer.getId(), game)) { - if (target.getTargets().contains(permanent.getId())) { - firstPile.add(permanent); - } else { - secondPile.add(permanent); - } - } - - StringBuilder sb = new StringBuilder("First pile of ").append(currentPlayer.getLogName()).append(": "); - sb.append(firstPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); - - game.informPlayers(sb.toString()); - - sb = new StringBuilder("Second pile of ").append(currentPlayer.getLogName()).append(": "); - sb.append(secondPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); - - game.informPlayers(sb.toString()); - } - List> playerPiles = new ArrayList<>(); - playerPiles.add(firstPile); - playerPiles.add(secondPile); - playerPermanents.put(currentPlayer.getId(), playerPiles); - } - currentPlayer = nextPlayer; - } - - // For each player, one of their piles is chosen by one of their opponents of their choice - for (Map.Entry>> playerPiles : playerPermanents.entrySet()) { - Player player = game.getPlayer(playerPiles.getKey()); - if (player != null) { - FilterPlayer filter = new FilterPlayer("opponent"); - List opponentPredicates = new ArrayList<>(); - for (UUID opponentId : game.getOpponents(player.getId())) { - opponentPredicates.add(new PlayerIdPredicate(opponentId)); - } - filter.add(Predicates.or(opponentPredicates)); - Target target = new TargetPlayer(1, 1, true, filter); - target.setTargetController(player.getId()); - target.setAbilityController(source.getControllerId()); - if (player.chooseTarget(outcome, target, source, game)) { - Player chosenOpponent = game.getPlayer(target.getFirstTarget()); - if (chosenOpponent != null) { - List firstPile = playerPiles.getValue().get(0); - List secondPile = playerPiles.getValue().get(1); - game.informPlayers(player.getLogName() + " chose " + chosenOpponent.getLogName() + " to choose their pile"); - if (chosenOpponent.choosePile(outcome, "Piles of " + player.getName(), firstPile, secondPile, game)) { - List> lists = playerPiles.getValue(); - lists.clear(); - lists.add(firstPile); - lists.add(secondPile); - game.informPlayers(player.getLogName() + " will have their first pile destroyed"); - } else { - List> lists = playerPiles.getValue(); - lists.clear(); - lists.add(secondPile); - lists.add(firstPile); - game.informPlayers(player.getLogName() + " will have their second pile destroyed"); - } - } - } - } - } - // Destroy all lands in the chosen piles. Tap all lands in the other piles - for (Map.Entry>> playerPiles : playerPermanents.entrySet()) { - Player player = game.getPlayer(playerPiles.getKey()); - if (player != null) { - List pileToSac = playerPiles.getValue().get(0); - List pileToTap = playerPiles.getValue().get(1); - for (Permanent permanent : pileToSac) { - if (permanent != null) { - permanent.destroy(source, game, false); - } - } - for (Permanent permanent : pileToTap) { - if (permanent != null) { - permanent.tap(source, game); - } - } - } - } - return true; + PlayerList playerList = game.getState().getPlayerList().copy(); + while (!playerList.get().equals(source.getControllerId()) && controller.canRespond()) { + playerList.getNext(); } - return false; + Player currentPlayer = game.getPlayer(playerList.get()); + Player nextPlayer; + UUID firstNextPlayer = null; + + while (!getNextPlayerInDirection(true, playerList).equals(firstNextPlayer) && controller.canRespond()) { + nextPlayer = game.getPlayer(playerList.get()); + if (nextPlayer == null) { + return false; + } + if (firstNextPlayer == null) { + firstNextPlayer = nextPlayer.getId(); + } + if (!nextPlayer.canRespond()) { + continue; + } + // Each player separates all nontoken lands they control into two piles + if (currentPlayer == null || !game.getState().getPlayersInRange(controller.getId(), game).contains(currentPlayer.getId())) { + continue; + } + List firstPile = new ArrayList<>(); + List secondPile = new ArrayList<>(); + FilterControlledLandPermanent filter = new FilterControlledLandPermanent("lands you control to assign to the first pile (lands not chosen will be assigned to the second pile)"); + TargetPermanent target = new TargetControlledPermanent(0, Integer.MAX_VALUE, filter, true); + if (!target.canChoose(source.getSourceId(), currentPlayer.getId(), game)) { continue; } + + // TODO: add support for AI (50/50), need AI hints mechanic here + currentPlayer.chooseTarget(Outcome.Neutral, target, source, game); + for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filter, currentPlayer.getId(), game)) { + if (target.getTargets().contains(permanent.getId())) { + firstPile.add(permanent); + } else { + secondPile.add(permanent); + } + } + + StringBuilder sb = new StringBuilder("First pile of ").append(currentPlayer.getLogName()).append(": "); + sb.append(firstPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); + + game.informPlayers(sb.toString()); + + sb = new StringBuilder("Second pile of ").append(currentPlayer.getLogName()).append(": "); + sb.append(secondPile.stream().map(Permanent::getLogName).collect(Collectors.joining(", "))); + + game.informPlayers(sb.toString()); + + List> playerPiles = new ArrayList<>(); + playerPiles.add(firstPile); + playerPiles.add(secondPile); + playerPermanents.put(currentPlayer.getId(), playerPiles); + + currentPlayer = nextPlayer; + } + + // For each player, one of their piles is chosen by one of their opponents of their choice + for (Map.Entry>> playerPiles : playerPermanents.entrySet()) { + Player player = game.getPlayer(playerPiles.getKey()); + if (player == null) { continue; } + + FilterPlayer filter = new FilterPlayer("opponent"); + List opponentPredicates = new ArrayList<>(); + for (UUID opponentId : game.getOpponents(player.getId())) { + opponentPredicates.add(new PlayerIdPredicate(opponentId)); + } + filter.add(Predicates.or(opponentPredicates)); + Target target = new TargetPlayer(1, 1, true, filter); + target.setTargetController(player.getId()); + target.setAbilityController(source.getControllerId()); + if (!player.chooseTarget(outcome, target, source, game)) { continue; } + + Player chosenOpponent = game.getPlayer(target.getFirstTarget()); + if (chosenOpponent == null) { continue; } + + List firstPile = playerPiles.getValue().get(0); + List secondPile = playerPiles.getValue().get(1); + game.informPlayers(player.getLogName() + " chose " + chosenOpponent.getLogName() + " to choose their pile"); + if (chosenOpponent.choosePile(outcome, "Piles of " + player.getName(), firstPile, secondPile, game)) { + List> lists = playerPiles.getValue(); + lists.clear(); + lists.add(firstPile); + lists.add(secondPile); + game.informPlayers(player.getLogName() + " will have their first pile destroyed"); + } else { + List> lists = playerPiles.getValue(); + lists.clear(); + lists.add(secondPile); + lists.add(firstPile); + game.informPlayers(player.getLogName() + " will have their second pile destroyed"); + } + } + // Destroy all lands in the chosen piles. Tap all lands in the other piles + for (Map.Entry>> playerPiles : playerPermanents.entrySet()) { + Player player = game.getPlayer(playerPiles.getKey()); + if (player == null) { continue; } + + List pileToSac = playerPiles.getValue().get(0); + List pileToTap = playerPiles.getValue().get(1); + for (Permanent permanent : pileToSac) { + if (permanent != null) { + permanent.destroy(source, game, false); + } + } + for (Permanent permanent : pileToTap) { + if (permanent != null) { + permanent.tap(source, game); + } + } + } + return true; } private UUID getNextPlayerInDirection(boolean left, PlayerList playerList) { diff --git a/Mage.Sets/src/mage/cards/b/BenevolentOffering.java b/Mage.Sets/src/mage/cards/b/BenevolentOffering.java index c6bd066c46..6a33bef478 100644 --- a/Mage.Sets/src/mage/cards/b/BenevolentOffering.java +++ b/Mage.Sets/src/mage/cards/b/BenevolentOffering.java @@ -63,19 +63,18 @@ class BenevolentOfferingEffect1 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Target target = new TargetOpponent(true); - target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game); - Player opponent = game.getPlayer(target.getFirstTarget()); - if (opponent != null) { - Effect effect = new CreateTokenTargetEffect(new SpiritWhiteToken(), 3); - effect.setTargetPointer(new FixedTarget(opponent.getId())); - effect.apply(game, source); - new CreateTokenEffect(new SpiritWhiteToken(), 3).apply(game, source); - return true; - } - } - return false; + if (controller == null) { return false; } + + Target target = new TargetOpponent(true); + target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game); + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent == null) { return false; } + + Effect effect = new CreateTokenTargetEffect(new SpiritWhiteToken(), 3); + effect.setTargetPointer(new FixedTarget(opponent.getId())); + effect.apply(game, source); + new CreateTokenEffect(new SpiritWhiteToken(), 3).apply(game, source); + return true; } } @@ -98,18 +97,18 @@ class BenevolentOfferingEffect2 extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Target target = new TargetOpponent(true); - target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game); - Player opponent = game.getPlayer(target.getFirstTarget()); - if (opponent != null) { - int count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game) * 2; - controller.gainLife(count, game, source); - count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game) * 2; - opponent.gainLife(count, game, source); - return true; - } - } - return false; + if (controller == null) { return false; } + + Target target = new TargetOpponent(true); + target.choose(Outcome.Sacrifice, source.getControllerId(), source.getSourceId(), game); + Player opponent = game.getPlayer(target.getFirstTarget()); + if (opponent == null) { return false; } + + int count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, controller.getId(), game) * 2; + controller.gainLife(count, game, source); + count = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, opponent.getId(), game) * 2; + opponent.gainLife(count, game, source); + + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BenthicExplorers.java b/Mage.Sets/src/mage/cards/b/BenthicExplorers.java index 1b91349da2..bb7a1355e0 100644 --- a/Mage.Sets/src/mage/cards/b/BenthicExplorers.java +++ b/Mage.Sets/src/mage/cards/b/BenthicExplorers.java @@ -67,7 +67,7 @@ public final class BenthicExplorers extends CardImpl { class BenthicExplorersCost extends CostImpl { - TargetLandPermanent target; + private final TargetLandPermanent target; public BenthicExplorersCost(TargetLandPermanent target) { this.target = target; @@ -155,59 +155,60 @@ class BenthicExplorersManaEffect extends ManaEffect { @Override public Mana produceMana(Game game, Ability source) { Mana mana = new Mana(); - if (game == null) { - return mana; - } + if (game == null) { return mana; } + Choice choice = ManaType.getChoiceOfManaTypes(getManaTypes(game, source), false); - if (!choice.getChoices().isEmpty()) { - Player player = game.getPlayer(source.getControllerId()); - if (choice.getChoices().size() == 1) { - choice.setChoice(choice.getChoices().iterator().next()); - } else { - if (player == null - || !player.choose(Outcome.Neutral, choice, game)) { - return mana; - } - } - if (choice.getChoice() != null) { - switch (choice.getChoice()) { - case "Black": - mana.setBlack(1); - break; - case "Blue": - mana.setBlue(1); - break; - case "Red": - mana.setRed(1); - break; - case "Green": - mana.setGreen(1); - break; - case "White": - mana.setWhite(1); - break; - case "Colorless": - mana.setColorless(1); - break; - } + if (choice.getChoices().isEmpty()) { return mana; } + + Player player = game.getPlayer(source.getControllerId()); + if (choice.getChoices().size() == 1) { + choice.setChoice(choice.getChoices().iterator().next()); + } else { + if (player == null + || !player.choose(Outcome.Neutral, choice, game)) { + return mana; } } + + if (choice.getChoice() == null) { return mana; } + + switch (choice.getChoice()) { + case "Black": + mana.setBlack(1); + break; + case "Blue": + mana.setBlue(1); + break; + case "Red": + mana.setRed(1); + break; + case "Green": + mana.setGreen(1); + break; + case "White": + mana.setWhite(1); + break; + case "Colorless": + mana.setColorless(1); + break; + } + return mana; } private Set getManaTypes(Game game, Ability source) { Set types = EnumSet.noneOf(ManaType.class); - if (game == null - || game.getPhase() == null) { + if (game == null || game.getPhase() == null) { return types; } + Permanent land = (Permanent) game.getState().getValue("UntapTargetCost" + source.getSourceId().toString()); - if (land != null) { - Abilities mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD); - for (ActivatedManaAbilityImpl ability : mana) { - if (ability.definesMana(game)) { - types.addAll(ability.getProducableManaTypes(game)); - } + if (land == null) { return types; } + + Abilities mana = land.getAbilities().getActivatedManaAbilities(Zone.BATTLEFIELD); + for (ActivatedManaAbilityImpl ability : mana) { + if (ability.definesMana(game)) { + types.addAll(ability.getProducableManaTypes(game)); } } return types; diff --git a/Mage.Sets/src/mage/cards/b/Berserk.java b/Mage.Sets/src/mage/cards/b/Berserk.java index ab4ac24236..da69f465d8 100644 --- a/Mage.Sets/src/mage/cards/b/Berserk.java +++ b/Mage.Sets/src/mage/cards/b/Berserk.java @@ -127,15 +127,15 @@ class BerserkDestroyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - //create delayed triggered ability - Effect effect = new BerserkDelayedDestroyEffect(); - effect.setTargetPointer(new FixedTarget(this.getTargetPointer().getFirst(game, source), game)); - AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); - game.addDelayedTriggeredAbility(delayedAbility, source); - return true; - } - return false; + if (controller == null) { return false; } + + //create delayed triggered ability + Effect effect = new BerserkDelayedDestroyEffect(); + effect.setTargetPointer(new FixedTarget(this.getTargetPointer().getFirst(game, source), game)); + AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect); + game.addDelayedTriggeredAbility(delayedAbility, source); + + return true; } } @@ -158,15 +158,15 @@ class BerserkDelayedDestroyEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); - if (permanent != null) { - AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); - if (watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game))) { - return permanent.destroy(source, game, false); - } - } - } - return false; + if (controller == null) { return false; } + + Permanent permanent = game.getPermanent(this.getTargetPointer().getFirst(game, source)); + if (permanent == null) { return false; } + + AttackedThisTurnWatcher watcher = game.getState().getWatcher(AttackedThisTurnWatcher.class); + if (watcher == null) { return false; } + + return watcher.getAttackedThisTurnCreatures().contains(new MageObjectReference(permanent, game)) + && permanent.destroy(source, game, false); } } diff --git a/Mage.Sets/src/mage/cards/b/BiomanticMastery.java b/Mage.Sets/src/mage/cards/b/BiomanticMastery.java index 19742a056f..73de4b5d5d 100644 --- a/Mage.Sets/src/mage/cards/b/BiomanticMastery.java +++ b/Mage.Sets/src/mage/cards/b/BiomanticMastery.java @@ -26,7 +26,6 @@ public final class BiomanticMastery extends CardImpl { // Draw a card for each creature target player controls, then draw a card for each creature another target player controls. this.getSpellAbility().addEffect(new BiomanticMasteryEffect()); this.getSpellAbility().addTarget(new TargetPlayer(2)); - } private BiomanticMastery(final BiomanticMastery card) { @@ -58,16 +57,15 @@ class BiomanticMasteryEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - for (UUID playerId : getTargetPointer().getTargets(game, source)) { - Player player = game.getPlayer(playerId); - if (player != null) { - int creatures = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game); - controller.drawCards(creatures, source, game); - } - } - return true; + if (controller == null) { return false; } + + for (UUID playerId : getTargetPointer().getTargets(game, source)) { + Player player = game.getPlayer(playerId); + if (player == null) { continue; } + + int creatures = game.getBattlefield().countAll(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game); + controller.drawCards(creatures, source, game); } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BitterFeud.java b/Mage.Sets/src/mage/cards/b/BitterFeud.java index 8ad9ab2694..8ced30b6de 100644 --- a/Mage.Sets/src/mage/cards/b/BitterFeud.java +++ b/Mage.Sets/src/mage/cards/b/BitterFeud.java @@ -63,23 +63,27 @@ class BitterFeudEntersBattlefieldEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + Permanent permanent = game.getPermanentEntering(source.getSourceId()); - if (controller != null && permanent != null) { - TargetPlayer target = new TargetPlayer(2, 2, true); - controller.chooseTarget(outcome, target, source, game); - Player player1 = game.getPlayer(target.getFirstTarget()); - if (target.getTargets().size() > 1) { - Player player2 = game.getPlayer(target.getTargets().get(1)); - if (player1 != null && player2 != null) { - game.getState().setValue(source.getSourceId() + "_player1", player1); - game.getState().setValue(source.getSourceId() + "_player2", player2); - game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " has chosen " + player1.getLogName() + " and " + player2.getLogName()); - permanent.addInfo("chosen players", "Chosen players: " + player1.getName() + ", " + player2.getName() + "", game); - return true; - } - } - } - return false; + if (permanent == null) { return false; } + + TargetPlayer target = new TargetPlayer(2, 2, true); + controller.chooseTarget(outcome, target, source, game); + Player player1 = game.getPlayer(target.getFirstTarget()); + if (player1 == null) { return false; } + + if (target.getTargets().size() <= 1) { return false; } + + Player player2 = game.getPlayer(target.getTargets().get(1)); + if (player2 == null) { return false; } + + game.getState().setValue(source.getSourceId() + "_player1", player1); + game.getState().setValue(source.getSourceId() + "_player2", player2); + game.informPlayers(permanent.getLogName() + ": " + controller.getLogName() + " has chosen " + player1.getLogName() + " and " + player2.getLogName()); + permanent.addInfo("chosen players", "Chosen players: " + player1.getName() + ", " + player2.getName() + "", game); + + return true; } @Override @@ -91,8 +95,8 @@ class BitterFeudEntersBattlefieldEffect extends OneShotEffect { class BitterFeudEffect extends ReplacementEffectImpl { - Player player1; - Player player2; + private Player player1; + private Player player2; public BitterFeudEffect() { super(Duration.WhileOnBattlefield, Outcome.Damage); @@ -101,6 +105,8 @@ class BitterFeudEffect extends ReplacementEffectImpl { public BitterFeudEffect(final BitterFeudEffect effect) { super(effect); + this.player1 = effect.player1; + this.player2 = effect.player2; } @Override @@ -110,54 +116,50 @@ class BitterFeudEffect extends ReplacementEffectImpl { @Override public boolean checksEventType(GameEvent event, Game game) { - switch (event.getType()) { - case DAMAGE_PERMANENT: - case DAMAGE_PLAYER: - return true; - default: - return false; - } + return event.getType() == GameEvent.EventType.DAMAGE_PERMANENT && event.getType() == GameEvent.EventType.DAMAGE_PLAYER; } @Override public boolean applies(GameEvent event, Ability source, Game game) { player1 = (Player) game.getState().getValue(source.getSourceId() + "_player1"); - player2 = (Player) game.getState().getValue(source.getSourceId() + "_player2"); - if (player1 != null && player2 != null) { - UUID targetPlayerId = null; - switch (event.getType()) { - case DAMAGE_PLAYER: - targetPlayerId = event.getTargetId(); - break; - case DAMAGE_PERMANENT: - Permanent permanent = game.getPermanent(event.getTargetId()); - if (permanent != null) { - targetPlayerId = permanent.getControllerId(); - } - break; - default: - return false; - } + if (player1 == null) { return false; } - if (player1.getId().equals(targetPlayerId) || player2.getId().equals(targetPlayerId)) { - UUID sourcePlayerId = null; - MageObject damageSource = game.getObject(event.getSourceId()); - if (damageSource instanceof StackObject) { - sourcePlayerId = ((StackObject) damageSource).getControllerId(); - } else if (damageSource instanceof Permanent) { - sourcePlayerId = ((Permanent) damageSource).getControllerId(); - } else if (damageSource instanceof Card) { - sourcePlayerId = ((Card) damageSource).getOwnerId(); - } - if (sourcePlayerId != null - && (player1.getId().equals(sourcePlayerId) || player2.getId().equals(sourcePlayerId)) - && !sourcePlayerId.equals(targetPlayerId)) { - return true; - } - } + player2 = (Player) game.getState().getValue(source.getSourceId() + "_player2"); + if (player2 == null) { return false; } + + UUID targetPlayerId; + switch (event.getType()) { + case DAMAGE_PLAYER: + targetPlayerId = event.getTargetId(); + break; + case DAMAGE_PERMANENT: + Permanent permanent = game.getPermanent(event.getTargetId()); + if (permanent == null) { return false; } + + targetPlayerId = permanent.getControllerId(); + break; + default: + return false; } - return false; + if (!player1.getId().equals(targetPlayerId) && !player2.getId().equals(targetPlayerId)) { return false; } + + UUID sourcePlayerId; + MageObject damageSource = game.getObject(event.getSourceId()); + + if (damageSource instanceof StackObject) { + sourcePlayerId = ((StackObject) damageSource).getControllerId(); + } else if (damageSource instanceof Permanent) { + sourcePlayerId = ((Permanent) damageSource).getControllerId(); + } else if (damageSource instanceof Card) { + sourcePlayerId = ((Card) damageSource).getOwnerId(); + } else { + return false; + } + + return sourcePlayerId != null + && (player1.getId().equals(sourcePlayerId) || player2.getId().equals(sourcePlayerId)) + && !sourcePlayerId.equals(targetPlayerId); } @Override diff --git a/Mage.Sets/src/mage/cards/b/BlasphemousAct.java b/Mage.Sets/src/mage/cards/b/BlasphemousAct.java index c67a14b676..defbca5e4a 100644 --- a/Mage.Sets/src/mage/cards/b/BlasphemousAct.java +++ b/Mage.Sets/src/mage/cards/b/BlasphemousAct.java @@ -57,12 +57,12 @@ class BlasphemousCostReductionEffect extends CostModificationEffectImpl { @Override public boolean apply(Game game, Ability source, Ability abilityToModify) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - int reductionAmount = game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getSourceId(), source.getControllerId(), game); - CardUtil.reduceCost(abilityToModify, reductionAmount); - return true; - } - return false; + if (player == null) { return false; } + + int reductionAmount = game.getBattlefield().count(StaticFilters.FILTER_PERMANENT_CREATURE, source.getSourceId(), source.getControllerId(), game); + CardUtil.reduceCost(abilityToModify, reductionAmount); + + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BlazingEffigy.java b/Mage.Sets/src/mage/cards/b/BlazingEffigy.java index 68c7af9496..c64d4e9826 100644 --- a/Mage.Sets/src/mage/cards/b/BlazingEffigy.java +++ b/Mage.Sets/src/mage/cards/b/BlazingEffigy.java @@ -89,15 +89,16 @@ class BlazingEffigyWatcher extends Watcher { @Override public void watch(GameEvent event, Game game) { - if (event.getType() == GameEvent.EventType.DAMAGED_PERMANENT) { - if (!event.getSourceId().equals(event.getTargetId())) { - MageObjectReference damageSourceRef = new MageObjectReference(event.getSourceId(), game); - MageObjectReference damageTargetRef = new MageObjectReference(event.getTargetId(), game); - if (game.getPermanentOrLKIBattlefield(event.getSourceId()) != null && game.getPermanentOrLKIBattlefield(event.getSourceId()).getName().equals("Blazing Effigy")) { - damagedObjects.putIfAbsent(damageTargetRef, 0); - damagedObjects.compute(damageTargetRef, (k, damage) -> damage + event.getAmount()); - } - } + if (event.getType() != GameEvent.EventType.DAMAGED_PERMANENT) { return; } + + if (event.getSourceId().equals(event.getTargetId())) { return; } + + // TODO: Should damageSourceRef be used for anything? + MageObjectReference damageSourceRef = new MageObjectReference(event.getSourceId(), game); + MageObjectReference damageTargetRef = new MageObjectReference(event.getTargetId(), game); + if (game.getPermanentOrLKIBattlefield(event.getSourceId()) != null && game.getPermanentOrLKIBattlefield(event.getSourceId()).getName().equals("Blazing Effigy")) { + damagedObjects.putIfAbsent(damageTargetRef, 0); + damagedObjects.compute(damageTargetRef, (k, damage) -> damage + event.getAmount()); } } diff --git a/Mage.Sets/src/mage/cards/b/BlinkmothInfusion.java b/Mage.Sets/src/mage/cards/b/BlinkmothInfusion.java index a02615bfd7..9bc1c7020e 100644 --- a/Mage.Sets/src/mage/cards/b/BlinkmothInfusion.java +++ b/Mage.Sets/src/mage/cards/b/BlinkmothInfusion.java @@ -23,9 +23,9 @@ public final class BlinkmothInfusion extends CardImpl { public BlinkmothInfusion(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.INSTANT},"{12}{U}{U}"); - // Affinity for artifacts this.addAbility(new AffinityForArtifactsAbility()); + // Untap all artifacts. this.getSpellAbility().addEffect(new UntapAllArtifactsEffect()); } @@ -54,13 +54,12 @@ class UntapAllArtifactsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - for (Permanent artifact: game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), game)) { - artifact.untap(game); - } - return true; + if (player == null) { return false; } + + for (Permanent artifact: game.getBattlefield().getAllActivePermanents(new FilterArtifactPermanent(), game)) { + artifact.untap(game); } - return false; + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BloodBaronOfVizkopa.java b/Mage.Sets/src/mage/cards/b/BloodBaronOfVizkopa.java index 68b1873d0e..0137ca84c6 100644 --- a/Mage.Sets/src/mage/cards/b/BloodBaronOfVizkopa.java +++ b/Mage.Sets/src/mage/cards/b/BloodBaronOfVizkopa.java @@ -32,7 +32,6 @@ public final class BloodBaronOfVizkopa extends CardImpl { // As long as you have 30 or more life and an opponent has 10 or less life, Blood Baron of Vizkopa gets +6/+6 and has flying. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new BloodBaronOfVizkopaEffect())); - } private BloodBaronOfVizkopa(final BloodBaronOfVizkopa card) { @@ -53,7 +52,7 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { staticText = "As long as you have 30 or more life and an opponent has 10 or less life, {this} gets +6/+6 and has flying"; } - public BloodBaronOfVizkopaEffect(final BloodBaronOfVizkopaEffect effect) { + private BloodBaronOfVizkopaEffect(final BloodBaronOfVizkopaEffect effect) { super(effect); } @@ -64,41 +63,45 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { @Override public boolean apply(Layer layer, SubLayer sublayer, Ability source, Game game) { - if (conditionState(source, game)) { - Permanent creature = game.getPermanent(source.getSourceId()); - if (creature != null) { - switch (layer) { - case PTChangingEffects_7: - if (sublayer == SubLayer.ModifyPT_7c) { - creature.addPower(6); - creature.addToughness(6); - } - break; - case AbilityAddingRemovingEffects_6: - if (sublayer == SubLayer.NA) { - creature.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); - } - break; - default: + if (!conditionState(source, game)) { return false; } + + Permanent creature = game.getPermanent(source.getSourceId()); + if (creature == null) { return false; } + + switch (layer) { + case PTChangingEffects_7: + if (sublayer == SubLayer.ModifyPT_7c) { + creature.addPower(6); + creature.addToughness(6); } - return true; - } + break; + case AbilityAddingRemovingEffects_6: + if (sublayer == SubLayer.NA) { + creature.addAbility(FlyingAbility.getInstance(), source.getSourceId(), game); + } + break; + default: + return false; } - return false; + + return true; } - protected boolean conditionState(Ability source, Game game) { + private boolean conditionState(Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null && controller.getLife() >= 30) { - for (UUID opponentId : game.getState().getPlayersInRange(controller.getId(), game)) { - if (controller.hasOpponent(opponentId, game)) { - Player opponent = game.getPlayer(opponentId); - if (opponent != null && opponent.getLife() < 11) { - return true; - } - } - } + if (controller == null) { return false; } + + if (controller.getLife() < 30) { return false; } + + for (UUID opponentId : game.getState().getPlayersInRange(controller.getId(), game)) { + if (!controller.hasOpponent(opponentId, game)) { return false; } + + Player opponent = game.getPlayer(opponentId); + if (opponent == null) { return false; } + + return opponent.getLife() < 11; } + return false; } @@ -109,8 +112,6 @@ class BloodBaronOfVizkopaEffect extends ContinuousEffectImpl { @Override public boolean hasLayer(Layer layer) { - return (layer == Layer.AbilityAddingRemovingEffects_6 || layer == layer.PTChangingEffects_7); - + return (layer == Layer.AbilityAddingRemovingEffects_6 || layer == Layer.PTChangingEffects_7); } - } diff --git a/Mage.Sets/src/mage/cards/b/BloodlineShaman.java b/Mage.Sets/src/mage/cards/b/BloodlineShaman.java index 08eb1ff2a0..b561b9795a 100644 --- a/Mage.Sets/src/mage/cards/b/BloodlineShaman.java +++ b/Mage.Sets/src/mage/cards/b/BloodlineShaman.java @@ -67,31 +67,34 @@ class BloodlineShamanEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + MageObject sourceObject = game.getObject(source.getSourceId()); + if (sourceObject == null) { return false; } + Choice typeChoice = new ChoiceCreatureType(sourceObject); - if (controller != null && sourceObject != null && controller.choose(outcome, typeChoice, game)) { - game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); - FilterCard filterSubtype = new FilterCard(); - filterSubtype.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); + if (!controller.choose(outcome, typeChoice, game)) { return false; } - // Reveal the top card of your library. - if (controller.getLibrary().hasCards()) { - Card card = controller.getLibrary().getFromTop(game); - Cards cards = new CardsImpl(card); - controller.revealCards(sourceObject.getIdName(), cards, game); + game.informPlayers(sourceObject.getLogName() + " chosen type: " + typeChoice.getChoice()); + FilterCard filterSubtype = new FilterCard(); + filterSubtype.add(SubType.byDescription(typeChoice.getChoice()).getPredicate()); - if (card != null) { - // If that card is a creature card of the chosen type, put it into your hand. - if (filterSubtype.match(card, game)) { - controller.moveCards(card, Zone.HAND, source, game); - // Otherwise, put it into your graveyard. - } else { - controller.moveCards(card, Zone.GRAVEYARD, source, game); - } + // Reveal the top card of your library. + if (controller.getLibrary().hasCards()) { + Card card = controller.getLibrary().getFromTop(game); + Cards cards = new CardsImpl(card); + controller.revealCards(sourceObject.getIdName(), cards, game); + + if (card != null) { + // If that card is a creature card of the chosen type, put it into your hand. + if (filterSubtype.match(card, game)) { + controller.moveCards(card, Zone.HAND, source, game); + // Otherwise, put it into your graveyard. + } else { + controller.moveCards(card, Zone.GRAVEYARD, source, game); } } - return true; } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/Blustersquall.java b/Mage.Sets/src/mage/cards/b/Blustersquall.java index 1611be826c..f81550cbb7 100644 --- a/Mage.Sets/src/mage/cards/b/Blustersquall.java +++ b/Mage.Sets/src/mage/cards/b/Blustersquall.java @@ -30,8 +30,7 @@ public final class Blustersquall extends CardImpl { this.getSpellAbility().addEffect(new TapTargetEffect()); // Overload {3}{U} (You may cast this spell for its overload cost. If you do, change its text by replacing all instances of "target" with "each.") - this.addAbility(new OverloadAbility(this, new BlustersqallTapAllEffect(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL), new ManaCostsImpl("{3}{U}"))); - + this.addAbility(new OverloadAbility(this, new BlustersqallTapAllEffect(), new ManaCostsImpl("{3}{U}"))); } private Blustersquall(final Blustersquall card) { @@ -46,22 +45,18 @@ public final class Blustersquall extends CardImpl { class BlustersqallTapAllEffect extends OneShotEffect { - protected FilterCreaturePermanent filter; - - BlustersqallTapAllEffect(FilterCreaturePermanent filter) { + BlustersqallTapAllEffect() { super(Outcome.Tap); - this.filter = filter; staticText = "Tap each creature you don't control"; } private BlustersqallTapAllEffect(final BlustersqallTapAllEffect effect) { super(effect); - this.filter = effect.filter; } @Override public boolean apply(Game game, Ability source) { - for (Permanent creature : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + for (Permanent creature : game.getBattlefield().getActivePermanents(StaticFilters.FILTER_CREATURE_YOU_DONT_CONTROL, source.getControllerId(), source.getSourceId(), game)) { creature.tap(source, game); } return true; diff --git a/Mage.Sets/src/mage/cards/b/BoneyardScourge.java b/Mage.Sets/src/mage/cards/b/BoneyardScourge.java index 12aeba5106..f992ca337d 100644 --- a/Mage.Sets/src/mage/cards/b/BoneyardScourge.java +++ b/Mage.Sets/src/mage/cards/b/BoneyardScourge.java @@ -64,7 +64,7 @@ public final class BoneyardScourge extends CardImpl { class DiesWhileInGraveyardTriggeredAbility extends TriggeredAbilityImpl { - protected FilterCreaturePermanent filter; + private final FilterCreaturePermanent filter; public DiesWhileInGraveyardTriggeredAbility(Effect effect, FilterCreaturePermanent filter) { super(Zone.GRAVEYARD, effect, false); @@ -89,22 +89,19 @@ class DiesWhileInGraveyardTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; + if (!zEvent.isDiesEvent()) { return false; } + for (Zone z : Zone.values()) { if (game.getShortLivingLKI(sourceId, z) && z != Zone.GRAVEYARD) { return false; } } - if (zEvent.isDiesEvent()) { - if (filter.match(zEvent.getTarget(), sourceId, controllerId, game)) { - return true; - } - } - return false; + + return filter.match(zEvent.getTarget(), sourceId, controllerId, game); } @Override public String getTriggerPhrase() { return "Whenever " + filter.getMessage() + " dies while {this} is in your graveyard, " ; } - } diff --git a/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java b/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java index 24766e3eca..058afd270a 100644 --- a/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java +++ b/Mage.Sets/src/mage/cards/b/BoonweaverGiant.java @@ -54,7 +54,8 @@ class BoonweaverGiantEffect extends OneShotEffect { public BoonweaverGiantEffect() { super(Outcome.UnboostCreature); - this.staticText = "you may search your graveyard, hand, and/or library for an Aura card and put it onto the battlefield attached to {this}. If you search your library this way, shuffle."; + this.staticText = "you may search your graveyard, hand, and/or library for an Aura card and put it onto the battlefield attached to {this}." + + "If you search your library this way, shuffle."; } public BoonweaverGiantEffect(final BoonweaverGiantEffect effect) { @@ -69,45 +70,40 @@ class BoonweaverGiantEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } + if (controller == null) { return false; } FilterCard filter = new FilterCard("Aura card"); filter.add(CardType.ENCHANTMENT.getPredicate()); filter.add(SubType.AURA.getPredicate()); Card card = null; - Zone zone = null; + + // Choose card from graveyard if (controller.chooseUse(Outcome.Neutral, "Search your graveyard for an Aura card?", source, game)) { TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(filter); if (controller.choose(Outcome.PutCardInPlay, controller.getGraveyard(), target, game)) { card = game.getCard(target.getFirstTarget()); - if (card != null) { - zone = Zone.GRAVEYARD; - } } } + + // Choose card from your hand if (card == null && controller.chooseUse(Outcome.Neutral, "Search your Hand for an Aura card?", source, game)) { TargetCardInHand target = new TargetCardInHand(filter); if (controller.choose(Outcome.PutCardInPlay, controller.getHand(), target, game)) { card = game.getCard(target.getFirstTarget()); - if (card != null) { - zone = Zone.HAND; - } } } + + // Choose a card from your library if (card == null) { TargetCardInLibrary target = new TargetCardInLibrary(filter); if (controller.searchLibrary(target, source, game)) { card = game.getCard(target.getFirstTarget()); - if (card != null) { - zone = Zone.LIBRARY; - } } controller.shuffleLibrary(source, game); } - // aura card found - attach it + + // Aura card found - attach it if (card != null) { Permanent permanent = game.getPermanent(source.getSourceId()); if (permanent != null) { diff --git a/Mage.Sets/src/mage/cards/b/BosiumStrip.java b/Mage.Sets/src/mage/cards/b/BosiumStrip.java index bc0a5e4dc7..179cfaf857 100644 --- a/Mage.Sets/src/mage/cards/b/BosiumStrip.java +++ b/Mage.Sets/src/mage/cards/b/BosiumStrip.java @@ -109,13 +109,13 @@ class BosiumStripReplacementEffect extends ReplacementEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card card = (Card) game.getState().getValue("BosiumStrip"); - if (card != null) { - ((ZoneChangeEvent) event).setToZone(Zone.EXILED); - } - } - return false; + if (controller == null) { return false; } + + Card card = (Card) game.getState().getValue("BosiumStrip"); + if (card == null) { return false; } + + ((ZoneChangeEvent) event).setToZone(Zone.EXILED); + return true; } @Override @@ -126,16 +126,16 @@ class BosiumStripReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.getToZone() == Zone.GRAVEYARD) { - Card card = game.getCard(event.getSourceId()); - if (card != null - && StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game)) { - CastFromGraveyardWatcher watcher = game.getState().getWatcher(CastFromGraveyardWatcher.class); - return watcher != null - && watcher.spellWasCastFromGraveyard(event.getTargetId(), - game.getState().getZoneChangeCounter(event.getTargetId())); - } - } - return false; + if (zEvent.getToZone() != Zone.GRAVEYARD) { return false; } + + Card card = game.getCard(event.getSourceId()); + if (card == null) { return false; } + + if (!StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY.match(card, game)) { return false; } + + CastFromGraveyardWatcher watcher = game.getState().getWatcher(CastFromGraveyardWatcher.class); + return watcher != null + && watcher.spellWasCastFromGraveyard(event.getTargetId(), + game.getState().getZoneChangeCounter(event.getTargetId())); } } diff --git a/Mage.Sets/src/mage/cards/b/BountyOfTheLuxa.java b/Mage.Sets/src/mage/cards/b/BountyOfTheLuxa.java index 29297c7beb..6725f4af51 100644 --- a/Mage.Sets/src/mage/cards/b/BountyOfTheLuxa.java +++ b/Mage.Sets/src/mage/cards/b/BountyOfTheLuxa.java @@ -26,9 +26,10 @@ public final class BountyOfTheLuxa extends CardImpl { public BountyOfTheLuxa(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}{U}"); - //At the beginning of your precombat main phase, remove all flood counters from Bounty of the Luxa. If no counters were removed this way, put a flood counter on Bounty of the Luxa and draw a card. Otherwise, add {C}{G}{U}. + // At the beginning of your precombat main phase, remove all flood counters from Bounty of the Luxa. + // If no counters were removed this way, put a flood counter on Bounty of the Luxa and draw a card. + // Otherwise, add {C}{G}{U}. this.addAbility(new BeginningOfPreCombatMainTriggeredAbility(new BountyOfTheLuxaEffect(), TargetController.YOU, false)); - } private BountyOfTheLuxa(final BountyOfTheLuxa card) { @@ -46,7 +47,9 @@ class BountyOfTheLuxaEffect extends OneShotEffect { public BountyOfTheLuxaEffect() { super(Outcome.Benefit); - staticText = "remove all flood counters from {this}. If no counters were removed this way, put a flood counter on {this} and draw a card. Otherwise, add {C}{G}{U}"; + staticText = "remove all flood counters from {this}. " + + "If no counters were removed this way, put a flood counter on {this} and draw a card. " + + "Otherwise, add {C}{G}{U}"; } public BountyOfTheLuxaEffect(final BountyOfTheLuxaEffect effect) { @@ -65,26 +68,25 @@ class BountyOfTheLuxaEffect extends OneShotEffect { if (bountyOfLuxa != null && bountyOfLuxa.getZoneChangeCounter(game) != source.getSourceObjectZoneChangeCounter()) { bountyOfLuxa = null; } - if (controller != null) { - if (bountyOfLuxa != null - && bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) > 0) { - bountyOfLuxa.removeCounters(CounterType.FLOOD.createInstance(bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD)), source, game); - if (bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) == 0) { - Mana manaToAdd = new Mana(); - manaToAdd.increaseColorless(); - manaToAdd.increaseGreen(); - manaToAdd.increaseBlue(); - controller.getManaPool().addMana(manaToAdd, game, source); - } - } else { - if (bountyOfLuxa != null) { - new AddCountersSourceEffect(CounterType.FLOOD.createInstance()).apply(game, source); - } - controller.drawCards(1, source, game); + if (controller == null) { return false; } + + if (bountyOfLuxa != null + && bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) > 0) { + bountyOfLuxa.removeCounters(CounterType.FLOOD.createInstance(bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD)), source, game); + if (bountyOfLuxa.getCounters(game).getCount(CounterType.FLOOD) == 0) { + Mana manaToAdd = new Mana(); + manaToAdd.increaseColorless(); + manaToAdd.increaseGreen(); + manaToAdd.increaseBlue(); + controller.getManaPool().addMana(manaToAdd, game, source); } - return true; + } else { + if (bountyOfLuxa != null) { + new AddCountersSourceEffect(CounterType.FLOOD.createInstance()).apply(game, source); + } + controller.drawCards(1, source, game); } - return false; + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BraceForImpact.java b/Mage.Sets/src/mage/cards/b/BraceForImpact.java index 63e33ff055..cf43d37fb2 100644 --- a/Mage.Sets/src/mage/cards/b/BraceForImpact.java +++ b/Mage.Sets/src/mage/cards/b/BraceForImpact.java @@ -72,24 +72,23 @@ class BraceForImpactPreventDamageTargetEffect extends PreventionEffectImpl { @Override public boolean replaceEvent(GameEvent event, Ability source, Game game) { GameEvent preventEvent = new PreventDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), event.getAmount(), ((DamageEvent) event).isCombatDamage()); - if (!game.replaceEvent(preventEvent)) { - int prevented = 0; - int damage = event.getAmount(); - event.setAmount(0); - game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); - prevented = damage; + if (game.replaceEvent(preventEvent)) { return false; } + int prevented; + int damage = event.getAmount(); + event.setAmount(0); + game.fireEvent(new PreventedDamageEvent(event.getTargetId(), source.getSourceId(), source, source.getControllerId(), damage)); + prevented = damage; - // add counters now - if (prevented > 0) { - Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); - if (targetPermanent != null) { - targetPermanent.addCounters(CounterType.P1P1.createInstance(prevented), source.getControllerId(), source, game); - game.informPlayers("Brace for Impact: Prevented " + prevented + " damage "); - game.informPlayers("Brace for Impact: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName()); - } + // add counters now + if (prevented > 0) { + Permanent targetPermanent = game.getPermanent(source.getTargets().getFirstTarget()); + if (targetPermanent != null) { + targetPermanent.addCounters(CounterType.P1P1.createInstance(prevented), source.getControllerId(), source, game); + game.informPlayers("Brace for Impact: Prevented " + prevented + " damage "); + game.informPlayers("Brace for Impact: Adding " + prevented + " +1/+1 counters to " + targetPermanent.getName()); } } - return false; + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java b/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java index 7ec702193b..da663d202f 100644 --- a/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java +++ b/Mage.Sets/src/mage/cards/b/BridgeFromBelow.java @@ -57,7 +57,7 @@ public final class BridgeFromBelow extends CardImpl { class BridgeFromBelowAbility extends TriggeredAbilityImpl { - protected FilterCreaturePermanent filter; + private final FilterCreaturePermanent filter; public BridgeFromBelowAbility(Effect effect, FilterCreaturePermanent filter) { super(Zone.GRAVEYARD, effect, false); @@ -82,14 +82,12 @@ class BridgeFromBelowAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.isDiesEvent()) { - Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (permanent != null - && filter.match(permanent, sourceId, controllerId, game)) { - return true; - } - } - return false; + if (!zEvent.isDiesEvent()) { return false; } + + Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); + if (permanent == null) { return false; } + + return filter.match(permanent, sourceId, controllerId, game); } @Override diff --git a/Mage.Sets/src/mage/cards/b/Brightflame.java b/Mage.Sets/src/mage/cards/b/Brightflame.java index cdb83cbc2f..1b6a305407 100644 --- a/Mage.Sets/src/mage/cards/b/Brightflame.java +++ b/Mage.Sets/src/mage/cards/b/Brightflame.java @@ -64,24 +64,24 @@ class BrightflameEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Permanent target = game.getPermanent(targetPointer.getFirst(game, source)); int damageDealt = 0; - if (target != null) { - ObjectColor color = target.getColor(game); - damageDealt += target.damage(amount.calculate(game, source, this), source.getSourceId(), source, game); - for (Permanent p : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { - if (!target.getId().equals(p.getId()) && p.getColor(game).shares(color)) { - damageDealt += p.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, true); - } - } - Player you = game.getPlayer(source.getControllerId()); - if (you != null && damageDealt > 0) { - you.gainLife(damageDealt, game, source); + Permanent target = game.getPermanent(targetPointer.getFirst(game, source)); + if (target == null) { return false; } + + ObjectColor color = target.getColor(game); + damageDealt += target.damage(amount.calculate(game, source, this), source.getSourceId(), source, game); + for (Permanent p : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), game)) { + if (!target.getId().equals(p.getId()) && p.getColor(game).shares(color)) { + damageDealt += p.damage(amount.calculate(game, source, this), source.getSourceId(), source, game, false, true); } - return true; } - return false; + + Player you = game.getPlayer(source.getControllerId()); + if (you != null && damageDealt > 0) { + you.gainLife(damageDealt, game, source); + } + return true; } @Override diff --git a/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java b/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java index f0b431005c..0217207233 100644 --- a/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java +++ b/Mage.Sets/src/mage/cards/b/BrimazKingOfOreskos.java @@ -75,31 +75,30 @@ class BrimazKingOfOreskosEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } - if (controller != null) { - Token token = new CatSoldierCreatureToken(); - token.putOntoBattlefield(1, game, source, source.getControllerId()); - Permanent attackingCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); - if (attackingCreature != null && game.getState().getCombat() != null) { - // Possible ruling (see Aetherplasm) - // The token you created is blocking the attacking creature, - // even if the block couldn't legally be declared (for example, if that creature - // enters the battlefield tapped, or it can't block, or the attacking creature - // has protection from it) - CombatGroup combatGroup = game.getState().getCombat().findGroup(attackingCreature.getId()); - if (combatGroup != null) { - for (UUID tokenId : token.getLastAddedTokenIds()) { - Permanent catToken = game.getPermanent(tokenId); - if (catToken != null) { - combatGroup.addBlocker(tokenId, source.getControllerId(), game); - game.getCombat().addBlockingGroup(tokenId, attackingCreature.getId(), controller.getId(), game); - } - } - combatGroup.pickBlockerOrder(attackingCreature.getControllerId(), game); - } - } - return true; + Token token = new CatSoldierCreatureToken(); + token.putOntoBattlefield(1, game, source, source.getControllerId()); + Permanent attackingCreature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (attackingCreature == null || game.getState().getCombat() == null) { return true; } + + // Possible ruling (see Aetherplasm) + // The token you created is blocking the attacking creature, + // even if the block couldn't legally be declared (for example, if that creature + // enters the battlefield tapped, or it can't block, or the attacking creature + // has protection from it) + CombatGroup combatGroup = game.getState().getCombat().findGroup(attackingCreature.getId()); + if (combatGroup == null) { return true; } + + for (UUID tokenId : token.getLastAddedTokenIds()) { + Permanent catToken = game.getPermanent(tokenId); + if (catToken == null) { continue; } + + combatGroup.addBlocker(tokenId, source.getControllerId(), game); + game.getCombat().addBlockingGroup(tokenId, attackingCreature.getId(), controller.getId(), game); } - return false; + combatGroup.pickBlockerOrder(attackingCreature.getControllerId(), game); + + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BrineHag.java b/Mage.Sets/src/mage/cards/b/BrineHag.java index fde66fdf7a..af7b561d76 100644 --- a/Mage.Sets/src/mage/cards/b/BrineHag.java +++ b/Mage.Sets/src/mage/cards/b/BrineHag.java @@ -68,26 +68,27 @@ class BrineHagEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + Permanent sourcePermanent = game.getPermanentOrLKIBattlefield(source.getSourceId()); - if (sourcePermanent != null) { - List list = new ArrayList<>(); - for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { - Player player = game.getPlayer(playerId); - if (player != null) { - for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) { - if (sourcePermanent.getDealtDamageByThisTurn().contains(new MageObjectReference(creature.getId(), game))) { - list.add(creature); - } - } + if (sourcePermanent == null) { return false; } + + List list = new ArrayList<>(); + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { + Player player = game.getPlayer(playerId); + if (player == null) { continue; } + + for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, playerId, game)) { + if (sourcePermanent.getDealtDamageByThisTurn().contains(new MageObjectReference(creature.getId(), game))) { + list.add(creature); } } - if (!list.isEmpty()) { - FilterCreaturePermanent filter = new FilterCreaturePermanent(); - filter.add(new PermanentInListPredicate(list)); - game.addEffect(new SetPowerToughnessAllEffect(0, 2, Duration.Custom, filter, true), source); - } - return true; } - return false; + if (!list.isEmpty()) { + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new PermanentInListPredicate(list)); + game.addEffect(new SetPowerToughnessAllEffect(0, 2, Duration.Custom, filter, true), source); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/b/BroodhatchNantuko.java b/Mage.Sets/src/mage/cards/b/BroodhatchNantuko.java index 81ce22ee1c..3bd8e8e4a4 100644 --- a/Mage.Sets/src/mage/cards/b/BroodhatchNantuko.java +++ b/Mage.Sets/src/mage/cards/b/BroodhatchNantuko.java @@ -32,8 +32,9 @@ public final class BroodhatchNantuko extends CardImpl { // Whenever Broodhatch Nantuko is dealt damage, you may create that many 1/1 green Insect creature tokens. this.addAbility(new DealtDamageToSourceTriggeredAbility(new BroodhatchNantukoDealDamageEffect(), true, false)); + // Morph {2}{G} - this.addAbility(new MorphAbility(this, new ManaCostsImpl("{2}{G}"))); + this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{2}{G}"))); } private BroodhatchNantuko(final BroodhatchNantuko card) { @@ -65,12 +66,11 @@ class BroodhatchNantukoDealDamageEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - int amount = (Integer) getValue("damage"); - if (amount > 0) { - return new CreateTokenEffect(new InsectToken(), amount).apply(game, source); - } - } - return false; + if (player == null) { return false; } + + int amount = (Integer) getValue("damage"); + if (amount <= 0) { return false; } + + return new CreateTokenEffect(new InsectToken(), amount).apply(game, source); } } diff --git a/Mage.Sets/src/mage/cards/b/BroodmateDragon.java b/Mage.Sets/src/mage/cards/b/BroodmateDragon.java index cd337e7690..cee58d55f3 100644 --- a/Mage.Sets/src/mage/cards/b/BroodmateDragon.java +++ b/Mage.Sets/src/mage/cards/b/BroodmateDragon.java @@ -19,7 +19,7 @@ import mage.game.permanent.token.DragonToken; */ public final class BroodmateDragon extends CardImpl { - private static DragonToken dragonToken = new DragonToken(); + private static final DragonToken dragonToken = new DragonToken(); public BroodmateDragon(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{R}{G}"); diff --git a/Mage.Sets/src/mage/cards/b/BrunaLightOfAlabaster.java b/Mage.Sets/src/mage/cards/b/BrunaLightOfAlabaster.java index 9329557a7b..f7055c7489 100644 --- a/Mage.Sets/src/mage/cards/b/BrunaLightOfAlabaster.java +++ b/Mage.Sets/src/mage/cards/b/BrunaLightOfAlabaster.java @@ -75,8 +75,10 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - UUID bruna = source.getSourceId(); Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + + UUID bruna = source.getSourceId(); FilterPermanent filterAura = new FilterPermanent("Aura"); FilterCard filterAuraCard = new FilterCard("Aura card"); @@ -88,13 +90,9 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { filterAuraCard.add(SubType.AURA.getPredicate()); filterAuraCard.add(new AuraCardCanAttachToPermanentId(bruna)); - if (controller == null) { - return false; - } Permanent sourcePermanent = game.getPermanent(source.getSourceId()); - if (sourcePermanent == null) { - return false; - } + if (sourcePermanent == null) { return false; } + List fromBattlefield = new ArrayList<>(); List fromHandGraveyard = new ArrayList<>(); @@ -104,16 +102,17 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { && controller.chooseUse(Outcome.Benefit, "Attach an Aura from the battlefield?", source, game)) { Target targetAura = new TargetPermanent(filterAura); targetAura.setNotTarget(true); - if (controller.choose(Outcome.Benefit, targetAura, source.getSourceId(), game)) { - Permanent aura = game.getPermanent(targetAura.getFirstTarget()); - if (aura != null) { - Target target = aura.getSpellAbility().getTargets().get(0); - if (target != null) { - fromBattlefield.add(aura); - filterAura.add(Predicates.not(new CardIdPredicate(aura.getId()))); - } - } - } + if (!controller.choose(Outcome.Benefit, targetAura, source.getSourceId(), game)) { continue; } + + Permanent aura = game.getPermanent(targetAura.getFirstTarget()); + if (aura == null) { continue; } + + Target target = aura.getSpellAbility().getTargets().get(0); + if (target == null) { continue; } + + fromBattlefield.add(aura); + filterAura.add(Predicates.not(new CardIdPredicate(aura.getId()))); + countBattlefield = game.getBattlefield().getAllActivePermanents(filterAura, game).size() - sourcePermanent.getAttachments().size(); } @@ -122,16 +121,16 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { && countHand > 0 && controller.chooseUse(Outcome.Benefit, "Attach an Aura from your hand?", source, game)) { TargetCard targetAura = new TargetCard(Zone.HAND, filterAuraCard); - if (controller.choose(Outcome.Benefit, controller.getHand(), targetAura, game)) { - Card aura = game.getCard(targetAura.getFirstTarget()); - if (aura != null) { - Target target = aura.getSpellAbility().getTargets().get(0); - if (target != null) { - fromHandGraveyard.add(aura); - filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId()))); - } - } - } + if (!controller.choose(Outcome.Benefit, controller.getHand(), targetAura, game)) { continue; } + + Card aura = game.getCard(targetAura.getFirstTarget()); + if (aura == null) { continue; } + + Target target = aura.getSpellAbility().getTargets().get(0); + if (target == null) { continue; } + fromHandGraveyard.add(aura); + filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId()))); + countHand = controller.getHand().count(filterAuraCard, game); } @@ -140,18 +139,20 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { && countGraveyard > 0 && controller.chooseUse(Outcome.Benefit, "Attach an Aura from your graveyard?", source, game)) { TargetCard targetAura = new TargetCard(Zone.GRAVEYARD, filterAuraCard); - if (controller.choose(Outcome.Benefit, controller.getGraveyard(), targetAura, game)) { - Card aura = game.getCard(targetAura.getFirstTarget()); - if (aura != null) { - Target target = aura.getSpellAbility().getTargets().get(0); - if (target != null) { - fromHandGraveyard.add(aura); - filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId()))); - } - } - } + if (!controller.choose(Outcome.Benefit, controller.getGraveyard(), targetAura, game)) { continue; } + + Card aura = game.getCard(targetAura.getFirstTarget()); + if (aura == null) { continue; } + + Target target = aura.getSpellAbility().getTargets().get(0); + if (target == null) { continue; } + + fromHandGraveyard.add(aura); + filterAuraCard.add(Predicates.not(new CardIdPredicate(aura.getId()))); + countGraveyard = controller.getGraveyard().count(filterAuraCard, game); } + // Move permanents for (Permanent aura : fromBattlefield) { Permanent attachedTo = game.getPermanent(aura.getAttachedTo()); @@ -160,13 +161,14 @@ class BrunaLightOfAlabasterEffect extends OneShotEffect { } sourcePermanent.addAttachment(aura.getId(), source, game); } + // Move cards for (Card aura : fromHandGraveyard) { - if (aura != null) { - game.getState().setValue("attachTo:" + aura.getId(), sourcePermanent); - controller.moveCards(aura, Zone.BATTLEFIELD, source, game); - sourcePermanent.addAttachment(aura.getId(), source, game); - } + if (aura == null) { continue; } + + game.getState().setValue("attachTo:" + aura.getId(), sourcePermanent); + controller.moveCards(aura, Zone.BATTLEFIELD, source, game); + sourcePermanent.addAttachment(aura.getId(), source, game); } return true; } diff --git a/Mage.Sets/src/mage/cards/b/BudokaGardener.java b/Mage.Sets/src/mage/cards/b/BudokaGardener.java index 58d601a750..a149b51f6c 100644 --- a/Mage.Sets/src/mage/cards/b/BudokaGardener.java +++ b/Mage.Sets/src/mage/cards/b/BudokaGardener.java @@ -70,13 +70,12 @@ class BudokaGardenerEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - if (game.getBattlefield().count(filterLands, source.getSourceId(), source.getControllerId(), game) >= 10) { - new FlipSourceEffect(new DokaiWeaverofLife()).apply(game, source); - } - return true; + if (controller == null) { return false; } + if (game.getBattlefield().count(filterLands, source.getSourceId(), source.getControllerId(), game) < 10) { + return false; } - return false; + + return new FlipSourceEffect(new DokaiWeaverofLife()).apply(game, source); } @Override diff --git a/Mage.Sets/src/mage/cards/b/BullElephant.java b/Mage.Sets/src/mage/cards/b/BullElephant.java index 2328b9e52f..75c8a137ba 100644 --- a/Mage.Sets/src/mage/cards/b/BullElephant.java +++ b/Mage.Sets/src/mage/cards/b/BullElephant.java @@ -15,7 +15,7 @@ import java.util.UUID; public final class BullElephant extends CardImpl { - private static FilterControlledLandPermanent controlledForest = new FilterControlledLandPermanent("Forests"); + private static final FilterControlledLandPermanent controlledForest = new FilterControlledLandPermanent("Forests"); static { controlledForest.add(SubType.FOREST.getPredicate()); @@ -25,10 +25,14 @@ public final class BullElephant extends CardImpl { public BullElephant(UUID cardId, CardSetInfo cardSetInfo) { super(cardId, cardSetInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); this.subtype.add(SubType.ELEPHANT); + power = new MageInt(4); toughness = new MageInt(4); -//When Bull Elephant enters the battlefield, sacrifice it unless you return two Forests you control to their owner's hand. - addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost(new TargetControlledPermanent(2, 2, controlledForest, false))))); + + // When Bull Elephant enters the battlefield, sacrifice it unless you return two Forests you control to their owner's hand. + addAbility(new EntersBattlefieldTriggeredAbility(new SacrificeSourceUnlessPaysEffect(new ReturnToHandChosenControlledPermanentCost( + new TargetControlledPermanent(2, 2, controlledForest, false) + )))); } public BullElephant(BullElephant other) { diff --git a/Mage.Sets/src/mage/cards/b/BurnFromWithin.java b/Mage.Sets/src/mage/cards/b/BurnFromWithin.java index 1a940c1583..7c11ae7dd3 100644 --- a/Mage.Sets/src/mage/cards/b/BurnFromWithin.java +++ b/Mage.Sets/src/mage/cards/b/BurnFromWithin.java @@ -32,7 +32,6 @@ public final class BurnFromWithin extends CardImpl { // If that creature would die this turn, exile it instead. this.getSpellAbility().addEffect(new BurnFromWithinEffect()); this.getSpellAbility().addTarget(new TargetAnyTarget()); - } private BurnFromWithin(final BurnFromWithin card) { @@ -49,7 +48,9 @@ class BurnFromWithinEffect extends OneShotEffect { public BurnFromWithinEffect() { super(Outcome.Benefit); - this.staticText = "{this} deals X damage to any target. If a creature is dealt damage this way, it loses indestructible until end of turn. If that creature would die this turn, exile it instead"; + this.staticText = "{this} deals X damage to any target. " + + "If a creature is dealt damage this way, it loses indestructible until end of turn. " + + "If that creature would die this turn, exile it instead"; } public BurnFromWithinEffect(final BurnFromWithinEffect effect) { @@ -64,25 +65,31 @@ class BurnFromWithinEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); - int amount = source.getManaCostsToPay().getX(); - if (creature != null) { - game.addEffect(new DiesReplacementEffect(new MageObjectReference(creature, game), Duration.EndOfTurn), source); - int damageDealt = creature.damage(amount, source.getSourceId(), source, game, false, true); - if (damageDealt > 0) { - ContinuousEffect effect = new LoseAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn); - effect.setTargetPointer(new FixedTarget(creature.getId(), game)); - game.addEffect(effect, source); - } - return true; - } - Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); - if (targetPlayer != null) { - targetPlayer.damage(amount, source.getSourceId(), source, game); - return true; + if (controller == null) { return false; } + + int amount = source.getManaCostsToPay().getX(); + + // Target is a creature + Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source)); + if (creature != null) { + game.addEffect(new DiesReplacementEffect(new MageObjectReference(creature, game), Duration.EndOfTurn), source); + int damageDealt = creature.damage(amount, source.getSourceId(), source, game, false, true); + if (damageDealt > 0) { + ContinuousEffect effect = new LoseAbilityTargetEffect(IndestructibleAbility.getInstance(), Duration.EndOfTurn); + effect.setTargetPointer(new FixedTarget(creature.getId(), game)); + game.addEffect(effect, source); } + return true; } + + // Target is a player + Player targetPlayer = game.getPlayer(this.getTargetPointer().getFirst(game, source)); + if (targetPlayer != null) { + targetPlayer.damage(amount, source.getSourceId(), source, game); + return true; + } + + // No valid target return false; } } diff --git a/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java b/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java index c25450038a..183e267127 100644 --- a/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java +++ b/Mage.Sets/src/mage/cards/b/BurningCinderFuryOfCrimsonChaosFire.java @@ -145,7 +145,7 @@ class BurningCinderFuryOfCrimsonChaosFireEffect extends OneShotEffect { class BurningCinderFuryOfCrimsonChaosFireCreatureGainControlEffect extends ContinuousEffectImpl { - private UUID controller; + private final UUID controller; public BurningCinderFuryOfCrimsonChaosFireCreatureGainControlEffect(Duration duration, UUID controller) { super(duration, Layer.ControlChangingEffects_2, SubLayer.NA, Outcome.GainControl); diff --git a/Mage.Sets/src/mage/cards/b/BurningOfXinye.java b/Mage.Sets/src/mage/cards/b/BurningOfXinye.java index 5e99712311..95ffc4d62e 100644 --- a/Mage.Sets/src/mage/cards/b/BurningOfXinye.java +++ b/Mage.Sets/src/mage/cards/b/BurningOfXinye.java @@ -61,22 +61,21 @@ class BurningOfXinyeEffect extends OneShotEffect{ @Override public boolean apply(Game game, Ability source) { boolean abilityApplied = false; - - Player controller = game.getPlayer(source.getControllerId()); + Player controller = game.getPlayer(source.getControllerId()); if (controller != null) { abilityApplied |= playerDestroys(game, source, controller); } - - Player opponent = game.getPlayer(source.getFirstTarget()); - if (controller != null) { + Player opponent = game.getPlayer(source.getFirstTarget()); + if (opponent != null) { abilityApplied |= playerDestroys(game, source, opponent); } + return abilityApplied; } - public boolean playerDestroys(Game game, Ability source,Player player){ + private boolean playerDestroys(Game game, Ability source, Player player){ boolean abilityApplied = false; int realCount = game.getBattlefield().countAll(filter, player.getId(), game); @@ -88,10 +87,10 @@ class BurningOfXinyeEffect extends OneShotEffect{ player.choose(Outcome.Sacrifice, target, source.getSourceId(), game); } - for ( int idx = 0; idx < target.getTargets().size(); idx++) { - Permanent permanent = game.getPermanent(target.getTargets().get(idx)); + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); - if ( permanent != null ) { + if (permanent != null) { abilityApplied |= permanent.destroy(source, game, false); } } @@ -103,5 +102,4 @@ class BurningOfXinyeEffect extends OneShotEffect{ public BurningOfXinyeEffect copy() { return new BurningOfXinyeEffect(this); } - } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/k/KnowledgePool.java b/Mage.Sets/src/mage/cards/k/KnowledgePool.java index 122b18ddfb..213ab9cacc 100644 --- a/Mage.Sets/src/mage/cards/k/KnowledgePool.java +++ b/Mage.Sets/src/mage/cards/k/KnowledgePool.java @@ -37,10 +37,11 @@ public final class KnowledgePool extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{6}"); // Imprint - When Knowledge Pool enters the battlefield, each player exiles the top three cards of their library - this.addAbility(new EntersBattlefieldTriggeredAbility(new KnowledgePoolEffect1(), false).setAbilityWord(AbilityWord.IMPRINT)); + this.addAbility(new EntersBattlefieldTriggeredAbility(new KnowledgePoolExileThreeCardsEffect(), false).setAbilityWord(AbilityWord.IMPRINT)); - // Whenever a player casts a spell from their hand, that player exiles it. If the player does, they may cast another nonland card exiled with Knowledge Pool without paying that card's mana cost. - this.addAbility(new KnowledgePoolAbility()); + // Whenever a player casts a spell from their hand, that player exiles it. + // If the player does, they may cast another nonland card exiled with Knowledge Pool without paying that card's mana cost. + this.addAbility(new KnowledgePoolWhenCastFromHandAbility()); } private KnowledgePool(final KnowledgePool card) { @@ -51,58 +52,62 @@ public final class KnowledgePool extends CardImpl { public KnowledgePool copy() { return new KnowledgePool(this); } - } -class KnowledgePoolEffect1 extends OneShotEffect { +class KnowledgePoolExileThreeCardsEffect extends OneShotEffect { - public KnowledgePoolEffect1() { + public KnowledgePoolExileThreeCardsEffect() { super(Outcome.Neutral); staticText = "each player exiles the top three cards of their library"; } - public KnowledgePoolEffect1(final KnowledgePoolEffect1 effect) { + public KnowledgePoolExileThreeCardsEffect(final KnowledgePoolExileThreeCardsEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { return false; } + MageObject sourceObject = game.getObject(source.getSourceId()); - if (controller == null || sourceObject == null) { - return false; - } + if (sourceObject == null) { return false; } + for (UUID playerId : game.getState().getPlayersInRange(controller.getId(), game)) { Player player = game.getPlayer(playerId); - if (player != null) { - player.moveCardsToExile(player.getLibrary().getTopCards(game, 3), source, game, true, - CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), - sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ')'); - } + if (player == null) { continue; } + + player.moveCardsToExile( + player.getLibrary().getTopCards(game, 3), + source, + game, + true, + CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()), + sourceObject.getIdName() + " (" + sourceObject.getZoneChangeCounter(game) + ')' + ); } return true; } @Override - public KnowledgePoolEffect1 copy() { - return new KnowledgePoolEffect1(this); + public KnowledgePoolExileThreeCardsEffect copy() { + return new KnowledgePoolExileThreeCardsEffect(this); } - } -class KnowledgePoolAbility extends TriggeredAbilityImpl { +class KnowledgePoolWhenCastFromHandAbility extends TriggeredAbilityImpl { - public KnowledgePoolAbility() { - super(Zone.BATTLEFIELD, new KnowledgePoolEffect2(), false); + public KnowledgePoolWhenCastFromHandAbility() { + super(Zone.BATTLEFIELD, new KnowledgePoolExileAndPlayEffect(), false); } - public KnowledgePoolAbility(final KnowledgePoolAbility ability) { + private KnowledgePoolWhenCastFromHandAbility(final KnowledgePoolWhenCastFromHandAbility ability) { super(ability); } @Override - public KnowledgePoolAbility copy() { - return new KnowledgePoolAbility(this); + public KnowledgePoolWhenCastFromHandAbility copy() { + return new KnowledgePoolWhenCastFromHandAbility(this); } @Override @@ -112,72 +117,76 @@ class KnowledgePoolAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getZone() == Zone.HAND) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - } - return true; - } - } - return false; - } + if (event.getZone() != Zone.HAND) { return false; } + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell == null) { return false; } + + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); + } + return true; + } } -class KnowledgePoolEffect2 extends OneShotEffect { +class KnowledgePoolExileAndPlayEffect extends OneShotEffect { - private static FilterNonlandCard filter = new FilterNonlandCard("nonland card exiled with Knowledge Pool"); - - public KnowledgePoolEffect2() { + public KnowledgePoolExileAndPlayEffect() { super(Outcome.Neutral); staticText = "Whenever a player casts a spell from their hand, that player exiles it. If the player does, they may cast another nonland card exiled with {this} without paying that card's mana cost"; } - public KnowledgePoolEffect2(final KnowledgePoolEffect2 effect) { + private KnowledgePoolExileAndPlayEffect(final KnowledgePoolExileAndPlayEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { Spell spell = game.getStack().getSpell(targetPointer.getFirst(game, source)); - if (spell == null) { + if (spell == null) { return false; } + + Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); + if (sourceObject == null ) { return false; } + + Player spellController = game.getPlayer(spell.getControllerId()); + if (spellController == null) { return false; } + + UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), sourceObject.getZoneChangeCounter(game)); + + if (!spellController.moveCardsToExile(spell, source, game, true, exileZoneId, sourceObject.getIdName())) { + // The card didn't make it to exile, none of Knowledge Pool's effect applied return false; } - Permanent sourceObject = game.getPermanentOrLKIBattlefield(source.getSourceId()); - Player spellController = game.getPlayer(spell.getControllerId()); - if (spellController != null - && sourceObject != null) { - UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), sourceObject.getZoneChangeCounter(game)); - if (exileZoneId == null) { - return false; - } - if (spellController.moveCardsToExile(spell, source, game, true, exileZoneId, sourceObject.getIdName())) { - if (spellController.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with " + sourceObject.getLogName() + " without paying that card's mana cost?", source, game)) { - FilterNonlandCard realFilter = filter.copy(); - realFilter.add(Predicates.not(new CardIdPredicate(spell.getSourceId()))); - TargetCardInExile target = new TargetCardInExile(0, 1, realFilter, source.getSourceId()); - target.setNotTarget(true); - if (spellController.choose(Outcome.PlayForFree, game.getExile().getExileZone(exileZoneId), target, game)) { - Card card = game.getCard(target.getFirstTarget()); - if (card != null - && !card.getId().equals(spell.getSourceId())) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } - } - return true; - } + + // From here on down the function returns true since at least part of the effect went off + + if (!spellController.chooseUse(Outcome.PlayForFree, "Cast another nonland card exiled with " + sourceObject.getLogName() + " without paying that card's mana cost?", source, game)) { + // Pleyer didn't want to cast another spell BUT their original spell was exiled with Knowledge Pool, so return true. + return true; } - return false; + FilterNonlandCard filter = new FilterNonlandCard("nonland card exiled with Knowledge Pool"); + filter.add(Predicates.not(new CardIdPredicate(spell.getSourceId()))); + + TargetCardInExile target = new TargetCardInExile(0, 1, filter, source.getSourceId()); + target.setNotTarget(true); + + if (!spellController.choose(Outcome.PlayForFree, game.getExile().getExileZone(exileZoneId), target, game)) { + // Player chose to not cast any ofthe spells + return true; + } + + Card card = game.getCard(target.getFirstTarget()); + if (card == null || card.getId().equals(spell.getSourceId())) { return true; } + + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); + spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game)); + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); + + return true; } @Override - public KnowledgePoolEffect2 copy() { - return new KnowledgePoolEffect2(this); + public KnowledgePoolExileAndPlayEffect copy() { + return new KnowledgePoolExileAndPlayEffect(this); } - } diff --git a/Mage.Sets/src/mage/cards/p/PossibilityStorm.java b/Mage.Sets/src/mage/cards/p/PossibilityStorm.java index 10dafb8fea..87a3cdf420 100644 --- a/Mage.Sets/src/mage/cards/p/PossibilityStorm.java +++ b/Mage.Sets/src/mage/cards/p/PossibilityStorm.java @@ -70,16 +70,15 @@ class PossibilityStormTriggeredAbility extends TriggeredAbilityImpl { @Override public boolean checkTrigger(GameEvent event, Game game) { - if (event.getZone() == Zone.HAND) { - Spell spell = game.getStack().getSpell(event.getTargetId()); - if (spell != null) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId())); - } - return true; - } + if (event.getZone() != Zone.HAND) { return false; } + + Spell spell = game.getStack().getSpell(event.getTargetId()); + if (spell == null) { return false; } + + for (Effect effect : this.getEffects()) { + effect.setTargetPointer(new FixedTarget(event.getTargetId())); } - return false; + return true; } @Override @@ -107,43 +106,44 @@ class PossibilityStormEffect extends OneShotEffect { spell = ((Spell) game.getLastKnownInformation(targetPointer.getFirst(game, source), Zone.STACK)); noLongerOnStack = true; } + if (spell == null) { return false; } + + Player spellController = game.getPlayer(spell.getControllerId()); + if (spellController == null) { return false; } + MageObject sourceObject = source.getSourceObject(game); - if (sourceObject != null && spell != null) { - Player spellController = game.getPlayer(spell.getControllerId()); - if (spellController != null) { - if (!noLongerOnStack) { - spellController.moveCardsToExile(spell, source, game, true, source.getSourceId(), sourceObject.getIdName()); - } - if (spellController.getLibrary().hasCards()) { - Library library = spellController.getLibrary(); - Card card; - do { - card = library.getFromTop(game); - if (card != null) { - spellController.moveCardsToExile(card, source, game, true, source.getSourceId(), sourceObject.getIdName()); - } - } while (library.hasCards() && card != null && !sharesType(card, spell.getCardType(game), game)); + if (sourceObject == null) { return false; } - if (card != null && sharesType(card, spell.getCardType(game), game) - && !card.isLand(game) - && card.getSpellAbility().canChooseTarget(game, spellController.getId())) { - if (spellController.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) { - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); - spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game)); - game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); - } - } + if (!noLongerOnStack) { + spellController.moveCardsToExile(spell, source, game, true, source.getSourceId(), sourceObject.getIdName()); + } - ExileZone exile = game.getExile().getExileZone(source.getSourceId()); - if (exile != null) { - spellController.putCardsOnBottomOfLibrary(exile, game, source, false); - } + if (!spellController.getLibrary().hasCards()) { return true; } + Library library = spellController.getLibrary(); + Card card; + do { + card = library.getFromTop(game); + if (card != null) { + spellController.moveCardsToExile(card, source, game, true, source.getSourceId(), sourceObject.getIdName()); + } + } while (library.hasCards() && card != null && !sharesType(card, spell.getCardType(game), game)); - } - return true; + if (card != null && sharesType(card, spell.getCardType(game), game) + && !card.isLand(game) + && card.getSpellAbility().canChooseTarget(game, spellController.getId())) { + if (spellController.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + " without paying cost?", source, game)) { + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE); + spellController.cast(spellController.chooseAbilityForCast(card, game, true), game, true, new ApprovingObject(source, game)); + game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null); } } - return false; + + ExileZone exile = game.getExile().getExileZone(source.getSourceId()); + if (exile != null) { + spellController.putCardsOnBottomOfLibrary(exile, game, source, false); + } + + return true; } private boolean sharesType(Card card, List cardTypes, Game game) { diff --git a/Mage.Sets/src/mage/cards/t/ThievesAuction.java b/Mage.Sets/src/mage/cards/t/ThievesAuction.java index 8d19d0f968..66dda41a89 100644 --- a/Mage.Sets/src/mage/cards/t/ThievesAuction.java +++ b/Mage.Sets/src/mage/cards/t/ThievesAuction.java @@ -27,7 +27,9 @@ public final class ThievesAuction extends CardImpl { public ThievesAuction(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{R}{R}{R}"); - // Exile all nontoken permanents. Starting with you, each player chooses one of the exiled cards and puts it onto the battlefield tapped under their control. Repeat this process until all cards exiled this way have been chosen. + // Exile all nontoken permanents. + // Starting with you, each player chooses one of the exiled cards and puts it onto the battlefield tapped under their control. + // Repeat this process until all cards exiled this way have been chosen. this.getSpellAbility().addEffect(new ThievesAuctionEffect()); } @@ -54,7 +56,7 @@ class ThievesAuctionEffect extends OneShotEffect { this.staticText = "Exile all nontoken permanents. Starting with you, each player chooses one of the exiled cards and puts it onto the battlefield tapped under their control. Repeat this process until all cards exiled this way have been chosen"; } - ThievesAuctionEffect(final ThievesAuctionEffect effect) { + private ThievesAuctionEffect(final ThievesAuctionEffect effect) { super(effect); } @@ -66,36 +68,39 @@ class ThievesAuctionEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - // Exile all nontoken permanents. - Cards exiledCards = new CardsImpl(); - for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { - exiledCards.add(permanent); - controller.moveCardsToExile(permanent, source, game, true, CardUtil.getCardExileZoneId(game, source.getSourceId()), "Thieves' Auction"); - } - // Starting with you, each player - PlayerList playerList = game.getState().getPlayersInRange(controller.getId(), game); - Player player = playerList.getCurrent(game); - while (player != null && !exiledCards.isEmpty() && !game.hasEnded()) { - if (player.canRespond()) { - // chooses one of the exiled cards - TargetCard target = new TargetCardInExile(new FilterCard()); - if (player.choose(Outcome.PutCardInPlay, exiledCards, target, game)) { - // and puts it onto the battlefield tapped under their control. - Card chosenCard = exiledCards.get(target.getFirstTarget(), game); - if (chosenCard != null) { - player.moveCards(chosenCard, Zone.BATTLEFIELD, source, game, true, false, false, null); - } - exiledCards.remove(chosenCard); - } else { - break; - } - } - // Repeat this process until all cards exiled this way have been chosen. - player = playerList.getNext(game, false); - } - return true; + if (controller == null) { return false; } + + // Exile all nontoken permanents. + Cards exiledCards = new CardsImpl(); + for (Permanent permanent : game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { + exiledCards.add(permanent); + controller.moveCardsToExile(permanent, source, game, true, CardUtil.getCardExileZoneId(game, source.getSourceId()), "Thieves' Auction"); } - return false; + + // Starting with you, each player + PlayerList playerList = game.getState().getPlayersInRange(controller.getId(), game); + Player player = playerList.getCurrent(game); + while (player != null && !exiledCards.isEmpty() && !game.hasEnded()) { + if (!player.canRespond()) { continue; } + + // chooses one of the exiled cards + TargetCard target = new TargetCardInExile(new FilterCard()); + if (player.choose(Outcome.PutCardInPlay, exiledCards, target, game)) { + // and puts it onto the battlefield tapped under their control. + Card chosenCard = exiledCards.get(target.getFirstTarget(), game); + if (chosenCard != null) { + player.moveCards(chosenCard, Zone.BATTLEFIELD, source, game, true, false, false, null); + } + exiledCards.remove(chosenCard); + } else { + // TODO Why does this break? + break; + } + + // Repeat this process until all cards exiled this way have been chosen. + player = playerList.getNext(game, false); + } + + return true; } } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/dis/AzoriusAethermageTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/dis/AzoriusAethermageTest.java new file mode 100644 index 0000000000..a7bb0f69af --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/dis/AzoriusAethermageTest.java @@ -0,0 +1,54 @@ +package org.mage.test.cards.single.dis; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +public class AzoriusAethermageTest extends CardTestPlayerBase { + + /** + * Whenever you bounce a permanent (tokens included) you may pay {1}, if you do, draw a card + */ + @Test + public void testBouncedLand() { + /* + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); // Used for paying ability cost + addCard(Zone.BATTLEFIELD, playerA, "Island", 2*3); + addCard(Zone.BATTLEFIELD, playerA, "Toggo, Goblin Weaponsmith"); + addCard(Zone.HAND, playerA, "Boomerang",3); + + // Permanents to bounce + addCard(Zone.HAND, playerA, "Plains", 1); + addCard(Zone.BATTLEFIELD, playerA, "Azorius Aethermage"); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Plains"); // Create a Rock token with Toggo + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Plains"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true); + setChoice(playerA, "Yes"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Rock"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true); + setChoice(playerA, "Yes"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boomerang", "Azorius Aethermage"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true); + setChoice(playerA, "Yes"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + // 3 cards bounced: plains, token, and aethermage, but the token never makes it to the hand -> +2 cards in hand + // 3 cards drawn -> +3 cards in hand + assertHandCount(playerA, (1+1) + (1) + (1+1)); + */ + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/hou/AbandonedSarcophagusTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/hou/AbandonedSarcophagusTest.java new file mode 100644 index 0000000000..78a337ba30 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/hou/AbandonedSarcophagusTest.java @@ -0,0 +1,108 @@ +package org.mage.test.cards.single.hou; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + + +public class AbandonedSarcophagusTest extends CardTestPlayerBase { + + /** + * You may cast non-land card with cycling from your graveyard + */ + @Test + public void castNonLandFromGraveyard() { + addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.GRAVEYARD, playerA, "Astral Drift"); // {2}{W} Enchantment + addCard(Zone.GRAVEYARD, playerA, "Ash Barrens"); // Land + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Astral Drift"); + // Can't play lands with this ability + checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Play Ash Barrens", false); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertPermanentCount(playerA, "Astral Drift", 1); + } + + /** + * You can only cast the card from the graveyard, you CANNOT cycle it + */ + @Test + public void cantCycleFromGraveyard() { + addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 3); + addCard(Zone.GRAVEYARD, playerA, "Astral Drift"); // {2}{W} Enchantment + addCard(Zone.GRAVEYARD, playerA, "Ash Barrens"); // Land + + checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling", false); + checkPlayableAbility("before play", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Basic landcycling", false); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + } + + /** + * When a card with cycling is cycled it still goes to the graveyard + */ + @Test + public void cycledCardGoesToGraveyard() { + addCard(Zone.LIBRARY, playerA, "Forest", 5); + addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.HAND, playerA, "Astral Drift"); // {2}{W} Enchantment + addCard(Zone.HAND, playerA, "Ash Barrens"); // Land + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Basic landcycling"); + addTarget(playerA, "Forest"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cycling"); + + setStopAt(1, PhaseStep.END_TURN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertHandCount(playerA, 2); + assertGraveyardCount(playerA, 2); + } + + /** + * When a card goes to the graveyard and it WAS NOT cycled, it gets exiled + */ + @Test + public void nonCycledCardGoesToExile() { + addCard(Zone.BATTLEFIELD, playerA, "Abandoned Sarcophagus"); + addCard(Zone.BATTLEFIELD, playerA, "Plains", 4); + addCard(Zone.BATTLEFIELD, playerA, "Forest", 6); + addCard(Zone.HAND, playerA, "Astral Drift"); // {2}{W} Enchantment + addCard(Zone.HAND, playerA, "Ash Barrens"); // Land + addCard(Zone.HAND, playerA, "Beast Within", 2); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Astral Drift"); + playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ash Barrens"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Beast Within", "Astral Drift"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Beast Within", "Ash Barrens"); + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + + setStrictChooseMode(true); + execute(); + + assertAllCommandsUsed(); + + assertExileCount(playerA, 2); + } +}