diff --git a/Mage.Sets/src/mage/sets/riseoftheeldrazi/ItThatBetrays.java b/Mage.Sets/src/mage/sets/riseoftheeldrazi/ItThatBetrays.java index c9478a7f190..8b4b49840ae 100644 --- a/Mage.Sets/src/mage/sets/riseoftheeldrazi/ItThatBetrays.java +++ b/Mage.Sets/src/mage/sets/riseoftheeldrazi/ItThatBetrays.java @@ -28,7 +28,6 @@ package mage.sets.riseoftheeldrazi; import java.util.UUID; - import mage.MageInt; import mage.abilities.common.OpponentSacrificesNonTokenPermanentTriggeredAbility; import mage.abilities.effects.common.ReturnToBattlefieldUnderYourControlTargetEffect; @@ -40,17 +39,16 @@ import mage.filter.FilterPermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.TokenPredicate; - /** * * @author jeffwadsworth */ public class ItThatBetrays extends CardImpl { - private static final FilterPermanent filter = new FilterPermanent("nontoken permanent"); + private static final FilterPermanent FILTER = new FilterPermanent("nontoken permanent"); static { - filter.add(Predicates.not(new TokenPredicate())); + FILTER.add(Predicates.not(new TokenPredicate())); } public ItThatBetrays(UUID ownerId) { @@ -61,6 +59,7 @@ public class ItThatBetrays extends CardImpl { this.power = new MageInt(11); this.toughness = new MageInt(11); + // Annihilator 2 (Whenever this creature attacks, defending player sacrifices two permanents.) this.addAbility(new AnnihilatorAbility(2)); // Whenever an opponent sacrifices a nontoken permanent, put that card onto the battlefield under your control. @@ -75,5 +74,5 @@ public class ItThatBetrays extends CardImpl { public ItThatBetrays copy() { return new ItThatBetrays(this); } - + } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java index 3dd7735cd8e..4a6a6077a0a 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/control/ItThatBetraysTest.java @@ -87,4 +87,44 @@ public class ItThatBetraysTest extends CardTestPlayerBase { assertPermanentCount(playerB, "Flooded Strand", 1); } + /** + * I just sacrificed a Spreading Seas to an attacking It That Betrays, and + * it returned the Spreading Seas under my control. It made me choose a land + * to enchant, and I drew a card. + */ + @Test + public void testExileItThatBetraysEffectEnchantment() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 1); + addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1); + addCard(Zone.HAND, playerA, "Spreading Seas", 1); // {1}{U} + + // Annihilator 2 (Whenever this creature attacks, defending player sacrifices two permanents.) + // Whenever an opponent sacrifices a nontoken permanent, put that card onto the battlefield under your control. + addCard(Zone.BATTLEFIELD, playerB, "It That Betrays"); // 11/11 + addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1); + + // Enchant land + // When Spreading Seas enters the battlefield, draw a card. + // Enchanted land is an Island. + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Spreading Seas", "Mountain"); + + attack(2, playerB, "It That Betrays"); + setChoice(playerA, "Spreading Seas"); + setChoice(playerA, "Silvercoat Lion"); + + setStopAt(2, PhaseStep.POSTCOMBAT_MAIN); + execute(); + + assertLife(playerA, 9); + assertLife(playerB, 20); + + assertHandCount(playerA, "Spreading Seas", 0); + + // Player B now controls a Silvercoat Lion and Spreading Seas + assertPermanentCount(playerB, "Silvercoat Lion", 1); + assertPermanentCount(playerA, "Spreading Seas", 0); + assertGraveyardCount(playerA, "Spreading Seas", 0); + assertPermanentCount(playerB, "Spreading Seas", 1); + } } diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 87d245772d3..2dc30510882 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -601,7 +601,7 @@ public class TestPlayer implements Player { targetName = targetName.substring(0, targetName.length() - 11); } } - for (Permanent permanent : game.getBattlefield().getAllActivePermanents(filterPermanent, game)) { + for (Permanent permanent : game.getBattlefield().getActivePermanents(filterPermanent, getId(), sourceId, game)) { if (target.getTargets().contains(permanent.getId())) { continue; } diff --git a/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java b/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java index 116930ba282..6065eb3584c 100644 --- a/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/AuraReplacementEffect.java @@ -117,6 +117,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { } game.applyEffects(); // So continuousEffects are removed if previous effect of the same ability did move objects that cuase continuous effects + Player controllingPlayer = null; if (targetId == null) { SpellAbility spellAbility = card.getSpellAbility(); if (spellAbility.getTargets().isEmpty()) { @@ -145,8 +146,14 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { target.setNotTarget(true); // always not target because this way it's not handled targeted target.clearChosen(); // neccessary if e.g. aura is blinked multiple times } - Player player = game.getPlayer(card.getOwnerId()); - if (target != null && player != null && player.choose(auraOutcome, target, card.getId(), game)) { + + if (event.getPlayerId() != null) { + controllingPlayer = game.getPlayer(event.getPlayerId()); + } else { + controllingPlayer = game.getPlayer(card.getOwnerId()); + } + + if (target != null && controllingPlayer != null && controllingPlayer.choose(auraOutcome, target, card.getId(), game)) { targetId = target.getFirstTarget(); } } @@ -162,7 +169,7 @@ public class AuraReplacementEffect extends ReplacementEffectImpl { if (targetCard != null || targetPermanent != null || targetPlayer != null) { card.removeFromZone(game, fromZone, sourceId); card.updateZoneChangeCounter(game); - PermanentCard permanent = new PermanentCard(card, card.getOwnerId(), game); + PermanentCard permanent = new PermanentCard(card, (controllingPlayer == null ? card.getOwnerId() : controllingPlayer.getId()), game); game.getBattlefield().addPermanent(permanent); card.setZone(Zone.BATTLEFIELD, game); if (permanent.entersBattlefield(event.getSourceId(), game, fromZone, true)) { diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index 6d6c73d06d4..4815c0f8bc5 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -82,7 +82,7 @@ import org.apache.log4j.Logger; */ public class ContinuousEffects implements Serializable { - private static final Logger logger = Logger.getLogger(ContinuousEffects.class); + private static final Logger LOGGER = Logger.getLogger(ContinuousEffects.class); private long order = 0; @@ -226,7 +226,7 @@ public class ContinuousEffects implements Serializable { } } } else { - logger.error("No abilities for continuous effect: " + effect.toString()); + LOGGER.error("No abilities for continuous effect: " + effect.toString()); } break; default: @@ -462,17 +462,15 @@ public class ContinuousEffects implements Serializable { exists = permanent.getCard().getAbilities().contains(ability); } } - } else { - if (object instanceof PermanentCard) { - PermanentCard permanent = (PermanentCard) object; - if (permanent.isFaceDown(game) && !ability.getWorksFaceDown()) { - return false; - } - } else if (object instanceof Spell) { - Spell spell = (Spell) object; - if (spell.isFaceDown(game) && !ability.getWorksFaceDown()) { - return false; - } + } else if (object instanceof PermanentCard) { + PermanentCard permanent = (PermanentCard) object; + if (permanent.isFaceDown(game) && !ability.getWorksFaceDown()) { + return false; + } + } else if (object instanceof Spell) { + Spell spell = (Spell) object; + if (spell.isFaceDown(game) && !ability.getWorksFaceDown()) { + return false; } } return exists; @@ -539,10 +537,8 @@ public class ContinuousEffects implements Serializable { if (effect.applies(objectId, ability, controllerId, game)) { return true; } - } else { - if (effect.applies(objectId, affectedAbility, ability, game)) { - return true; - } + } else if (effect.applies(objectId, affectedAbility, ability, game)) { + return true; } } } @@ -1082,11 +1078,9 @@ public class ContinuousEffects implements Serializable { if (abilities == null) { abilities = new HashSet<>(); temporaryEffects.put(effect, abilities); - } else { - if (abilities.contains(source)) { - // this ability (for the continuous effect) is already added - return; - } + } else if (abilities.contains(source)) { + // this ability (for the continuous effect) is already added + return; } abilities.add(source); @@ -1097,10 +1091,10 @@ public class ContinuousEffects implements Serializable { public void addEffect(ContinuousEffect effect, Ability source) { if (effect == null) { - logger.error("Effect is null: " + source.toString()); + LOGGER.error("Effect is null: " + source.toString()); return; } else if (source == null) { - logger.warn("Adding effect without ability : " + effect.toString()); + LOGGER.warn("Adding effect without ability : " + effect.toString()); } switch (effect.getEffectType()) { case REPLACEMENT: @@ -1166,10 +1160,8 @@ public class ContinuousEffects implements Serializable { if (ability.getSourceId().equals(sourceId)) { ability.setControllerId(controllerId); } - } else { - if (!ability.getZone().equals(Zone.COMMAND)) { - logger.fatal("Continuous effect for ability with no sourceId Ability: " + ability); - } + } else if (!ability.getZone().equals(Zone.COMMAND)) { + LOGGER.fatal("Continuous effect for ability with no sourceId Ability: " + ability); } } } @@ -1240,7 +1232,7 @@ public class ContinuousEffects implements Serializable { } } } else { - logger.error("Replacement effect without ability: " + entry.getKey().toString()); + LOGGER.error("Replacement effect without ability: " + entry.getKey().toString()); } } return texts; @@ -1278,7 +1270,7 @@ public class ContinuousEffects implements Serializable { } } } else { - logger.warn("Ability without sourceId:" + ability.getRule()); + LOGGER.warn("Ability without sourceId:" + ability.getRule()); } } } diff --git a/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java b/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java index 7a43a5711c8..66653099764 100644 --- a/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/AnnihilatorAbility.java @@ -104,7 +104,7 @@ public class AnnihilatorAbility extends TriggeredAbilityImpl { class AnnihilatorEffect extends OneShotEffect { private final int count; - private static final FilterControlledPermanent filter = new FilterControlledPermanent(); + private static final FilterControlledPermanent FILTER = new FilterControlledPermanent(); AnnihilatorEffect(int count) { super(Outcome.Sacrifice); @@ -124,8 +124,8 @@ class AnnihilatorEffect extends OneShotEffect { player = game.getPlayer(defendingPlayerId); } if (player != null) { - int amount = Math.min(count, game.getBattlefield().countAll(filter, player.getId(), game)); - Target target = new TargetControlledPermanent(amount, amount, filter, true); + int amount = Math.min(count, game.getBattlefield().countAll(FILTER, player.getId(), game)); + Target target = new TargetControlledPermanent(amount, amount, FILTER, true); if (target.canChoose(player.getId(), game)) { while (!target.isChosen() && target.canChoose(player.getId(), game) && player.canRespond()) { player.choose(Outcome.Sacrifice, target, source.getSourceId(), game);