updated various cards to improve how they handle exiling with info (#7615)

This commit is contained in:
Evan Kranzler 2021-02-22 15:26:58 -05:00 committed by GitHub
parent bb0a995541
commit bd3777997e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 349 additions and 442 deletions

View file

@ -3,8 +3,7 @@ package mage.cards.b;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.effects.common.ExileTargetForSourceEffect;
import mage.abilities.effects.common.ReturnFromExileEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
@ -13,9 +12,10 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates;
import mage.target.common.TargetControlledPermanent;
import mage.target.TargetPermanent;
import java.util.UUID;
@ -24,6 +24,12 @@ import java.util.UUID;
*/
public final class BragoKingEternal extends CardImpl {
private static final FilterPermanent filter = new FilterControlledPermanent("nonland permanents you control");
static {
filter.add(Predicates.not(CardType.LAND.getPredicate()));
}
public BragoKingEternal(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}");
addSuperType(SuperType.LEGENDARY);
@ -34,14 +40,11 @@ public final class BragoKingEternal extends CardImpl {
// Flying
this.addAbility(FlyingAbility.getInstance());
// When Brago, King Eternal deals combat damage to a player, exile any number of target nonland permanents you control, then return those cards to the battlefield under their owner's control.
Effect effect = new ExileTargetEffect(this.getId(), this.getName(), Zone.BATTLEFIELD);
effect.setText("exile any number of target nonland permanents you control");
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(effect, false);
FilterControlledPermanent filterControlledNonlandPermanent = new FilterControlledPermanent();
filterControlledNonlandPermanent.add(Predicates.not(CardType.LAND.getPredicate()));
ability.addTarget(new TargetControlledPermanent(0, Integer.MAX_VALUE, filterControlledNonlandPermanent, false));
ability.addEffect(new ReturnFromExileEffect(this.getId(), Zone.BATTLEFIELD, ", then return those cards to the battlefield under their owner's control"));
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new ExileTargetForSourceEffect().setText("exile any number of target nonland permanents you control"), false);
ability.addTarget(new TargetPermanent(0, Integer.MAX_VALUE, filter, false));
ability.addEffect(new ReturnFromExileEffect(Zone.BATTLEFIELD, ", then return those cards to the battlefield under their owner's control"));
this.addAbility(ability);
}

View file

@ -144,7 +144,7 @@ class BreechesBrazenPlundererEffect extends OneShotEffect {
return false;
}
for (Card card : cards.getCards(game)) {
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.EndOfTurn);
CardUtil.makeCardPlayable(game, source, card, Duration.EndOfTurn, true);
}
return true;
}

View file

@ -91,7 +91,7 @@ class CovetousUrgeEffect extends OneShotEffect {
if (card.getSpellAbility() == null) {
return true;
}
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.Custom);
CardUtil.makeCardPlayable(game, source, card, Duration.Custom, true);
return true;
}
}

View file

