diff --git a/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java b/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java index b3b9532bbec..fa68bfd5821 100644 --- a/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java +++ b/Mage.Sets/src/mage/cards/a/AngelOfSerenity.java @@ -55,7 +55,8 @@ public final class AngelOfSerenity extends CardImpl { this.addAbility(ability); // When Angel of Serenity leaves the battlefield, return the exiled cards to their owners' hands. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.HAND).withText(true, true), false)); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.HAND) + .withText(true, true, false), false)); } private AngelOfSerenity(final AngelOfSerenity card) { diff --git a/Mage.Sets/src/mage/cards/b/BomatCourier.java b/Mage.Sets/src/mage/cards/b/BomatCourier.java index 4ae9d51a81e..ccf0f49a78b 100644 --- a/Mage.Sets/src/mage/cards/b/BomatCourier.java +++ b/Mage.Sets/src/mage/cards/b/BomatCourier.java @@ -3,23 +3,18 @@ package mage.cards.b; import java.util.UUID; import mage.MageInt; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.AttacksTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardHandCost; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.ColoredManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileCardsFromTopOfLibraryControllerEffect; +import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.abilities.keyword.HasteAbility; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; -import mage.game.ExileZone; -import mage.game.Game; -import mage.players.Player; -import mage.util.CardUtil; /** * @@ -37,10 +32,15 @@ public final class BomatCourier extends CardImpl { this.addAbility(HasteAbility.getInstance()); // Whenever Bomat Courier attacks, exile the top card of your library face down. - this.addAbility(new AttacksTriggeredAbility(new BomatCourierExileEffect(), false)); + this.addAbility(new AttacksTriggeredAbility( + new ExileCardsFromTopOfLibraryControllerEffect(1, true, true, true), + false)); // {R}, Discard your hand, Sacrifice Bomat Courier: Put all cards exiled with Bomat Courier into their owners' hands. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new BomatCourierReturnEffect(), new ColoredManaCost(ColoredManaSymbol.R)); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new ReturnFromExileForSourceEffect(Zone.HAND).withText(true, true, true), + new ColoredManaCost(ColoredManaSymbol.R)); ability.addCost(new DiscardHandCost()); ability.addCost(new SacrificeSourceCost()); this.addAbility(ability); @@ -55,67 +55,3 @@ public final class BomatCourier extends CardImpl { return new BomatCourier(this); } } - -class BomatCourierExileEffect extends OneShotEffect { - - BomatCourierExileEffect() { - super(Outcome.Exile); - this.staticText = "exile the top card of your library face down"; - } - - private BomatCourierExileEffect(final BomatCourierExileEffect effect) { - super(effect); - } - - @Override - public BomatCourierExileEffect copy() { - return new BomatCourierExileEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - Card card = controller.getLibrary().getFromTop(game); - if (card != null) { - UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - card.setFaceDown(true, game); - controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName()); - card.setFaceDown(true, game); - return true; - } - } - return false; - } -} - -class BomatCourierReturnEffect extends OneShotEffect { - - BomatCourierReturnEffect() { - super(Outcome.DrawCard); - this.staticText = "Put all cards exiled with {this} into their owners' hands"; - } - - private BomatCourierReturnEffect(final BomatCourierReturnEffect effect) { - super(effect); - } - - @Override - public BomatCourierReturnEffect copy() { - return new BomatCourierReturnEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter())); - if (exileZone != null) { - controller.moveCards(exileZone, Zone.HAND, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/c/ConnectingTheDots.java b/Mage.Sets/src/mage/cards/c/ConnectingTheDots.java new file mode 100644 index 00000000000..0e634309abd --- /dev/null +++ b/Mage.Sets/src/mage/cards/c/ConnectingTheDots.java @@ -0,0 +1,48 @@ +package mage.cards.c; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.AttacksCreatureYouControlTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardHandCost; +import mage.abilities.costs.common.SacrificeSourceCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.effects.common.ExileCardsFromTopOfLibraryControllerEffect; +import mage.abilities.effects.common.ReturnFromExileForSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Zone; + +/** + * @author Cguy7777 + */ +public final class ConnectingTheDots extends CardImpl { + + public ConnectingTheDots(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{R}"); + + // Whenever a creature you control attacks, exile the top card of your library face down. + this.addAbility(new AttacksCreatureYouControlTriggeredAbility( + new ExileCardsFromTopOfLibraryControllerEffect(1, true, true, true))); + + // {1}{R}, Discard your hand, Sacrifice Connecting the Dots: Put all cards exiled with Connecting the Dots into their owners' hands. + Ability ability = new SimpleActivatedAbility( + new ReturnFromExileForSourceEffect(Zone.HAND) + .withText(true, true, true), + new ManaCostsImpl<>("{1}{R}")); + ability.addCost(new DiscardHandCost()); + ability.addCost(new SacrificeSourceCost()); + this.addAbility(ability); + } + + private ConnectingTheDots(final ConnectingTheDots card) { + super(card); + } + + @Override + public ConnectingTheDots copy() { + return new ConnectingTheDots(this); + } +} diff --git a/Mage.Sets/src/mage/cards/e/ExpertLevelSafe.java b/Mage.Sets/src/mage/cards/e/ExpertLevelSafe.java new file mode 100644 index 00000000000..629216547b3 --- /dev/null +++ b/Mage.Sets/src/mage/cards/e/ExpertLevelSafe.java @@ -0,0 +1,95 @@ +package mage.cards.e; + +import java.util.UUID; + +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTriggeredAbility; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; +import mage.abilities.costs.mana.GenericManaCost; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileCardsFromTopOfLibraryControllerEffect; +import mage.abilities.effects.common.ReturnFromExileForSourceEffect; +import mage.abilities.effects.common.SacrificeSourceEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; +import mage.target.common.TargetOpponent; + +/** + * @author Cguy7777 + */ +public final class ExpertLevelSafe extends CardImpl { + + public ExpertLevelSafe(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}"); + + // When Expert-Level Safe enters the battlefield, exile the top two cards of your library face down. + this.addAbility(new EntersBattlefieldTriggeredAbility( + new ExileCardsFromTopOfLibraryControllerEffect(2, true, true))); + + // {1}, {T}: You and target opponent each secretly choose 1, 2, or 3. Then those choices are revealed. + // If they match, sacrifice Expert-Level Safe and put all cards exiled with it into their owners' hands. + // Otherwise, exile the top card of your library face down. + Ability ability = new SimpleActivatedAbility(new ExpertLevelSafeEffect(), new GenericManaCost(1)); + ability.addCost(new TapSourceCost()); + ability.addTarget(new TargetOpponent()); + this.addAbility(ability); + } + + private ExpertLevelSafe(final ExpertLevelSafe card) { + super(card); + } + + @Override + public ExpertLevelSafe copy() { + return new ExpertLevelSafe(this); + } +} + +class ExpertLevelSafeEffect extends OneShotEffect { + + ExpertLevelSafeEffect() { + super(Outcome.Benefit); + staticText = "you and target opponent each secretly choose 1, 2, or 3. Then those choices are revealed. " + + "If they match, sacrifice {this} and put all cards exiled with it into their owners' hands. " + + "Otherwise, exile the top card of your library face down"; + } + + protected ExpertLevelSafeEffect(ExpertLevelSafeEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller == null || opponent == null) { + return false; + } + + int controllerChoice = controller.getAmount(1, 3, "Choose a number", game); + int opponentChoice = opponent.getAmount(1, 3, "Choose a number", game); + + game.informPlayers(controller.getLogName() + " chose " + controllerChoice); + game.informPlayers(opponent.getLogName() + " chose " + opponentChoice); + + if (controllerChoice == opponentChoice) { + new SacrificeSourceEffect().apply(game, source); + new ReturnFromExileForSourceEffect(Zone.HAND).apply(game, source); + return true; + } + + new ExileCardsFromTopOfLibraryControllerEffect(1, true, true).apply(game, source); + return true; + } + + @Override + public ExpertLevelSafeEffect copy() { + return new ExpertLevelSafeEffect(this); + } +} diff --git a/Mage.Sets/src/mage/cards/f/FreeForAll.java b/Mage.Sets/src/mage/cards/f/FreeForAll.java index 630f6bc995c..6a858935ef0 100644 --- a/Mage.Sets/src/mage/cards/f/FreeForAll.java +++ b/Mage.Sets/src/mage/cards/f/FreeForAll.java @@ -5,6 +5,7 @@ import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.cards.Cards; @@ -36,7 +37,8 @@ public final class FreeForAll extends CardImpl { this.addAbility(new BeginningOfUpkeepTriggeredAbility(new FreeForAllReturnFromExileEffect(), TargetController.ANY, false)); // When Free-for-All leaves the battlefield, put all cards exiled with it into their owners' graveyards. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new FreeForAllLeavesBattlefieldEffect(), false)); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.GRAVEYARD) + .setText("put all cards exiled with it into their owners' graveyards"), false)); } private FreeForAll(final FreeForAll card) { @@ -111,29 +113,3 @@ class FreeForAllReturnFromExileEffect extends OneShotEffect { return player.moveCards(exiledCards.getRandom(game), Zone.BATTLEFIELD, source, game); } } - -class FreeForAllLeavesBattlefieldEffect extends OneShotEffect { - - FreeForAllLeavesBattlefieldEffect() { - super(Outcome.Detriment); - this.staticText = "put all cards exiled with it into their owners' graveyards"; - } - - private FreeForAllLeavesBattlefieldEffect(final FreeForAllLeavesBattlefieldEffect effect) { - super(effect); - } - - @Override - public FreeForAllLeavesBattlefieldEffect copy() { - return new FreeForAllLeavesBattlefieldEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - ExileZone exZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source)); - return controller != null - && exZone != null - && controller.moveCards(exZone.getCards(game), Zone.GRAVEYARD, source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/g/Gravegouger.java b/Mage.Sets/src/mage/cards/g/Gravegouger.java index e16cf4f74bd..78d25387bb8 100644 --- a/Mage.Sets/src/mage/cards/g/Gravegouger.java +++ b/Mage.Sets/src/mage/cards/g/Gravegouger.java @@ -34,7 +34,8 @@ public final class Gravegouger extends CardImpl { this.addAbility(ability); // When Gravegouger leaves the battlefield, return the exiled cards to their owner's graveyard. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.GRAVEYARD).withText(true, false), false)); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.GRAVEYARD) + .withText(true, false, false), false)); } private Gravegouger(final Gravegouger card) { diff --git a/Mage.Sets/src/mage/cards/k/KnowledgeVault.java b/Mage.Sets/src/mage/cards/k/KnowledgeVault.java index c5bf3c62143..95665972de9 100644 --- a/Mage.Sets/src/mage/cards/k/KnowledgeVault.java +++ b/Mage.Sets/src/mage/cards/k/KnowledgeVault.java @@ -2,25 +2,23 @@ package mage.cards.k; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.LeavesBattlefieldTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileCardsFromTopOfLibraryControllerEffect; import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.abilities.effects.common.discard.DiscardHandControllerEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.game.ExileZone; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; -import mage.util.CardUtil; /** * @@ -32,13 +30,20 @@ public final class KnowledgeVault extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{4}"); // {2}, {T}: Exile the top card of your library face down. - this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new KnowledgeVaultExileEffect(), new GenericManaCost(2))); + Ability ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new ExileCardsFromTopOfLibraryControllerEffect(1, true, true), + new GenericManaCost(2)); + ability.addCost(new TapSourceCost()); + this.addAbility(ability); // {0}: Sacrifice Knowledge Vault. If you do, discard your hand, then put all cards exiled with Knowledge Vault into their owner’s hand. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new KnowledgeVaultReturnEffect(), new GenericManaCost(0))); // When Knowledge Vault leaves the battlefield, put all cards exiled with Knowledge Vault into their owner’s graveyard. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.GRAVEYARD), false)); + this.addAbility(new LeavesBattlefieldTriggeredAbility( + new ReturnFromExileForSourceEffect(Zone.GRAVEYARD).withText(true, false, true), + false)); } private KnowledgeVault(final KnowledgeVault card) { @@ -51,40 +56,6 @@ public final class KnowledgeVault extends CardImpl { } } -class KnowledgeVaultExileEffect extends OneShotEffect { - - KnowledgeVaultExileEffect() { - super(Outcome.Exile); - this.staticText = "exile the top card of your library face down"; - } - - private KnowledgeVaultExileEffect(final KnowledgeVaultExileEffect effect) { - super(effect); - } - - @Override - public KnowledgeVaultExileEffect copy() { - return new KnowledgeVaultExileEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - Card card = controller.getLibrary().getFromTop(game); - if (card != null) { - UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - card.setFaceDown(true, game); - controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName()); - card.setFaceDown(true, game); - return true; - } - } - return false; - } -} - class KnowledgeVaultReturnEffect extends OneShotEffect { KnowledgeVaultReturnEffect() { @@ -108,10 +79,7 @@ class KnowledgeVaultReturnEffect extends OneShotEffect { if (sourcePermanent != null && controller != null) { if (sourcePermanent.sacrifice(source, game)) { new DiscardHandControllerEffect().apply(game, source); - ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter())); - if (exileZone != null) { - controller.moveCards(exileZone, Zone.HAND, source, game); - } + new ReturnFromExileForSourceEffect(Zone.HAND).apply(game, source); } return true; } diff --git a/Mage.Sets/src/mage/cards/k/KyrenArchive.java b/Mage.Sets/src/mage/cards/k/KyrenArchive.java index 808a1a43ad2..e51f3646873 100644 --- a/Mage.Sets/src/mage/cards/k/KyrenArchive.java +++ b/Mage.Sets/src/mage/cards/k/KyrenArchive.java @@ -2,25 +2,19 @@ package mage.cards.k; import java.util.UUID; -import mage.MageObject; import mage.abilities.Ability; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.DiscardHandCost; import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; +import mage.abilities.effects.common.ExileCardsFromTopOfLibraryControllerEffect; +import mage.abilities.effects.common.ReturnFromExileForSourceEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.TargetController; import mage.constants.Zone; -import mage.game.ExileZone; -import mage.game.Game; -import mage.players.Player; -import mage.util.CardUtil; /** * @@ -32,12 +26,16 @@ public final class KyrenArchive extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // At the beginning of your upkeep, you may exile the top card of your library face down. - this.addAbility(new BeginningOfUpkeepTriggeredAbility(new KyrenArchiveExileEffect(), TargetController.YOU, true)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new ExileCardsFromTopOfLibraryControllerEffect(1, true, true), + TargetController.YOU, + true) + ); // {5}, Discard your hand, Sacrifice Kyren Archive: Put all cards exiled with Kyren Archive into their owner's hand. Ability ability = new SimpleActivatedAbility( Zone.BATTLEFIELD, - new KyrenArchiveReturnEffect(), + new ReturnFromExileForSourceEffect(Zone.HAND).withText(true, false, true), new GenericManaCost(5) ); ability.addCost(new DiscardHandCost()); @@ -54,67 +52,3 @@ public final class KyrenArchive extends CardImpl { return new KyrenArchive(this); } } - -class KyrenArchiveExileEffect extends OneShotEffect { - - KyrenArchiveExileEffect() { - super(Outcome.Exile); - this.staticText = "exile the top card of your library face down"; - } - - private KyrenArchiveExileEffect(final KyrenArchiveExileEffect effect) { - super(effect); - } - - @Override - public KyrenArchiveExileEffect copy() { - return new KyrenArchiveExileEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - Card card = controller.getLibrary().getFromTop(game); - if (card != null) { - UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - card.setFaceDown(true, game); - controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName()); - card.setFaceDown(true, game); - return true; - } - } - return false; - } -} - -class KyrenArchiveReturnEffect extends OneShotEffect { - - KyrenArchiveReturnEffect() { - super(Outcome.DrawCard); - this.staticText = "Put all cards exiled with {this} into their owners' hands"; - } - - private KyrenArchiveReturnEffect(final KyrenArchiveReturnEffect effect) { - super(effect); - } - - @Override - public KyrenArchiveReturnEffect copy() { - return new KyrenArchiveReturnEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - ExileZone exileZone = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter())); - if (exileZone != null) { - controller.moveCards(exileZone, Zone.HAND, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MysticForge.java b/Mage.Sets/src/mage/cards/m/MysticForge.java index 09ad165fa8c..158399d614a 100644 --- a/Mage.Sets/src/mage/cards/m/MysticForge.java +++ b/Mage.Sets/src/mage/cards/m/MysticForge.java @@ -5,21 +5,17 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.PayLifeCost; import mage.abilities.costs.common.TapSourceCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileCardsFromTopOfLibraryControllerEffect; import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; import mage.abilities.effects.common.continuous.PlayTheTopCardEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.common.FilterNonlandCard; import mage.filter.predicate.Predicates; import mage.filter.predicate.mageobject.ColorlessPredicate; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -47,7 +43,7 @@ public final class MysticForge extends CardImpl { this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false))); // {T}, Pay 1 life: Exile the top card of your library. - Ability ability = new SimpleActivatedAbility(new MysticForgeExileEffect(), new TapSourceCost()); + Ability ability = new SimpleActivatedAbility(new ExileCardsFromTopOfLibraryControllerEffect(1), new TapSourceCost()); ability.addCost(new PayLifeCost(1)); this.addAbility(ability); } @@ -61,29 +57,3 @@ public final class MysticForge extends CardImpl { return new MysticForge(this); } } - -class MysticForgeExileEffect extends OneShotEffect { - - MysticForgeExileEffect() { - super(Outcome.Benefit); - staticText = "exile the top card of your library"; - } - - private MysticForgeExileEffect(final MysticForgeExileEffect effect) { - super(effect); - } - - @Override - public MysticForgeExileEffect copy() { - return new MysticForgeExileEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller == null) { - return false; - } - return controller.moveCards(controller.getLibrary().getFromTop(game), Zone.EXILED, source, game); - } -} diff --git a/Mage.Sets/src/mage/cards/p/Petradon.java b/Mage.Sets/src/mage/cards/p/Petradon.java index 77b0fe40694..634ae5333d8 100644 --- a/Mage.Sets/src/mage/cards/p/Petradon.java +++ b/Mage.Sets/src/mage/cards/p/Petradon.java @@ -15,7 +15,6 @@ import mage.constants.CardType; import mage.constants.Duration; import mage.constants.SubType; import mage.constants.Zone; -import mage.filter.StaticFilters; import mage.target.common.TargetLandPermanent; import java.util.UUID; @@ -38,7 +37,8 @@ public final class Petradon extends CardImpl { this.addAbility(ability); // When Petradon leaves the battlefield, return the exiled cards to the battlefield under their owners' control. - this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD).withText(true, true), false)); + this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileForSourceEffect(Zone.BATTLEFIELD) + .withText(true, true, false), false)); // {R}: Petradon gets +1/+0 until end of turn. this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 0, Duration.EndOfTurn), new ManaCostsImpl<>("{R}"))); diff --git a/Mage.Sets/src/mage/cards/p/PrecognitionField.java b/Mage.Sets/src/mage/cards/p/PrecognitionField.java index fda488a38f6..1641ba976c8 100644 --- a/Mage.Sets/src/mage/cards/p/PrecognitionField.java +++ b/Mage.Sets/src/mage/cards/p/PrecognitionField.java @@ -1,23 +1,17 @@ package mage.cards.p; -import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.GenericManaCost; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileCardsFromTopOfLibraryControllerEffect; import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; import mage.abilities.effects.common.continuous.PlayTheTopCardEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Outcome; import mage.constants.TargetController; -import mage.constants.Zone; import mage.filter.FilterCard; import mage.filter.predicate.Predicates; -import mage.game.Game; -import mage.players.Player; import java.util.UUID; @@ -45,7 +39,7 @@ public final class PrecognitionField extends CardImpl { this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(TargetController.YOU, filter, false))); // {3}: Exile the top card of your library. - this.addAbility(new SimpleActivatedAbility(new PrecognitionFieldExileEffect(), new GenericManaCost(3))); + this.addAbility(new SimpleActivatedAbility(new ExileCardsFromTopOfLibraryControllerEffect(1), new GenericManaCost(3))); } private PrecognitionField(final PrecognitionField card) { @@ -57,33 +51,3 @@ public final class PrecognitionField extends CardImpl { return new PrecognitionField(this); } } - -class PrecognitionFieldExileEffect extends OneShotEffect { - - PrecognitionFieldExileEffect() { - super(Outcome.Benefit); - staticText = "exile the top card of your library"; - } - - private PrecognitionFieldExileEffect(final PrecognitionFieldExileEffect effect) { - super(effect); - } - - @Override - public PrecognitionFieldExileEffect copy() { - return new PrecognitionFieldExileEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - Card card = controller.getLibrary().getFromTop(game); - if (card != null) { - controller.moveCards(card, Zone.EXILED, source, game); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java b/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java index a206032303c..662ef87239a 100644 --- a/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java +++ b/Mage.Sets/src/mage/cards/r/RonaDiscipleOfGix.java @@ -11,7 +11,7 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileCardsFromTopOfLibraryControllerEffect; import mage.abilities.effects.common.ExileTargetEffect; import mage.cards.Card; import mage.cards.CardImpl; @@ -26,7 +26,6 @@ import mage.constants.Zone; import mage.filter.common.FilterHistoricCard; import mage.game.ExileZone; import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetCardInYourGraveyard; import mage.util.CardUtil; @@ -59,7 +58,10 @@ public final class RonaDiscipleOfGix extends CardImpl { this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new RonaDiscipleOfGixPlayNonLandEffect())); // {4}, {T}: Exile the top card of your library. - ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new RonaDiscipleOfGixExileEffect(), new GenericManaCost(4)); + ability = new SimpleActivatedAbility( + Zone.BATTLEFIELD, + new ExileCardsFromTopOfLibraryControllerEffect(1, true), + new GenericManaCost(4)); ability.addCost(new TapSourceCost()); this.addAbility(ability); } @@ -111,35 +113,3 @@ class RonaDiscipleOfGixPlayNonLandEffect extends AsThoughEffectImpl { return false; } } - -class RonaDiscipleOfGixExileEffect extends OneShotEffect { - - RonaDiscipleOfGixExileEffect() { - super(Outcome.Exile); - this.staticText = "Exile the top card of your library"; - } - - private RonaDiscipleOfGixExileEffect(final RonaDiscipleOfGixExileEffect effect) { - super(effect); - } - - @Override - public RonaDiscipleOfGixExileEffect copy() { - return new RonaDiscipleOfGixExileEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - MageObject sourceObject = source.getSourceObject(game); - if (controller != null && sourceObject != null) { - Card card = controller.getLibrary().getFromTop(game); - if (card != null) { - UUID exileId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter()); - controller.moveCardsToExile(card, source, game, true, exileId, sourceObject.getIdName()); - } - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/t/TheaterOfHorrors.java b/Mage.Sets/src/mage/cards/t/TheaterOfHorrors.java index 8cd90df81c2..d17b81bd724 100644 --- a/Mage.Sets/src/mage/cards/t/TheaterOfHorrors.java +++ b/Mage.Sets/src/mage/cards/t/TheaterOfHorrors.java @@ -6,8 +6,8 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.AsThoughEffectImpl; -import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.DamageTargetEffect; +import mage.abilities.effects.common.ExileCardsFromTopOfLibraryControllerEffect; import mage.abilities.hint.common.OpponentsLostLifeHint; import mage.cards.Card; import mage.cards.CardImpl; @@ -15,7 +15,6 @@ import mage.cards.CardSetInfo; import mage.constants.*; import mage.game.ExileZone; import mage.game.Game; -import mage.players.Player; import mage.target.common.TargetOpponentOrPlaneswalker; import mage.util.CardUtil; import mage.watchers.common.PlayerLostLifeWatcher; @@ -32,7 +31,7 @@ public final class TheaterOfHorrors extends CardImpl { // At the beginning of your upkeep, exile the top card of your library. this.addAbility(new BeginningOfUpkeepTriggeredAbility( - new TheaterOfHorrorsExileEffect(), + new ExileCardsFromTopOfLibraryControllerEffect(1, true), TargetController.YOU, false )); @@ -58,39 +57,6 @@ public final class TheaterOfHorrors extends CardImpl { } } -class TheaterOfHorrorsExileEffect extends OneShotEffect { - - TheaterOfHorrorsExileEffect() { - super(Outcome.Benefit); - staticText = "exile the top card of your library."; - } - - private TheaterOfHorrorsExileEffect(final TheaterOfHorrorsExileEffect effect) { - super(effect); - } - - @Override - public TheaterOfHorrorsExileEffect copy() { - return new TheaterOfHorrorsExileEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player == null) { - return false; - } - Card card = player.getLibrary().getFromTop(game); - if (card == null) { - return false; - } - return player.moveCardsToExile( - card, source, game, true, CardUtil.getCardExileZoneId(game, source), - CardUtil.createObjectRealtedWindowTitle(source, game, null) - ); - } -} - class TheaterOfHorrorsCastEffect extends AsThoughEffectImpl { TheaterOfHorrorsCastEffect() { diff --git a/Mage.Sets/src/mage/cards/w/WormfangBehemoth.java b/Mage.Sets/src/mage/cards/w/WormfangBehemoth.java index 4511da5417c..310c255b6cf 100644 --- a/Mage.Sets/src/mage/cards/w/WormfangBehemoth.java +++ b/Mage.Sets/src/mage/cards/w/WormfangBehemoth.java @@ -37,7 +37,7 @@ public final class WormfangBehemoth extends CardImpl { // When Wormfang Behemoth leaves the battlefield, return the exiled cards to their owner's hand. this.addAbility(new LeavesBattlefieldTriggeredAbility( - new ReturnFromExileForSourceEffect(Zone.HAND).withText(true, false), false + new ReturnFromExileForSourceEffect(Zone.HAND).withText(true, false, false), false )); } diff --git a/Mage.Sets/src/mage/sets/Fallout.java b/Mage.Sets/src/mage/sets/Fallout.java index eb211f9293e..ac6726a0139 100644 --- a/Mage.Sets/src/mage/sets/Fallout.java +++ b/Mage.Sets/src/mage/sets/Fallout.java @@ -70,6 +70,8 @@ public final class Fallout extends ExpansionSet { cards.add(new SetCardInfo("Everflowing Chalice", 230, Rarity.UNCOMMON, mage.cards.e.EverflowingChalice.class)); cards.add(new SetCardInfo("Evolving Wilds", 263, Rarity.COMMON, mage.cards.e.EvolvingWilds.class)); cards.add(new SetCardInfo("Exotic Orchard", 264, Rarity.RARE, mage.cards.e.ExoticOrchard.class)); + cards.add(new SetCardInfo("Expert-Level Safe", 133, Rarity.UNCOMMON, mage.cards.e.ExpertLevelSafe.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Expert-Level Safe", 661, Rarity.UNCOMMON, mage.cards.e.ExpertLevelSafe.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Explorer's Scope", 231, Rarity.COMMON, mage.cards.e.ExplorersScope.class)); cards.add(new SetCardInfo("Farewell", 353, Rarity.RARE, mage.cards.f.Farewell.class)); cards.add(new SetCardInfo("Farseek", 197, Rarity.COMMON, mage.cards.f.Farseek.class)); diff --git a/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java b/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java index 9cade3be47c..04ad3635429 100644 --- a/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java +++ b/Mage.Sets/src/mage/sets/MurdersAtKarlovManor.java @@ -70,6 +70,8 @@ public final class MurdersAtKarlovManor extends ExpansionSet { cards.add(new SetCardInfo("Cold Case Cracker", 46, Rarity.COMMON, mage.cards.c.ColdCaseCracker.class)); cards.add(new SetCardInfo("Commercial District", 259, Rarity.RARE, mage.cards.c.CommercialDistrict.class)); cards.add(new SetCardInfo("Concealed Weapon", 117, Rarity.UNCOMMON, mage.cards.c.ConcealedWeapon.class)); + cards.add(new SetCardInfo("Connecting the Dots", 118, Rarity.RARE, mage.cards.c.ConnectingTheDots.class, NON_FULL_USE_VARIOUS)); + cards.add(new SetCardInfo("Connecting the Dots", 403, Rarity.RARE, mage.cards.c.ConnectingTheDots.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Convenient Target", 119, Rarity.UNCOMMON, mage.cards.c.ConvenientTarget.class)); cards.add(new SetCardInfo("Cornered Crook", 120, Rarity.UNCOMMON, mage.cards.c.CorneredCrook.class)); cards.add(new SetCardInfo("Crime Novelist", 121, Rarity.UNCOMMON, mage.cards.c.CrimeNovelist.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/ExileCardsFromTopOfLibraryControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ExileCardsFromTopOfLibraryControllerEffect.java new file mode 100644 index 00000000000..62567f40912 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/ExileCardsFromTopOfLibraryControllerEffect.java @@ -0,0 +1,100 @@ +package mage.abilities.effects.common; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.constants.Outcome; +import mage.game.Game; +import mage.players.Player; +import mage.util.CardUtil; + +import java.util.Set; +import java.util.UUID; + +/** + * @author Cguy7777 + */ +public class ExileCardsFromTopOfLibraryControllerEffect extends OneShotEffect { + + private final int amount; + private final boolean toUniqueExileZone; + private final boolean faceDown; + + public ExileCardsFromTopOfLibraryControllerEffect(int amount) { + this(amount, false); + } + + public ExileCardsFromTopOfLibraryControllerEffect(int amount, boolean toUniqueExileZone) { + this(amount, toUniqueExileZone, false); + } + + public ExileCardsFromTopOfLibraryControllerEffect(int amount, boolean toUniqueExileZone, boolean faceDown) { + this(amount, toUniqueExileZone, faceDown, false); + } + + /** + * @param amount number of cards to exile + * @param toUniqueExileZone moves the card to a source object dependant + * unique exile zone, so another effect of the same source object (e.g. + * Theater of Horrors) can identify the card + * @param faceDown if true, cards are exiled face down + * @param withFaceDownReminderText if true, add the reminder text for exiling one face down card + */ + public ExileCardsFromTopOfLibraryControllerEffect(int amount, boolean toUniqueExileZone, boolean faceDown, boolean withFaceDownReminderText) { + super(Outcome.Exile); + this.amount = amount; + this.toUniqueExileZone = toUniqueExileZone; + this.faceDown = faceDown; + + staticText = "exile the top " + + ((amount > 1) ? CardUtil.numberToText(amount) + " cards" : "card") + + " of your library" + + (faceDown ? " face down" : "") + + (withFaceDownReminderText ? ". (You can't look at it.)" : ""); + } + + protected ExileCardsFromTopOfLibraryControllerEffect(final ExileCardsFromTopOfLibraryControllerEffect effect) { + super(effect); + this.amount = effect.amount; + this.toUniqueExileZone = effect.toUniqueExileZone; + this.faceDown = effect.faceDown; + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + UUID exileZoneId = null; + String exileZoneName = ""; + if (toUniqueExileZone) { + MageObject sourceObject = source.getSourceObject(game); + if (sourceObject == null) { + return false; + } + exileZoneId = CardUtil.getExileZoneId(game, source); + exileZoneName = CardUtil.createObjectRealtedWindowTitle(source, game, null); + } + + Set cards = controller.getLibrary().getTopCards(game, amount); + if (cards.isEmpty()) { + return true; + } + + boolean exiledSuccessfully = false; + for (Card card : cards) { + card.setFaceDown(faceDown, game); + exiledSuccessfully |= controller.moveCardsToExile(card, source, game, !faceDown, exileZoneId, exileZoneName); + card.setFaceDown(faceDown, game); + } + return exiledSuccessfully; + } + + @Override + public ExileCardsFromTopOfLibraryControllerEffect copy() { + return new ExileCardsFromTopOfLibraryControllerEffect(this); + } +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java index c0771ccab9e..0bcb084d1a0 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ReturnFromExileForSourceEffect.java @@ -22,6 +22,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { private final Zone returnToZone; private boolean pluralCards; private boolean pluralOwners; + private boolean putPhrasing; /** * @param zone Zone the card should return to @@ -31,6 +32,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { this.returnToZone = zone; this.pluralCards = false; this.pluralOwners = false; + this.putPhrasing = false; updateText(); } @@ -39,6 +41,7 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { this.returnToZone = effect.returnToZone; this.pluralCards = effect.pluralCards; this.pluralOwners = effect.pluralOwners; + this.putPhrasing = effect.putPhrasing; } @Override @@ -77,16 +80,22 @@ public class ReturnFromExileForSourceEffect extends OneShotEffect { return true; } - public ReturnFromExileForSourceEffect withText(boolean pluralCards, boolean pluralOwners) { + public ReturnFromExileForSourceEffect withText(boolean pluralCards, boolean pluralOwners, boolean putPhrasing) { this.pluralCards = pluralCards; this.pluralOwners = pluralOwners; + this.putPhrasing = putPhrasing; updateText(); return this; } private void updateText() { StringBuilder sb = new StringBuilder(); - sb.append("return the exiled ").append(pluralCards ? "cards" : "card").append(" to "); + if (putPhrasing) { + sb.append("put ").append(pluralCards ? "all cards " : "the card ").append("exiled with {this} "); + sb.append(returnToZone == Zone.BATTLEFIELD ? "onto " : "into "); + } else { + sb.append("return the exiled ").append(pluralCards ? "cards" : "card").append(" to "); + } if (returnToZone == Zone.BATTLEFIELD) { sb.append("the battlefield under "); }