diff --git a/Mage.Sets/src/mage/cards/a/AuraGraft.java b/Mage.Sets/src/mage/cards/a/AuraGraft.java index 2a46cf70829..b13c78e091b 100644 --- a/Mage.Sets/src/mage/cards/a/AuraGraft.java +++ b/Mage.Sets/src/mage/cards/a/AuraGraft.java @@ -1,9 +1,7 @@ - package mage.cards.a; import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.effects.Effect; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.GainControlTargetEffect; import mage.cards.CardImpl; @@ -12,35 +10,37 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.Outcome; import mage.constants.SubType; +import mage.filter.Filter; import mage.filter.FilterPermanent; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.filter.predicate.mageobject.AnotherPredicate; -import mage.filter.predicate.permanent.PermanentCanBeAttachedToPredicate; +import mage.filter.predicate.permanent.CanBeEnchantedByPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; +import mage.util.TargetAddress; /** * @author duncant */ public final class AuraGraft extends CardImpl { + private static final FilterPermanent filter = new FilterPermanent("Aura that's attached to a permanent"); + static { + filter.add(SubType.AURA.getPredicate()); + filter.add(AuraGraftAttachedToPermanentPredicate.instance); + } + public AuraGraft(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); // Gain control of target Aura that's attached to a permanent. Attach it to another permanent it can enchant. - FilterPermanent filter = new FilterPermanent("Aura that's attached to a permanent"); - filter.add(SubType.AURA.getPredicate()); - filter.add(new AttachedToPermanentPredicate()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); - - Effect gainControlEffect = new GainControlTargetEffect(Duration.EndOfGame); - this.getSpellAbility().addEffect(gainControlEffect); - - this.getSpellAbility().addEffect(new MoveTargetAuraEffect()); + this.getSpellAbility().addEffect(new GainControlTargetEffect(Duration.EndOfGame)); + this.getSpellAbility().addEffect(new AuraGraftMoveAuraEffect()); } private AuraGraft(final AuraGraft card) { @@ -53,11 +53,8 @@ public final class AuraGraft extends CardImpl { } } -class AttachedToPermanentPredicate implements ObjectSourcePlayerPredicate { - - public AttachedToPermanentPredicate() { - super(); - } +enum AuraGraftAttachedToPermanentPredicate implements ObjectSourcePlayerPredicate { + instance; public boolean apply(ObjectSourcePlayer input, Game game) { Permanent attached = input.getObject(); @@ -65,49 +62,68 @@ class AttachedToPermanentPredicate implements ObjectSourcePlayerPredicate { - public MoveTargetAuraEffect() { + protected Permanent aura; + + AuraGraftAuraCanEnchantPredicate(Permanent aura) { + super(); + this.aura = aura; + } + + @Override + public boolean apply(ObjectSourcePlayer input, Game game) { + Permanent potentialAttachment = input.getObject(); + for (TargetAddress addr : TargetAddress.walk(aura)) { + Target target = addr.getTarget(aura); + Filter filter = target.getFilter(); + return filter.match(potentialAttachment, game); + } + return false; + } +} + +class AuraGraftMoveAuraEffect extends OneShotEffect { + + AuraGraftMoveAuraEffect() { super(Outcome.Benefit); staticText = "Attach it to another permanent it can enchant"; } - public MoveTargetAuraEffect(final MoveTargetAuraEffect effect) { + private AuraGraftMoveAuraEffect(final AuraGraftMoveAuraEffect effect) { super(effect); } @Override - public MoveTargetAuraEffect copy() { - return new MoveTargetAuraEffect(this); + public AuraGraftMoveAuraEffect copy() { + return new AuraGraftMoveAuraEffect(this); } @Override public boolean apply(Game game, Ability source) { Permanent enchantment = game.getPermanent(targetPointer.getFirst(game, source)); - if (enchantment == null) { - return false; - } - Permanent oldAttachment = game.getPermanent(enchantment.getAttachedTo()); - if (oldAttachment == null) { - return false; - } Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { + if (enchantment == null || controller == null) { + return false; + } + Permanent previouslyEnchanted = game.getPermanent(enchantment.getAttachedTo()); + if (previouslyEnchanted == null) { return false; } FilterPermanent filter = new FilterPermanent("another permanent " + enchantment.getLogName() + " can enchant"); filter.add(AnotherPredicate.instance); - filter.add(new PermanentCanBeAttachedToPredicate(enchantment)); + filter.add(new AuraGraftAuraCanEnchantPredicate(enchantment)); // extracts Targets from Aura spell ability + filter.add(new CanBeEnchantedByPredicate(enchantment)); // checks for protection Target target = new TargetPermanent(filter); target.setNotTarget(true); if (target.canChoose(controller.getId(), source, game) && controller.choose(outcome, target, source, game)) { Permanent newAttachment = game.getPermanent(target.getFirstTarget()); if (newAttachment != null - && oldAttachment.removeAttachment(enchantment.getId(), source, game)) { + && previouslyEnchanted.removeAttachment(enchantment.getId(), source, game)) { newAttachment.addAttachment(enchantment.getId(), source, game); - game.informPlayers(enchantment.getLogName() + " was unattached from " + oldAttachment.getLogName() + " and attached to " + newAttachment.getLogName()); + game.informPlayers(enchantment.getLogName() + " was unattached from " + previouslyEnchanted.getLogName() + " and attached to " + newAttachment.getLogName()); return true; } } diff --git a/Mage.Sets/src/mage/cards/i/InfectiousRage.java b/Mage.Sets/src/mage/cards/i/InfectiousRage.java index c6f7c08db78..2591766ea95 100644 --- a/Mage.Sets/src/mage/cards/i/InfectiousRage.java +++ b/Mage.Sets/src/mage/cards/i/InfectiousRage.java @@ -11,8 +11,8 @@ import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.filter.FilterPermanent; -import mage.filter.predicate.permanent.PermanentCanBeAttachedToPredicate; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.permanent.CanBeEnchantedByPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -80,32 +80,28 @@ class InfectiousRageReattachEffect extends OneShotEffect { Player controller = game.getPlayer(source.getControllerId()); Card auraCard = game.getCard(source.getSourceId()); - Permanent auraPermanent = source.getSourcePermanentOrLKI(game); - if (controller == null || auraCard == null || auraPermanent == null) { + if (controller == null || auraCard == null) { return false; } if (source.getSourceObjectZoneChangeCounter() != auraCard.getZoneChangeCounter(game)) { return false; } - FilterPermanent filter = new FilterPermanent(); - filter.add(CardType.CREATURE.getPredicate()); - filter.add(new PermanentCanBeAttachedToPredicate(auraPermanent)); // Doesn't yet exclude creatures with protection abilities + FilterCreaturePermanent filter = new FilterCreaturePermanent(); + filter.add(new CanBeEnchantedByPredicate(auraCard)); List permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source, game); - if (!permanents.isEmpty()) { - Permanent creature = RandomUtil.randomFromCollection(permanents); - if (creature != null) { - game.getState().setValue("attachTo:" + auraCard.getId(), creature); - controller.moveCards(auraCard, Zone.BATTLEFIELD, source, game); - return creature.addAttachment(auraCard.getId(), source, game); - } + if (permanents.isEmpty()) { + game.informPlayers("No valid creatures for " + auraCard.getLogName() + "to enchant."); + return false; } - else { - game.informPlayers("No valid creatures for " + auraPermanent.getLogName() + "to enchant."); + Permanent creature = RandomUtil.randomFromCollection(permanents); + if (creature == null) { + return false; } - - return false; + game.getState().setValue("attachTo:" + auraCard.getId(), creature); + controller.moveCards(auraCard, Zone.BATTLEFIELD, source, game); + return creature.addAttachment(auraCard.getId(), source, game); } diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AuraAttachTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AuraAttachTest.java new file mode 100644 index 00000000000..71558b76c19 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/enchantments/AuraAttachTest.java @@ -0,0 +1,47 @@ +package org.mage.test.cards.enchantments; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author xenohedron + */ +public class AuraAttachTest extends CardTestPlayerBase { + + @Test + public void testInfectiousRage() { + /* + * Infectious Rage {1}{R} + * Enchant creature + * Enchanted creature gets +2/-1. + * When enchanted creature dies, choose a creature at random Infectious Rage can enchant. + * Return Infectious Rage to the battlefield attached to that creature. + */ + addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3); + addCard(Zone.BATTLEFIELD, playerA, "Pensive Minotaur", 1); // 2/3 (vanilla) + addCard(Zone.BATTLEFIELD, playerB, "Slippery Bogle", 1); // 1/1 hexproof + addCard(Zone.BATTLEFIELD, playerB, "Thermal Glider", 1); // 2/1 flying, protection from red + addCard(Zone.HAND, playerA, "Infectious Rage", 1); + addCard(Zone.HAND, playerA, "Shock", 1); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Infectious Rage", "Pensive Minotaur"); + // Minotaur is now a 4/2 + waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Shock", "Pensive Minotaur"); + // Minotaur dies. Infectious Rage triggers, only legal creature to enchant is Slippery Bogle + // Bogle dies. // Infectious Rage triggers, Thermal Glider can't be enchanted by it, so it remains in graveyard + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, "Pensive Minotaur", 1); + assertGraveyardCount(playerA, "Infectious Rage", 1); + assertGraveyardCount(playerA, "Shock", 1); + assertGraveyardCount(playerB, "Slippery Bogle", 1); + assertPermanentCount(playerB, "Thermal Glider", 1); + + } + +} diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/PermanentCanBeAttachedToPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/PermanentCanBeAttachedToPredicate.java deleted file mode 100644 index d905903602d..00000000000 --- a/Mage/src/main/java/mage/filter/predicate/permanent/PermanentCanBeAttachedToPredicate.java +++ /dev/null @@ -1,35 +0,0 @@ -package mage.filter.predicate.permanent; - -import mage.filter.Filter; -import mage.filter.predicate.ObjectSourcePlayer; -import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; -import mage.target.Target; -import mage.util.TargetAddress; - -/** - * @author duncant - */ - -public class PermanentCanBeAttachedToPredicate implements ObjectSourcePlayerPredicate { - - protected Permanent aura; - - public PermanentCanBeAttachedToPredicate(Permanent aura) { - super(); - this.aura = aura; - } - - @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - // TODO: Is it possible to add functionality to exclude objects the aura can't enchant (e.g. protection from)? - Permanent potentialAttachment = input.getObject(); - for (TargetAddress addr : TargetAddress.walk(aura)) { - Target target = addr.getTarget(aura); - Filter filter = target.getFilter(); - return filter.match(potentialAttachment, game); - } - return false; - } -}