diff --git a/Mage.Sets/src/mage/cards/c/CurseOfClingingWebs.java b/Mage.Sets/src/mage/cards/c/CurseOfClingingWebs.java index b1aff4820a1..42f3e572803 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfClingingWebs.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfClingingWebs.java @@ -11,9 +11,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.EnchantPlayerControlsPredicate; import mage.filter.predicate.permanent.TokenPredicate; import mage.game.permanent.token.SpiderToken; import mage.target.TargetPlayer; @@ -30,7 +30,7 @@ public final class CurseOfClingingWebs extends CardImpl { static { filter.add(TokenPredicate.FALSE); - filter.add(EnchantPlayerControlsPredicate.instance); + filter.add(TargetController.ENCHANTED.getControllerPredicate()); } public CurseOfClingingWebs(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CurseOfConformity.java b/Mage.Sets/src/mage/cards/c/CurseOfConformity.java index 6f2171b66ad..41d8c9d9d19 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfConformity.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfConformity.java @@ -11,7 +11,6 @@ import mage.constants.*; import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; -import mage.filter.predicate.permanent.EnchantPlayerControlsPredicate; import mage.game.Game; import mage.game.permanent.Permanent; import mage.target.TargetPlayer; @@ -55,7 +54,7 @@ class CurseOfConformityEffect extends ContinuousEffectImpl { static { filter.add(Predicates.not(SuperType.LEGENDARY.getPredicate())); - filter.add(EnchantPlayerControlsPredicate.instance); + filter.add(TargetController.ENCHANTED.getControllerPredicate()); } CurseOfConformityEffect() { diff --git a/Mage.Sets/src/mage/cards/c/CurseOfDeathsHold.java b/Mage.Sets/src/mage/cards/c/CurseOfDeathsHold.java index d1fe0ed60d6..ab293524c59 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfDeathsHold.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfDeathsHold.java @@ -6,12 +6,8 @@ import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.abilities.keyword.EnchantAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.SubType; +import mage.constants.*; import mage.filter.common.FilterCreaturePermanent; -import mage.filter.predicate.permanent.EnchantPlayerControlsPredicate; import mage.target.TargetPlayer; import java.util.UUID; @@ -25,7 +21,7 @@ public final class CurseOfDeathsHold extends CardImpl { = new FilterCreaturePermanent("creatures enchanted player controls"); static { - filter.add(EnchantPlayerControlsPredicate.instance); + filter.add(TargetController.ENCHANTED.getControllerPredicate()); } public CurseOfDeathsHold(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CurseOfTheRestlessDead.java b/Mage.Sets/src/mage/cards/c/CurseOfTheRestlessDead.java index 09919c2c47f..f1fc1cc57ef 100644 --- a/Mage.Sets/src/mage/cards/c/CurseOfTheRestlessDead.java +++ b/Mage.Sets/src/mage/cards/c/CurseOfTheRestlessDead.java @@ -10,9 +10,9 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.SubType; +import mage.constants.TargetController; import mage.filter.FilterPermanent; import mage.filter.common.FilterLandPermanent; -import mage.filter.predicate.permanent.EnchantPlayerControlsPredicate; import mage.game.permanent.token.ZombieDecayedToken; import mage.target.TargetPlayer; @@ -26,7 +26,7 @@ public final class CurseOfTheRestlessDead extends CardImpl { private static final FilterPermanent filter = new FilterLandPermanent(); static { - filter.add(EnchantPlayerControlsPredicate.instance); + filter.add(TargetController.ENCHANTED.getControllerPredicate()); } public CurseOfTheRestlessDead(UUID ownerId, CardSetInfo setInfo) { diff --git a/Mage.Sets/src/mage/cards/c/CurseOfUnbinding.java b/Mage.Sets/src/mage/cards/c/CurseOfUnbinding.java new file mode 100644 index 00000000000..2cc4c2494ae --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/CurseOfUnbinding.java @@ -0,0 +1,92 @@ +package mage.cards.c; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.AttachEffect; +import mage.abilities.keyword.EnchantAbility; +import mage.cards.*; +import mage.constants.*; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetPlayer; + +import java.util.UUID; + +/** + * @author TheElk801 + */ +public final class CurseOfUnbinding extends CardImpl { + + public CurseOfUnbinding(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{6}{U}"); + + this.subtype.add(SubType.AURA); + this.subtype.add(SubType.CURSE); + + // Enchant player + TargetPlayer auraTarget = new TargetPlayer(); + this.getSpellAbility().addTarget(auraTarget); + this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature)); + Ability ability = new EnchantAbility(auraTarget.getTargetName()); + this.addAbility(ability); + + // At the beginning of enchanted player's upkeep, that player reveals cards from the top of their library until they reveal a creature card. Put that card onto the battlefield under your control. That player puts the rest of the revealed cards into their graveyard. + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new CurseOfConformityEffect(), TargetController.ENCHANTED, false + )); + } + + private CurseOfUnbinding(final CurseOfUnbinding card) { + super(card); + } + + @Override + public CurseOfUnbinding copy() { + return new CurseOfUnbinding(this); + } +} + +class CurseOfUnbindingEffect extends OneShotEffect { + + CurseOfUnbindingEffect() { + super(Outcome.Benefit); + staticText = "that player reveals cards from the top of their library " + + "until they reveal a creature card. Put that card onto the battlefield under your control. " + + "That player puts the rest of the revealed cards into their graveyard"; + } + + private CurseOfUnbindingEffect(final CurseOfUnbindingEffect effect) { + super(effect); + } + + @Override + public CurseOfUnbindingEffect copy() { + return new CurseOfUnbindingEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(game.getActivePlayerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); + Card toHand = null; + for (Card card : player.getLibrary().getCards(game)) { + cards.add(card); + if (card.isCreature(game)) { + toHand = card; + break; + } + } + player.revealCards(source, cards, game); + Player controller = game.getPlayer(source.getControllerId()); + if (toHand != null && controller != null) { + controller.moveCards(toHand, Zone.BATTLEFIELD, source, game); + } + cards.retainZone(Zone.LIBRARY, game); + player.moveCards(cards, Zone.GRAVEYARD, source, game); + return true; + } +} diff --git a/Mage.Sets/src/mage/sets/MidnightHuntCommander.java b/Mage.Sets/src/mage/sets/MidnightHuntCommander.java index 80be93aca31..1a8172815c2 100644 --- a/Mage.Sets/src/mage/sets/MidnightHuntCommander.java +++ b/Mage.Sets/src/mage/sets/MidnightHuntCommander.java @@ -50,6 +50,7 @@ public final class MidnightHuntCommander extends ExpansionSet { cards.add(new SetCardInfo("Crowded Crypt", 17, Rarity.RARE, mage.cards.c.CrowdedCrypt.class)); cards.add(new SetCardInfo("Curse of Clinging Webs", 25, Rarity.RARE, mage.cards.c.CurseOfClingingWebs.class)); cards.add(new SetCardInfo("Curse of Conformity", 6, Rarity.RARE, mage.cards.c.CurseOfConformity.class)); + cards.add(new SetCardInfo("Curse of Unbinding", 12, Rarity.RARE, mage.cards.c.CurseOfUnbinding.class)); cards.add(new SetCardInfo("Curse of the Restless Dead", 18, Rarity.RARE, mage.cards.c.CurseOfTheRestlessDead.class)); cards.add(new SetCardInfo("Custodi Soulbinders", 83, Rarity.RARE, mage.cards.c.CustodiSoulbinders.class)); cards.add(new SetCardInfo("Dark Salvation", 110, Rarity.RARE, mage.cards.d.DarkSalvation.class)); diff --git a/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java index afd3a00a7ab..7f49922366e 100644 --- a/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/BeginningOfUpkeepTriggeredAbility.java @@ -14,8 +14,8 @@ import mage.target.targetpointer.FixedTarget; */ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl { - private TargetController targetController; - private boolean setTargetPointer; + private final TargetController targetController; + private final boolean setTargetPointer; protected String ruleTrigger; public BeginningOfUpkeepTriggeredAbility(Effect effect, TargetController targetController, boolean isOptional) { @@ -59,30 +59,20 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl { switch (targetController) { case YOU: boolean yours = event.getPlayerId().equals(this.controllerId); - if (yours && setTargetPointer) { - if (getTargets().isEmpty()) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } - } + if (yours && setTargetPointer && getTargets().isEmpty()) { + this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); } return yours; case NOT_YOU: boolean notYours = !event.getPlayerId().equals(this.controllerId); - if (notYours && setTargetPointer) { - if (getTargets().isEmpty()) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } - } + if (notYours && setTargetPointer && getTargets().isEmpty()) { + this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); } return notYours; case OPPONENT: if (game.getPlayer(this.controllerId).hasOpponent(event.getPlayerId(), game)) { if (setTargetPointer && getTargets().isEmpty()) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } + this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); } return true; } @@ -91,9 +81,7 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl { case ACTIVE: case EACH_PLAYER: if (setTargetPointer && getTargets().isEmpty()) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } + this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); } return true; case CONTROLLER_ATTACHED_TO: @@ -102,16 +90,23 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl { Permanent attachedTo = game.getPermanent(attachment.getAttachedTo()); if (attachedTo != null && attachedTo.isControlledBy(event.getPlayerId())) { if (setTargetPointer && getTargets().isEmpty()) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getPlayerId())); - } + this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); } return true; } } break; + case ENCHANTED: + Permanent permanent = getSourcePermanentIfItStillExists(game); + if (permanent == null || !game.isActivePlayer(permanent.getAttachedTo())) { + break; + } + if (setTargetPointer && getTargets().isEmpty()) { + this.getEffects().setTargetPointer(new FixedTarget(event.getPlayerId())); + } + return true; default: - throw new UnsupportedOperationException("Value for targetController not supported: " + targetController.toString()); + throw new UnsupportedOperationException("Value for targetController not supported: " + targetController); } return false; } @@ -133,6 +128,8 @@ public class BeginningOfUpkeepTriggeredAbility extends TriggeredAbilityImpl { return "At the beginning of each upkeep, " + generateZoneString(); case CONTROLLER_ATTACHED_TO: return "At the beginning of the upkeep of enchanted creature's controller, " + generateZoneString(); + case ENCHANTED: + return "At the beginning of enchanted player's upkeep, " + generateZoneString(); } return ""; } diff --git a/Mage/src/main/java/mage/constants/TargetController.java b/Mage/src/main/java/mage/constants/TargetController.java index c827820bbdd..7bdfac067b0 100644 --- a/Mage/src/main/java/mage/constants/TargetController.java +++ b/Mage/src/main/java/mage/constants/TargetController.java @@ -1,12 +1,11 @@ package mage.constants; import mage.cards.Card; -import mage.filter.predicate.ObjectPlayer; -import mage.filter.predicate.ObjectPlayerPredicate; import mage.filter.predicate.ObjectSourcePlayer; import mage.filter.predicate.ObjectSourcePlayerPredicate; import mage.game.Controllable; import mage.game.Game; +import mage.game.permanent.Permanent; import mage.players.Player; import java.util.UUID; @@ -26,6 +25,7 @@ public enum TargetController { CONTROLLER_ATTACHED_TO, NEXT, EACH_PLAYER, + ENCHANTED, SOURCE_TARGETS; private final OwnerPredicate ownerPredicate; @@ -50,7 +50,7 @@ public enum TargetController { return controllerPredicate; } - public static class OwnerPredicate implements ObjectPlayerPredicate> { + public static class OwnerPredicate implements ObjectSourcePlayerPredicate> { private final TargetController targetOwner; @@ -59,7 +59,7 @@ public enum TargetController { } @Override - public boolean apply(ObjectPlayer input, Game game) { + public boolean apply(ObjectSourcePlayer input, Game game) { Card card = input.getObject(); UUID playerId = input.getPlayerId(); if (card == null || playerId == null) { @@ -83,6 +83,9 @@ public enum TargetController { return true; } break; + case ENCHANTED: + Permanent permanent = game.getPermanent(input.getSourceId()); + return permanent != null && input.getObject().isOwnedBy(permanent.getAttachedTo()); case ANY: return true; } @@ -140,7 +143,7 @@ public enum TargetController { } } - public static class ControllerPredicate implements ObjectPlayerPredicate> { + public static class ControllerPredicate implements ObjectSourcePlayerPredicate> { private final TargetController controller; @@ -149,7 +152,7 @@ public enum TargetController { } @Override - public boolean apply(ObjectPlayer input, Game game) { + public boolean apply(ObjectSourcePlayer input, Game game) { Controllable object = input.getObject(); UUID playerId = input.getPlayerId(); @@ -180,6 +183,9 @@ public enum TargetController { return true; } break; + case ENCHANTED: + Permanent permanent = game.getPermanent(input.getSourceId()); + return permanent != null && input.getObject().isControlledBy(permanent.getAttachedTo()); case ANY: return true; } diff --git a/Mage/src/main/java/mage/filter/predicate/permanent/EnchantPlayerControlsPredicate.java b/Mage/src/main/java/mage/filter/predicate/permanent/EnchantPlayerControlsPredicate.java deleted file mode 100644 index d0086b1fbb3..00000000000 --- a/Mage/src/main/java/mage/filter/predicate/permanent/EnchantPlayerControlsPredicate.java +++ /dev/null @@ -1,19 +0,0 @@ -package mage.filter.predicate.permanent; - -import mage.filter.predicate.ObjectSourcePlayer; -import mage.filter.predicate.ObjectSourcePlayerPredicate; -import mage.game.Game; -import mage.game.permanent.Permanent; - -/** - * @author TheElk801 - */ -public enum EnchantPlayerControlsPredicate implements ObjectSourcePlayerPredicate> { - instance; - - @Override - public boolean apply(ObjectSourcePlayer input, Game game) { - Permanent permanent = game.getPermanent(input.getSourceId()); - return permanent != null && input.getObject().isControlledBy(permanent.getAttachedTo()); - } -}