@ -1,4 +1,3 @@
package mage.cards.c;
import mage.abilities.Ability;
@ -12,19 +11,16 @@ import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPlayer;
import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/**
*
* @author BetaSteward
*/
public final class CurseOfOblivion extends CardImpl {
@ -56,11 +52,11 @@ public final class CurseOfOblivion extends CardImpl {
class CurseOfOblivionAbility extends TriggeredAbilityImpl {
public CurseOfOblivionAbility() {
super(Zone.BATTLEFIELD, new ExileFromZoneTargetEffect(Zone.GRAVEYARD, null, "", new FilterCard(), 2));
CurseOfOblivionAbility() {
super(Zone.BATTLEFIELD, new ExileFromZoneTargetEffect(Zone.GRAVEYARD, StaticFilters.FILTER_CARD_CARDS, 2, false));
}
public CurseOfOblivionAbility(final CurseOfOblivionAbility ability) {
private CurseOfOblivionAbility(final CurseOfOblivionAbility ability) {
super(ability);
}
@ -76,20 +72,16 @@ class CurseOfOblivionAbility extends TriggeredAbilityImpl {
@Override
public boolean checkTrigger(GameEvent event, Game game) {
Permanent enchantment = game.getPermanent(this.sourceId);
if (enchantment != null && enchantment.getAttachedTo() != null) {
Player player = game.getPlayer(enchantment.getAttachedTo());
if (player != null && game.isActivePlayer(player.getId())) {
this.getEffects().get(0).setTargetPointer(new FixedTarget(player.getId()));
return true;
}
Permanent enchantment = getSourcePermanentOrLKI(game);
if (enchantment == null || !game.isActivePlayer(enchantment.getAttachedTo())) {
return false;
}
return false;
this.getEffects().setTargetPointer(new FixedTarget(enchantment.getAttachedTo()));
return true;
}
@Override
public String getRule() {
return "At the beginning of enchanted player's upkeep, that player exiles two cards from their graveyard.";
}
}

View file

@ -90,7 +90,7 @@ class DaxosOfMeletisEffect extends OneShotEffect {
if (card.getSpellAbility() != null) {
// allow to cast the card
// and you may spend mana as though it were mana of any color to cast it
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.EndOfTurn);
CardUtil.makeCardPlayable(game, source, card, Duration.EndOfTurn, true);
}
}
return true;

View file

@ -15,7 +15,6 @@ import mage.filter.FilterCard;
import mage.filter.predicate.Predicates;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.events.GameEvent.EventType;
import mage.game.events.ZoneChangeEvent;
import mage.players.Player;
import mage.target.common.TargetCardInOpponentsGraveyard;
@ -94,7 +93,7 @@ class DireFleetDaredevilEffect extends OneShotEffect {
targetCard = game.getCard(targetCard.getId());
if (targetCard != null) {
// you may play and spend any mana
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, targetCard, Duration.EndOfTurn);
CardUtil.makeCardPlayable(game, source, targetCard, Duration.EndOfTurn, true);
// exile from graveyard
ContinuousEffect effect = new DireFleetDaredevilReplacementEffect();
effect.setTargetPointer(new FixedTarget(targetCard, game));

View file

@ -1,42 +1,37 @@
package mage.cards.f;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.costs.common.SacrificeTargetCost;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.common.ExileFromZoneTargetEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.RegenerateSourceEffect;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.FilterCard;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.game.ExileZone;
import mage.filter.common.FilterControlledPermanent;
import mage.game.Game;
import mage.target.common.TargetControlledCreaturePermanent;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetControlledPermanent;
import mage.target.common.TargetDiscard;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author BetaSteward
*/
public final class FiendOfTheShadows extends CardImpl {
private UUID exileId = UUID.randomUUID();
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("a Human");
static {
filter.add(SubType.HUMAN.getPredicate());
}
private static final FilterControlledPermanent filter = new FilterControlledPermanent(SubType.HUMAN, "a Human");
public FiendOfTheShadows(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{B}");
this.subtype.add(SubType.VAMPIRE);
this.subtype.add(SubType.WIZARD);
@ -44,12 +39,12 @@ public final class FiendOfTheShadows extends CardImpl {
this.toughness = new MageInt(3);
this.addAbility(FlyingAbility.getInstance());
// Whenever Fiend of the Shadows deals combat damage to a player, that player exiles a card from their hand. You may play that card for as long as it remains exiled.
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new ExileFromZoneTargetEffect(Zone.HAND, exileId, "Fiend of the Shadows", new FilterCard()), false, true));
this.addAbility(new SimpleStaticAbility(Zone.ALL, new FiendOfTheShadowsEffect(exileId)));
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new FiendOfTheShadowsEffect(), false, true));
// Sacrifice a Human: Regenerate Fiend of the Shadows.
this.addAbility(new SimpleActivatedAbility(Zone.BATTLEFIELD, new RegenerateSourceEffect(), new SacrificeTargetCost(new TargetControlledCreaturePermanent(1, 1, filter, false))));
this.addAbility(new SimpleActivatedAbility(new RegenerateSourceEffect(), new SacrificeTargetCost(new TargetControlledPermanent(filter))));
}
private FiendOfTheShadows(final FiendOfTheShadows card) {
@ -62,24 +57,16 @@ public final class FiendOfTheShadows extends CardImpl {
}
}
class FiendOfTheShadowsEffect extends AsThoughEffectImpl {
class FiendOfTheShadowsEffect extends OneShotEffect {
private final UUID exileId;
public FiendOfTheShadowsEffect(UUID exileId) {
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfGame, Outcome.Benefit);
this.exileId = exileId;
staticText = "You may play that card for as long as it remains exiled";
FiendOfTheShadowsEffect() {
super(Outcome.Discard);
staticText = "that player exiles a card from their hand. " +
"You may play that card for as long as it remains exiled";
}
public FiendOfTheShadowsEffect(final FiendOfTheShadowsEffect effect) {
private FiendOfTheShadowsEffect(final FiendOfTheShadowsEffect effect) {
super(effect);
this.exileId = effect.exileId;
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
@ -88,14 +75,23 @@ class FiendOfTheShadowsEffect extends AsThoughEffectImpl {
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
if (affectedControllerId.equals(source.getControllerId())) {
ExileZone zone = game.getExile().getExileZone(exileId);
if (zone != null && zone.contains(objectId)) {
return true;
}
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
MageObject sourceObject = source.getSourceObject(game);
if (player == null || sourceObject == null || player.getHand().isEmpty()) {
return false;
}
return false;
TargetCard targetCard = new TargetDiscard(player.getId());
player.choose(outcome, targetCard, source.getSourceId(), game);
Card card = game.getCard(targetCard.getFirstTarget());
if (card == null) {
return false;
}
player.moveCardToExileWithInfo(
card, CardUtil.getExileZoneId(game, source), sourceObject.getName(),
source, game, Zone.HAND, true
);
CardUtil.makeCardPlayable(game, source, card, Duration.Custom, false);
return true;
}
}

View file

@ -157,7 +157,7 @@ class GrenzoHavocRaiserEffect extends OneShotEffect {
if (card.getSpellAbility() != null) {
// allow to cast the card
// and you may spend mana as though it were mana of any color to cast it
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.EndOfTurn);
CardUtil.makeCardPlayable(game, source, card, Duration.EndOfTurn, true);
}
}
return true;

View file

@ -1,8 +1,5 @@
package mage.cards.h;
import java.util.UUID;
import mage.MageInt;
import mage.MageObject;
import mage.abilities.Ability;
@ -15,24 +12,24 @@ import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.common.FilterArtifactCard;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInLibrary;
import mage.util.CardUtil;
import java.util.UUID;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public final class HoardingDragon extends CardImpl {
public HoardingDragon(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{R}{R}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}");
this.subtype.add(SubType.DRAGON);
this.power = new MageInt(4);
@ -41,10 +38,10 @@ public final class HoardingDragon extends CardImpl {
this.addAbility(FlyingAbility.getInstance());
// When Hoarding Dragon enters the battlefield, you may search your library for an artifact card, exile it, then shuffle your library.
this.addAbility(new EntersBattlefieldTriggeredAbility(new HoardingDragonEffect(this.getId()), true));
this.addAbility(new EntersBattlefieldTriggeredAbility(new HoardingDragonEffect(), true));
// When Hoarding Dragon dies, you may put the exiled card into its owner's hand.
this.addAbility(new DiesSourceTriggeredAbility(new ReturnFromExileEffect(this.getId(), Zone.HAND), false));
this.addAbility(new DiesSourceTriggeredAbility(new ReturnFromExileEffect(Zone.HAND), false));
}
private HoardingDragon(final HoardingDragon card) {
@ -60,42 +57,35 @@ public final class HoardingDragon extends CardImpl {
class HoardingDragonEffect extends OneShotEffect {
private final UUID exileId;
public HoardingDragonEffect(UUID exileId) {
HoardingDragonEffect() {
super(Outcome.Exile);
this.exileId = exileId;
this.staticText = "you may search your library for an artifact card, exile it, then shuffle your library";
}
public HoardingDragonEffect(final HoardingDragonEffect effect) {
private HoardingDragonEffect(final HoardingDragonEffect effect) {
super(effect);
this.exileId = effect.exileId;
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
MageObject sourceObject = source.getSourceObject(game);
if (controller != null && sourceObject != null) {
TargetCardInLibrary target = new TargetCardInLibrary(new FilterArtifactCard());
if (controller.searchLibrary(target, source, game)) {
if (!target.getTargets().isEmpty()) {
Card card = controller.getLibrary().getCard(target.getFirstTarget(), game);
if (card != null) {
controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source, game, Zone.LIBRARY, true);
}
}
}
controller.shuffleLibrary(source, game);
return true;
}
return false;
UUID exileId = CardUtil.getExileZoneId(game, source);
if (controller == null || sourceObject == null) {
return false;
}
TargetCardInLibrary target = new TargetCardInLibrary(new FilterArtifactCard());
controller.searchLibrary(target, source, game);
Card card = controller.getLibrary().getCard(target.getFirstTarget(), game);
if (card != null) {
controller.moveCardToExileWithInfo(card, exileId, sourceObject.getIdName(), source, game, Zone.LIBRARY, true);
}
controller.shuffleLibrary(source, game);
return true;
}
@Override
public HoardingDragonEffect copy() {
return new HoardingDragonEffect(this);
}
}

View file

@ -93,7 +93,7 @@ class HostageTakerExileEffect extends OneShotEffect {
UUID exileId = CardUtil.getCardExileZoneId(game, source);
controller.moveCardToExileWithInfo(card, exileId, permanent.getIdName(), source, game, Zone.BATTLEFIELD, true);
// allow to cast the card and you may spend mana as though it were mana of any color to cast it
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.Custom);
CardUtil.makeCardPlayable(game, source, card, Duration.Custom, true);
return true;
}
}

View file

@ -1,27 +1,27 @@
package mage.cards.i;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.ReturnFromExileEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.ExileZone;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
import java.util.Objects;
import java.util.UUID;
/**
*
* @author jeffwadsworth
*/
public final class IgnorantBliss extends CardImpl {
@ -30,9 +30,7 @@ public final class IgnorantBliss extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{R}");
// Exile all cards from your hand face down. At the beginning of the next end step, return those cards to your hand, then draw a card.
this.getSpellAbility().addEffect(new IgnorantBlissExileEffect());
this.getSpellAbility().addEffect(new IgnorantBlissReturnEffect());
this.getSpellAbility().addEffect(new IgnorantBlissEffect());
}
private IgnorantBliss(final IgnorantBliss card) {
@ -45,71 +43,40 @@ public final class IgnorantBliss extends CardImpl {
}
}
class IgnorantBlissExileEffect extends OneShotEffect {
class IgnorantBlissEffect extends OneShotEffect {
IgnorantBlissExileEffect() {
IgnorantBlissEffect() {
super(Outcome.Exile);
this.staticText = "Exile all cards from your hand face down";
this.staticText = "Exile all cards from your hand face down. At the beginning of the next end step, " +
"return those cards to your hand, then draw a card";
}
IgnorantBlissExileEffect(final IgnorantBlissExileEffect effect) {
private IgnorantBlissEffect(final IgnorantBlissEffect effect) {
super(effect);
}
@Override
public IgnorantBlissExileEffect copy() {
return new IgnorantBlissExileEffect(this);
public IgnorantBlissEffect copy() {
return new IgnorantBlissEffect(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) {
Cards hand = controller.getHand();
hand.getCards(game).stream().filter((card) -> (card != null)).map((card) -> {
UUID exileZoneId = CardUtil.getExileZoneId(game, source.getSourceId(), 0);
controller.moveCardsToExile(card, source, game, false, exileZoneId, sourceObject.getIdName());
return card;
}).forEachOrdered((card) -> {
card.setFaceDown(true, game);
});
return true;
if (controller == null || sourceObject == null) {
return false;
}
return false;
}
}
class IgnorantBlissReturnEffect extends OneShotEffect {
IgnorantBlissReturnEffect() {
super(Outcome.DrawCard);
this.staticText = "At the beginning of the next end step, return those cards to your hand, then draw a card";
}
IgnorantBlissReturnEffect(final IgnorantBlissReturnEffect effect) {
super(effect);
}
@Override
public IgnorantBlissReturnEffect copy() {
return new IgnorantBlissReturnEffect(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(), 0));
if (exileZone != null) {
Effect effect = new ReturnFromExileEffect(exileZone.getId(), Zone.HAND);
AtTheBeginOfNextEndStepDelayedTriggeredAbility ability = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect);
ability.addEffect(new DrawCardSourceControllerEffect(1));
game.addDelayedTriggeredAbility(ability, source);
return true;
}
}
return false;
Cards hand = new CardsImpl(controller.getHand());
controller.moveCardsToExile(hand.getCards(game), source, game, false, CardUtil.getExileZoneId(game, source), sourceObject.getIdName());
hand.getCards(game)
.stream()
.filter(Objects::nonNull)
.filter(card -> game.getState().getZone(card.getId()) == Zone.EXILED)
.forEach(card -> card.setFaceDown(true, game));
DelayedTriggeredAbility ability = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromExileEffect(Zone.HAND));
ability.addEffect(new DrawCardSourceControllerEffect(1));
game.addDelayedTriggeredAbility(ability, source);
return true;
}
}

View file

@ -146,7 +146,7 @@ class KingNarfisBetrayalSecondEffect extends OneShotEffect {
ExileZone zone = game.getExile().getExileZone(CardUtil.getCardExileZoneId(game, source));
if (zone != null) {
for (Card card : zone.getCards(game)) {
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.EndOfTurn);
CardUtil.makeCardPlayable(game, source, card, Duration.EndOfTurn, true);
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.k;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SpellCastControllerTriggeredAbility;
@ -12,18 +10,18 @@ import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class KyokiSanitysEclipse extends CardImpl {
public KyokiSanitysEclipse(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{4}{B}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{B}");
addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.DEMON);
this.subtype.add(SubType.SPIRIT);
@ -32,10 +30,12 @@ public final class KyokiSanitysEclipse extends CardImpl {
this.toughness = new MageInt(4);
// Whenever you cast a Spirit or Arcane spell, target opponent exiles a card from their hand.
Ability ability = new SpellCastControllerTriggeredAbility(new ExileFromZoneTargetEffect(Zone.HAND, null, "", new FilterCard()), StaticFilters.SPIRIT_OR_ARCANE_CARD, false);
Ability ability = new SpellCastControllerTriggeredAbility(
new ExileFromZoneTargetEffect(Zone.HAND, false),
StaticFilters.SPIRIT_OR_ARCANE_CARD, false
);
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}
private KyokiSanitysEclipse(final KyokiSanitysEclipse card) {

View file

@ -14,7 +14,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.FilterSpell;
import mage.filter.predicate.mageobject.ColorPredicate;
import mage.target.TargetPlayer;
@ -41,13 +40,14 @@ public final class MerrowBonegnawer extends CardImpl {
this.toughness = new MageInt(1);
// {tap}: Target player exiles a card from their graveyard.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileFromZoneTargetEffect(Zone.GRAVEYARD, null, getIdName(), new FilterCard()), new TapSourceCost());
Ability ability = new SimpleActivatedAbility(
new ExileFromZoneTargetEffect(Zone.GRAVEYARD, false), new TapSourceCost()
);
ability.addTarget(new TargetPlayer());
this.addAbility(ability);
// Whenever you cast a black spell, you may untap Merrow Bonegnawer.
this.addAbility(new SpellCastControllerTriggeredAbility(Zone.BATTLEFIELD, new UntapSourceEffect(), filter, true, false));
this.addAbility(new SpellCastControllerTriggeredAbility(new UntapSourceEffect(), filter, true, false));
}
private MerrowBonegnawer(final MerrowBonegnawer card) {

View file

@ -1,12 +1,9 @@
package mage.cards.m;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ExileFromZoneTargetEffect;
import mage.abilities.keyword.CantBeBlockedSourceAbility;
import mage.abilities.keyword.DevoidAbility;
@ -15,17 +12,17 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class Mindmelter extends CardImpl {
public Mindmelter(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}{B}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}{B}");
this.subtype.add(SubType.ELDRAZI);
this.subtype.add(SubType.DRONE);
this.power = new MageInt(2);
@ -38,9 +35,9 @@ public final class Mindmelter extends CardImpl {
this.addAbility(new CantBeBlockedSourceAbility());
// {3}{C}: Target opponent exiles a card from their hand. Activate this ability only any time you could cast a sorcery.
Effect effect = new ExileFromZoneTargetEffect(Zone.HAND, null, "", new FilterCard());
effect.setText("Target opponent exiles a card from their hand");
Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, effect, new ManaCostsImpl("{3}{C}"));
Ability ability = new ActivateAsSorceryActivatedAbility(
Zone.BATTLEFIELD, new ExileFromZoneTargetEffect(Zone.HAND, false), new ManaCostsImpl("{3}{C}")
);
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
}

View file

@ -101,7 +101,7 @@ class OppositionAgentReplacementEffect extends ReplacementEffectImpl {
// You may play those cards for as long as they remain exiled, and you may spend mana as though it were mana of any color to cast them
for (Card card : cardsToExile) {
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.Custom);
CardUtil.makeCardPlayable(game, source, card, Duration.Custom, true);
}
// return false all the time

View file

@ -1,12 +1,9 @@
package mage.cards.p;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
import mage.abilities.costs.common.RemoveCountersSourceCost;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ExileFromZoneTargetEffect;
import mage.abilities.effects.common.ReturnFromExileEffect;
import mage.abilities.keyword.FadingAbility;
@ -15,17 +12,15 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.counters.CounterType;
import mage.filter.FilterCard;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author spjspj
*/
public final class ParallaxNexus extends CardImpl {
private UUID exileId = UUID.randomUUID();
public ParallaxNexus(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}");
@ -33,14 +28,16 @@ public final class ParallaxNexus extends CardImpl {
this.addAbility(new FadingAbility(5, this));
// Remove a fade counter from Parallax Nexus: Target opponent exiles a card from their hand. Activate this ability only any time you could cast a sorcery.
Effect effect = new ExileFromZoneTargetEffect(Zone.HAND, exileId, "Parallax Nexus", new FilterCard());
effect.setText("Target opponent exiles a card from their hand");
Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD, effect, new RemoveCountersSourceCost(CounterType.FADE.createInstance()));
Ability ability = new ActivateAsSorceryActivatedAbility(
Zone.BATTLEFIELD,
new ExileFromZoneTargetEffect(Zone.HAND, true),
new RemoveCountersSourceCost(CounterType.FADE.createInstance())
);
ability.addTarget(new TargetOpponent());
this.addAbility(ability);
// When Parallax Nexus leaves the battlefield, each player returns to their hand all cards they own exiled with Parallax Nexus.
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileEffect(exileId, Zone.HAND), false));
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileEffect(Zone.HAND), false));
}
private ParallaxNexus(final ParallaxNexus card) {

View file

@ -80,7 +80,7 @@ class PlaneswalkersMischiefEffect extends OneShotEffect {
AsThoughEffect effect = new PlaneswalkersMischiefCastFromExileEffect();
effect.setTargetPointer(new FixedTarget(revealedCard.getId()));
game.addEffect(effect, source);
OneShotEffect effect2 = new ReturnFromExileEffect(source.getSourceId(), Zone.HAND);
OneShotEffect effect2 = new ReturnFromExileEffect(Zone.HAND);
Condition condition = new PlaneswalkersMischiefCondition(source.getSourceId(), revealedCard.getId());
ConditionalOneShotEffect effect3 = new ConditionalOneShotEffect(effect2, condition, "if you haven't cast it, return it to its owner's hand.");
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect3);

View file

@ -1,13 +1,11 @@
package mage.cards.p;
import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.AsThoughEffect;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ReturnFromExileEffect;
import mage.cards.Card;
@ -16,15 +14,15 @@ import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.common.FilterInstantOrSorceryCard;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.TargetCard;
import mage.target.TargetPlayer;
import mage.target.targetpointer.FixedTarget;
import mage.watchers.common.SpellsCastWatcher;
import mage.util.CardUtil;
import mage.watchers.Watcher;
import java.util.List;
import java.util.UUID;
import java.util.*;
/**
* @author L_J (significantly based on code by jeffwadsworth and Styxo)
@ -35,9 +33,9 @@ public final class PsychicTheft extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{U}");
// Target player reveals their hand. You choose an instant or sorcery card from it and exile that card. You may cast that card for as long as it remains exiled. At the beginning of the next end step, if you haven't cast the card, return it to its owner's hand.
this.getSpellAbility().addTarget(new TargetPlayer());
this.getSpellAbility().addEffect(new PsychicTheftEffect());
this.getSpellAbility().addTarget(new TargetPlayer());
this.getSpellAbility().addWatcher(new PsychicTheftWatcher());
}
private PsychicTheft(final PsychicTheft card) {
@ -54,12 +52,14 @@ class PsychicTheftEffect extends OneShotEffect {
private static final FilterInstantOrSorceryCard filter = new FilterInstantOrSorceryCard();
public PsychicTheftEffect() {
PsychicTheftEffect() {
super(Outcome.Benefit);
this.staticText = "Target player reveals their hand. You choose an instant or sorcery card from it and exile that card. You may cast that card for as long as it remains exiled. At the beginning of the next end step, if you haven't cast the card, return it to its owner's hand.";
this.staticText = "Target player reveals their hand. You choose an instant or sorcery card from it " +
"and exile that card. You may cast that card for as long as it remains exiled. " +
"At the beginning of the next end step, if you haven't cast the card, return it to its owner's hand.";
}
public PsychicTheftEffect(final PsychicTheftEffect effect) {
private PsychicTheftEffect(final PsychicTheftEffect effect) {
super(effect);
}
@ -72,101 +72,76 @@ class PsychicTheftEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) {
Player opponent = game.getPlayer(targetPointer.getFirst(game, source));
MageObject sourceObject = game.getObject(source.getSourceId());
if (opponent != null && sourceObject != null) {
opponent.revealCards(sourceObject.getName(), opponent.getHand(), game);
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
int cardsHand = opponent.getHand().count(filter, game);
Card chosenCard = null;
if (cardsHand > 0) {
TargetCard target = new TargetCard(Zone.HAND, filter);
if (controller.choose(Outcome.Exile, opponent.getHand(), target, game)) {
chosenCard = opponent.getHand().get(target.getFirstTarget(), game);
}
}
if (chosenCard != null) {
opponent.moveCardToExileWithInfo(chosenCard, source.getSourceId(), sourceObject.getIdName(), source, game, Zone.HAND, true);
AsThoughEffect effect = new PsychicTheftCastFromExileEffect();
effect.setTargetPointer(new FixedTarget(chosenCard.getId()));
game.addEffect(effect, source);
OneShotEffect effect2 = new ReturnFromExileEffect(source.getSourceId(), Zone.HAND);
Condition condition = new PsychicTheftCondition(source.getSourceId(), chosenCard.getId());
ConditionalOneShotEffect effect3 = new ConditionalOneShotEffect(effect2, condition, "if you haven't cast it, return it to its owner's hand.");
DelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(effect3);
delayedAbility.addWatcher(new SpellsCastWatcher());
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
if (opponent == null || sourceObject == null) {
return false;
}
opponent.revealCards(sourceObject.getName(), opponent.getHand(), game);
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
int cardsHand = opponent.getHand().count(filter, game);
Card chosenCard = null;
if (cardsHand > 0) {
TargetCard target = new TargetCard(Zone.HAND, filter);
if (controller.choose(Outcome.Exile, opponent.getHand(), target, game)) {
chosenCard = opponent.getHand().get(target.getFirstTarget(), game);
}
}
return false;
}
}
class PsychicTheftCastFromExileEffect extends AsThoughEffectImpl {
PsychicTheftCastFromExileEffect() {
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit);
staticText = "You may cast that card for as long as it remains exiled";
}
PsychicTheftCastFromExileEffect(final PsychicTheftCastFromExileEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
return true;
}
@Override
public PsychicTheftCastFromExileEffect copy() {
return new PsychicTheftCastFromExileEffect(this);
}
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
if (targetPointer.getTargets(game, source).contains(objectId)
&& game.getState().getZone(objectId) == Zone.EXILED) {
Player player = game.getPlayer(source.getControllerId());
Card card = game.getCard(objectId);
return player != null
&& card != null;
if (chosenCard == null) {
return false;
}
return false;
UUID exileId = CardUtil.getExileZoneId(game, source);
controller.moveCardToExileWithInfo(chosenCard, exileId, sourceObject.getIdName(), source, game, Zone.HAND, true);
CardUtil.makeCardPlayable(game, source, chosenCard, Duration.Custom, false);
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
new ConditionalOneShotEffect(
new ReturnFromExileEffect(Zone.HAND),
new PsychicTheftCondition(chosenCard, game),
"if you haven't cast it, return it to its owner's hand."
)
), source);
return true;
}
}
class PsychicTheftCondition implements Condition {
private final MageObjectReference mor;
protected UUID exileId;
protected UUID cardId;
public PsychicTheftCondition(UUID exileId, UUID cardId) {
this.exileId = exileId;
this.cardId = cardId;
PsychicTheftCondition(Card card, Game game) {
this.mor = new MageObjectReference(card.getId(), card.getZoneChangeCounter(game) + 1, game);
}
@Override
public boolean apply(Game game, Ability source) {
if (!game.getExile().getExileZone(exileId).contains(cardId)) {
return false;
}
SpellsCastWatcher watcher = game.getState().getWatcher(SpellsCastWatcher.class);
if (watcher != null) {
List<Spell> spells = watcher.getSpellsCastThisTurn(source.getControllerId());
if (spells != null) {
for (Spell spell : spells) {
if (spell.getSourceId().equals(cardId)) {
return false;
}
}
}
}
return true;
PsychicTheftWatcher watcher = game.getState().getWatcher(PsychicTheftWatcher.class);
return watcher != null && !watcher.checkPlayer(source.getSourceId(), mor);
}
}
class PsychicTheftWatcher extends Watcher {
private final Map<UUID, Set<MageObjectReference>> map = new HashMap<>();
PsychicTheftWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.SPELL_CAST) {
return;
}
Spell spell = game.getSpell(event.getTargetId());
if (spell == null || spell.getCard() == null || spell.getCard().getMainCard() == null) {
return;
}
map.computeIfAbsent(event.getPlayerId(), x -> new HashSet<>()).add(new MageObjectReference(spell.getCard().getMainCard(), game));
}
boolean checkPlayer(UUID playerId, MageObjectReference mor) {
return map.computeIfAbsent(playerId, x -> new HashSet<>()).contains(mor);
}
}

View file

@ -6,8 +6,6 @@ import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.condition.Condition;
import mage.abilities.decorator.ConditionalInterveningIfTriggeredAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.AsThoughManaEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.hint.ConditionHint;
import mage.abilities.keyword.HasteAbility;
@ -16,20 +14,12 @@ 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.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.players.ManaPoolItem;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget;
import mage.util.CardUtil;
import mage.watchers.Watcher;
import mage.watchers.common.AttackedThisTurnWatcher;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
/**
@ -145,7 +135,7 @@ class RobberOfTheRichEffect extends OneShotEffect {
if (card.getSpellAbility() != null) {
// allow to cast the card
// and you may spend mana as though it were mana of any color to cast it
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.Custom, RobberOfTheRichAnyTurnAttackedCondition.instance);
CardUtil.makeCardPlayable(game, source, card, Duration.Custom, true, RobberOfTheRichAnyTurnAttackedCondition.instance);
}
return true;
}

View file

@ -7,7 +7,7 @@ import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.effects.common.ExileTargetForSourceEffect;
import mage.abilities.effects.common.ReturnFromExileEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
@ -27,21 +27,18 @@ public final class SafeHaven extends CardImpl {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
// {2}, {tap}: Exile target creature you control.
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new ExileTargetEffect(this.getId(),
this.getIdName()), new ManaCostsImpl("{2}"));
Ability ability = new SimpleActivatedAbility(new ExileTargetForSourceEffect(), new ManaCostsImpl("{2}"));
ability.addCost(new TapSourceCost());
ability.addTarget(new TargetControlledCreaturePermanent());
this.addAbility(ability);
// At the beginning of your upkeep, you may sacrifice Safe Haven. If you do, return each card exiled with Safe Haven to the battlefield under its owner's control.
ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD,
new DoIfCostPaid(
new ReturnFromExileEffect(this.getId(), Zone.BATTLEFIELD, "return each card exiled with {this} to the battlefield under its owner's control"),
new SacrificeSourceCost()
),
TargetController.YOU,
false);
this.addAbility(ability);
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
new DoIfCostPaid(new ReturnFromExileEffect(
Zone.BATTLEFIELD, "return each card exiled with " +
"{this} to the battlefield under its owner's control"
), new SacrificeSourceCost()), TargetController.YOU, false
));
}
private SafeHaven(final SafeHaven card) {

View file

@ -3,13 +3,11 @@ package mage.cards.s;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.OneShotEffect;
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;
@ -80,7 +78,7 @@ class StolenStrategyEffect extends OneShotEffect {
if (!card.isLand() && card.getSpellAbility() != null) {
// allow to cast the card
// and you may spend mana as though it were mana of any color to cast it
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.EndOfTurn);
CardUtil.makeCardPlayable(game, source, card, Duration.EndOfTurn, true);
}
}
}

View file

@ -83,7 +83,7 @@ class TobiasBeckettEffect extends OneShotEffect {
if (card.getSpellAbility() != null) {
// allow to cast the card
// and you may spend mana as though it were mana of any color to cast it
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, card, Duration.Custom);
CardUtil.makeCardPlayable(game, source, card, Duration.Custom, true);
}
}
return true;

View file

@ -186,7 +186,7 @@ class UrzaAcademyHeadmasterRandomEffect extends OneShotEffect {
break;
case 11: // KARN LIBERATED 1
sb.append("Target player exiles a card from their hand.");
effects.add(new ExileFromZoneTargetEffect(Zone.HAND, null, "", new FilterCard()));
effects.add(new ExileFromZoneTargetEffect(Zone.HAND, true));
target = new TargetPlayer();
break;
case 12: // NISSA SAGE ANIMIST 1

View file

@ -1,7 +1,5 @@
package mage.cards.v;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
@ -11,22 +9,26 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author fireshoes
*/
public final class VesselOfMalignity extends CardImpl {
public VesselOfMalignity(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{1}{B}");
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
// {1}{B}, Sacrifice Vessel of Malignity: Target opponent exiles two cards from their hand. Activate this ability only any time you could cast a sorcery.
Ability ability = new ActivateAsSorceryActivatedAbility(Zone.BATTLEFIELD,
new ExileFromZoneTargetEffect(Zone.HAND, null, "", new FilterCard("cards"), 2),
new ManaCostsImpl("{1}{B}"));
Ability ability = new ActivateAsSorceryActivatedAbility(
Zone.BATTLEFIELD,
new ExileFromZoneTargetEffect(
Zone.HAND, StaticFilters.FILTER_CARD_CARDS, 2, false
), new ManaCostsImpl("{1}{B}")
);
ability.addCost(new SacrificeSourceCost());
ability.addTarget(new TargetOpponent());
this.addAbility(ability);

View file

@ -1,7 +1,5 @@
package mage.cards.w;
import java.util.UUID;
import mage.MageInt;
import mage.abilities.common.EndOfCombatTriggeredAbility;
import mage.abilities.common.LeavesBattlefieldTriggeredAbility;
@ -16,27 +14,29 @@ import mage.constants.Zone;
import mage.filter.common.FilterCreaturePermanent;
import mage.filter.predicate.permanent.BlockedByIdPredicate;
import java.util.UUID;
/**
*
* @author LoneFox
*/
public final class WallOfNets extends CardImpl {
public WallOfNets(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{W}{W}");
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}");
this.subtype.add(SubType.WALL);
this.power = new MageInt(0);
this.toughness = new MageInt(7);
// Defender
this.addAbility(DefenderAbility.getInstance());
// At end of combat, exile all creatures blocked by Wall of Nets.
FilterCreaturePermanent filter = new FilterCreaturePermanent("creatures blocked by {this}");
filter.add(new BlockedByIdPredicate(this.getId()));
this.addAbility(new EndOfCombatTriggeredAbility(new ExileAllEffect(filter, this.getId(), this.getIdName()), false));
this.addAbility(new EndOfCombatTriggeredAbility(new ExileAllEffect(filter, true), false));
// When Wall of Nets leaves the battlefield, return all cards exiled with Wall of Nets to the battlefield under their owners' control.
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileEffect(this.getId(),
Zone.BATTLEFIELD, "return all cards exiled with {this} to the battlefield under their owners' control"), false));
this.addAbility(new LeavesBattlefieldTriggeredAbility(new ReturnFromExileEffect(Zone.BATTLEFIELD, "return all cards exiled with {this} to the battlefield under their owners' control"), false));
}
private WallOfNets(final WallOfNets card) {

View file

@ -1,8 +1,5 @@
package mage.cards.w;
import java.util.UUID;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ExileFromZoneTargetEffect;
import mage.abilities.effects.common.LoseLifeTargetEffect;
import mage.abilities.keyword.DevoidAbility;
@ -10,26 +7,28 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.target.common.TargetOpponent;
import java.util.UUID;
/**
*
* @author LevelX2
*/
public final class WitnessTheEnd extends CardImpl {
public WitnessTheEnd(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{3}{B}");
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{B}");
// Devoid
this.addAbility(new DevoidAbility(this.color));
// Target opponent exiles two cards from their hand and loses 2 life.
getSpellAbility().addEffect(new ExileFromZoneTargetEffect(Zone.HAND, null, "", new FilterCard("cards"), 2));
Effect effect = new LoseLifeTargetEffect(2);
effect.setText("and loses 2 life");
getSpellAbility().addTarget(new TargetOpponent());
getSpellAbility().addEffect(effect);
this.getSpellAbility().addEffect(new ExileFromZoneTargetEffect(
Zone.HAND, StaticFilters.FILTER_CARD_CARDS, 2, false
));
this.getSpellAbility().addEffect(new LoseLifeTargetEffect(2).setText("and loses 2 life"));
this.getSpellAbility().addTarget(new TargetOpponent());
}
private WitnessTheEnd(final WitnessTheEnd card) {

View file

@ -45,7 +45,7 @@ public class FiendOfTheShadowsTest extends CardTestPlayerBase {
addCard(Zone.HAND, playerB, "Swamp");
attack(1, playerA, "Fiend of the Shadows");
addTarget(playerB, "Swamp");
setChoice(playerB, "Swamp");
playLand(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Swamp");
setStrictChooseMode(true);

View file

@ -1,44 +1,40 @@
package mage.abilities.effects.common;
import java.util.List;
import java.util.UUID;
import mage.constants.Outcome;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterPermanent;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.util.CardUtil;
/**
*
* @author LevelX2
*/
public class ExileAllEffect extends OneShotEffect {
private FilterPermanent filter;
private String exileZone = null;
private UUID exileId = null;
private final FilterPermanent filter;
private final boolean forSource;
public ExileAllEffect(FilterPermanent filter) {
this(filter, null, null);
this(filter, false);
}
public ExileAllEffect(FilterPermanent filter, UUID exileId, String exileZone) {
public ExileAllEffect(FilterPermanent filter, boolean forSource) {
super(Outcome.Exile);
this.filter = filter;
this.exileZone = exileZone;
this.exileId = exileId;
this.forSource = forSource;
setText();
}
public ExileAllEffect(final ExileAllEffect effect) {
super(effect);
this.filter = effect.filter.copy();
this.exileZone = effect.exileZone;
this.exileId = effect.exileId;
this.forSource = effect.forSource;
}
@Override
@ -49,14 +45,18 @@ public class ExileAllEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
List<Permanent> permanents = game.getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game);
for (Permanent permanent : permanents) {
controller.moveCardToExileWithInfo(permanent, exileId, exileZone, source, game, Zone.BATTLEFIELD, true);
}
return true;
MageObject sourceObject = source.getSourceObject(game);
if (controller == null || sourceObject == null) {
return false;
}
return false;
Cards cards = new CardsImpl();
game.getBattlefield().getActivePermanents(
filter, source.getControllerId(), source.getSourceId(), game
).stream().forEach(cards::add);
if (forSource) {
return controller.moveCardsToExile(cards.getCards(game), source, game, true, CardUtil.getExileZoneId(game, source), sourceObject.getName());
}
return controller.moveCards(cards, Zone.EXILED, source, game);
}

View file

@ -1,14 +1,15 @@
package mage.abilities.effects.common;
import java.util.Locale;
import java.util.UUID;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.cards.Cards;
import mage.cards.CardsImpl;
import mage.constants.Outcome;
import mage.constants.Zone;
import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.players.Player;
import mage.target.Target;
@ -16,29 +17,32 @@ import mage.target.common.TargetCardInHand;
import mage.target.common.TargetCardInYourGraveyard;
import mage.util.CardUtil;
import java.util.Locale;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class ExileFromZoneTargetEffect extends OneShotEffect {
private Zone zone;
private FilterCard filter;
private UUID exileId;
private String exileName;
private int amount;
private final Zone zone;
private final FilterCard filter;
private final int amount;
private final boolean withSource;
public ExileFromZoneTargetEffect(Zone zone, UUID exileId, String exileName, FilterCard filter) {
this(zone, exileId, exileName, filter, 1);
public ExileFromZoneTargetEffect(Zone zone, boolean withSource) {
this(zone, StaticFilters.FILTER_CARD, withSource);
}
public ExileFromZoneTargetEffect(Zone zone, UUID exileId, String exileName, FilterCard filter, int amount) {
public ExileFromZoneTargetEffect(Zone zone, FilterCard filter, boolean withSource) {
this(zone, filter, 1, withSource);
}
public ExileFromZoneTargetEffect(Zone zone, FilterCard filter, int amount, boolean withSource) {
super(Outcome.Exile);
this.zone = zone;
this.filter = filter;
this.exileId = exileId;
this.exileName = exileName;
this.amount = amount;
this.withSource = withSource;
setText();
}
@ -46,33 +50,36 @@ public class ExileFromZoneTargetEffect extends OneShotEffect {
super(effect);
this.zone = effect.zone;
this.filter = effect.filter.copy();
this.exileId = effect.exileId;
this.exileName = effect.exileName;
this.amount = effect.amount;
this.withSource = effect.withSource;
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(targetPointer.getFirst(game, source));
if (player != null) {
Target target = null;
switch (zone) {
case HAND:
target = new TargetCardInHand(Math.min(player.getHand().count(filter, game), amount), filter);
break;
case GRAVEYARD:
target = new TargetCardInYourGraveyard(Math.min(player.getGraveyard().count(filter, game), amount), filter);
break;
default:
}
if (target != null && target.canChoose(source.getSourceId(), player.getId(), game)) {
if (target.chooseTarget(Outcome.Exile, player.getId(), source, game)) {
player.moveCardsToExile(new CardsImpl(target.getTargets()).getCards(game), source, game, true, exileId, exileName);
}
}
MageObject mageObject = source.getSourceObject(game);
if (player == null) {
return false;
}
Target target = null;
switch (zone) {
case HAND:
target = new TargetCardInHand(Math.min(player.getHand().count(filter, game), amount), filter);
break;
case GRAVEYARD:
target = new TargetCardInYourGraveyard(Math.min(player.getGraveyard().count(filter, game), amount), filter);
break;
default:
}
if (target == null || !target.canChoose(source.getSourceId(), player.getId(), game)) {
return true;
}
return false;
target.chooseTarget(Outcome.Exile, player.getId(), source, game);
Cards cards = new CardsImpl(target.getTargets());
if (withSource) {
return player.moveCardsToExile(cards.getCards(game), source, game, true, CardUtil.getExileZoneId(game, source), mageObject.getName());
}
return player.moveCards(cards, Zone.EXILED, source, game);
}
@Override
@ -81,6 +88,7 @@ public class ExileFromZoneTargetEffect extends OneShotEffect {
}
private void setText() {
staticText = "target player exiles " + CardUtil.numberToText(amount, "a") + ' ' + filter.getMessage() + " from their " + zone.toString().toLowerCase(Locale.ENGLISH);
staticText = "target player exiles " + CardUtil.numberToText(amount, "a")
+ ' ' + filter.getMessage() + " from their " + zone.toString().toLowerCase(Locale.ENGLISH);
}
}

View file

@ -1,5 +1,6 @@
package mage.abilities.effects.common;
import mage.MageObject;
import mage.abilities.Ability;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
@ -7,6 +8,8 @@ import mage.constants.Outcome;
import mage.constants.Zone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.util.CardUtil;
/**
* Created by Eric on 9/24/2016.
@ -18,22 +21,21 @@ public class MistmeadowWitchEffect extends OneShotEffect {
staticText = "Exile target creature. Return that card to the battlefield under its owner's control at the beginning of the next end step";
}
public MistmeadowWitchEffect(final MistmeadowWitchEffect effect) {
private MistmeadowWitchEffect(final MistmeadowWitchEffect effect) {
super(effect);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
Permanent permanent = game.getPermanent(source.getFirstTarget());
if (permanent != null) {
if (permanent.moveToExile(source.getSourceId(), "Mistmeadow Witch Exile", source, game)) {
//create delayed triggered ability
AtTheBeginOfNextEndStepDelayedTriggeredAbility delayedAbility = new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromExileEffect(source.getSourceId(), Zone.BATTLEFIELD));
game.addDelayedTriggeredAbility(delayedAbility, source);
return true;
}
MageObject sourceObject = source.getSourceObject(game);
if (player == null || permanent == null || sourceObject == null) {
return false;
}
return false;
player.moveCardsToExile(permanent, source, game, true, CardUtil.getExileZoneId(game, source), sourceObject.getName());
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new ReturnFromExileEffect(Zone.BATTLEFIELD, "return the exiled card to the battlefield under its owner's control")), source);
return true;
}
@Override

View file

@ -1,7 +1,6 @@
package mage.abilities.effects.common;
import java.util.UUID;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
@ -9,29 +8,27 @@ import mage.constants.Zone;
import mage.game.ExileZone;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
/**
*
* @author BetaSteward_at_googlemail.com
*/
public class ReturnFromExileEffect extends OneShotEffect {
private UUID exileId;
private Zone zone;
private boolean tapped;
private final Zone zone;
private final boolean tapped;
public ReturnFromExileEffect(UUID exileId, Zone zone) {
this(exileId, zone, false);
public ReturnFromExileEffect(Zone zone) {
this(zone, false);
}
public ReturnFromExileEffect(UUID exileId, Zone zone, String text) {
this(exileId, zone, false);
public ReturnFromExileEffect(Zone zone, String text) {
this(zone, false);
staticText = text;
}
public ReturnFromExileEffect(UUID exileId, Zone zone, boolean tapped) {
public ReturnFromExileEffect(Zone zone, boolean tapped) {
super(Outcome.PutCardInPlay);
this.exileId = exileId;
this.zone = zone;
this.tapped = tapped;
setText();
@ -39,7 +36,6 @@ public class ReturnFromExileEffect extends OneShotEffect {
public ReturnFromExileEffect(final ReturnFromExileEffect effect) {
super(effect);
this.exileId = effect.exileId;
this.zone = effect.zone;
this.tapped = effect.tapped;
}
@ -51,19 +47,15 @@ public class ReturnFromExileEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
ExileZone exile = game.getExile().getExileZone(exileId);
ExileZone exile = game.getExile().getExileZone(CardUtil.getExileZoneId(game, source));
Player controller = game.getPlayer(source.getControllerId());
if (controller != null && exile != null) {
switch (zone) {
case LIBRARY:
controller.putCardsOnTopOfLibrary(exile, game, source, false);
break;
default:
controller.moveCards(exile.getCards(game), zone, source, game, tapped, false, true, null);
}
return true;
if (controller == null || exile == null) {
return false;
}
return false;
if (zone == Zone.LIBRARY) {
return controller.putCardsOnTopOfLibrary(exile, game, source, false);
}
return controller.moveCards(exile.getCards(game), zone, source, game, tapped, false, true, null);
}
private void setText() {

View file

@ -74,7 +74,7 @@ class TibaltCosmicImpostorPlayFromExileEffect extends AsThoughEffectImpl {
if (exile.contains(mainCardId)
&& affectedControllerId.equals(source.getControllerId())
&& game.getState().getZone(mainCardId).equals(Zone.EXILED)) {
CardUtil.makeCardPlayableAndSpendManaAsAnyColor(game, source, cardInExile, Duration.Custom);
CardUtil.makeCardPlayable(game, source, cardInExile, Duration.Custom, true);
return true;
}
return false;

View file

@ -1102,8 +1102,8 @@ public final class CardUtil {
}
}
public static void makeCardPlayableAndSpendManaAsAnyColor(Game game, Ability source, Card card, Duration duration) {
makeCardPlayableAndSpendManaAsAnyColor(game, source, card, duration, null);
public static void makeCardPlayable(Game game, Ability source, Card card, Duration duration, boolean anyColor) {
makeCardPlayable(game, source, card, duration, anyColor, null);
}
/**
@ -1115,9 +1115,10 @@ public final class CardUtil {
* @param game
* @param card
* @param duration
* @param anyColor
* @param condition can be null
*/
public static void makeCardPlayableAndSpendManaAsAnyColor(Game game, Ability source, Card card, Duration duration, Condition condition) {
public static void makeCardPlayable(Game game, Ability source, Card card, Duration duration, boolean anyColor, Condition condition) {
// Effect can be used for cards in zones and permanents on battlefield
// PermanentCard's ZCC is static, but we need updated ZCC from the card (after moved to another zone)
// So there is a workaround to get actual card's ZCC
@ -1125,7 +1126,9 @@ public final class CardUtil {
UUID objectId = card.getMainCard().getId();
int zcc = game.getState().getZoneChangeCounter(objectId);
game.addEffect(new CanPlayCardControllerEffect(game, objectId, zcc, duration, condition), source);
game.addEffect(new YouMaySpendManaAsAnyColorToCastTargetEffect(duration, condition).setTargetPointer(new FixedTarget(objectId, zcc)), source);
if (anyColor) {
game.addEffect(new YouMaySpendManaAsAnyColorToCastTargetEffect(duration, condition).setTargetPointer(new FixedTarget(objectId, zcc)), source);
}
}
/**