From 746d5eef3b67426953f6984268cbad44ce680d15 Mon Sep 17 00:00:00 2001 From: Evan Kranzler Date: Wed, 24 Feb 2021 14:37:22 -0500 Subject: [PATCH] refactored more zone changes, letters C and D (#7572) Decaying Soil has been heavily reworked --- .../src/mage/cards/c/CharmbreakerDevils.java | 66 ++++----- Mage.Sets/src/mage/cards/c/CitanulFlute.java | 57 +++---- Mage.Sets/src/mage/cards/c/CruelFate.java | 58 +++----- Mage.Sets/src/mage/cards/c/CruelRevival.java | 16 +- Mage.Sets/src/mage/cards/c/CutTheTethers.java | 46 +++--- Mage.Sets/src/mage/cards/d/DarkTutelage.java | 48 +++--- Mage.Sets/src/mage/cards/d/DecayingSoil.java | 140 +++++------------- Mage.Sets/src/mage/cards/d/DecoyGambit.java | 37 +---- .../src/mage/cards/d/DiabolicRevelation.java | 42 +++--- .../src/mage/cards/d/DisplacementWave.java | 29 ++-- Mage.Sets/src/mage/cards/d/DrakeFamiliar.java | 48 +++--- .../common/DiesCreatureTriggeredAbility.java | 4 +- 12 files changed, 234 insertions(+), 357 deletions(-) diff --git a/Mage.Sets/src/mage/cards/c/CharmbreakerDevils.java b/Mage.Sets/src/mage/cards/c/CharmbreakerDevils.java index 0700599043..f281aacd2d 100644 --- a/Mage.Sets/src/mage/cards/c/CharmbreakerDevils.java +++ b/Mage.Sets/src/mage/cards/c/CharmbreakerDevils.java @@ -1,54 +1,45 @@ - package mage.cards.c; -import java.util.UUID; import mage.MageInt; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.common.SpellCastControllerTriggeredAbility; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.CardType; -import mage.constants.SubType; -import mage.constants.Duration; -import mage.constants.Outcome; -import mage.constants.Zone; -import mage.filter.FilterCard; -import mage.filter.FilterSpell; -import mage.filter.predicate.Predicates; +import mage.constants.*; +import mage.filter.StaticFilters; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.players.Player; -import mage.util.RandomUtil; +import mage.target.TargetCard; +import mage.target.common.TargetCardInYourGraveyard; + +import java.util.UUID; /** - * * @author North */ public final class CharmbreakerDevils extends CardImpl { - private static final FilterSpell filter = new FilterSpell("instant or sorcery card"); - - static { - filter.add(Predicates.or( - CardType.INSTANT.getPredicate(), - CardType.SORCERY.getPredicate())); - } - public CharmbreakerDevils(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{R}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}"); this.subtype.add(SubType.DEVIL); this.power = new MageInt(4); this.toughness = new MageInt(4); // At the beginning of your upkeep, return an instant or sorcery card at random from your graveyard to your hand. - this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new CharmbreakerDevilsEffect(), false)); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new CharmbreakerDevilsEffect(), TargetController.YOU, false + )); + // Whenever you cast an instant or sorcery spell, Charmbreaker Devils gets +4/+0 until end of turn. - this.addAbility(new SpellCastControllerTriggeredAbility(new BoostSourceEffect(4, 0, Duration.EndOfTurn), filter, false)); + this.addAbility(new SpellCastControllerTriggeredAbility( + new BoostSourceEffect(4, 0, Duration.EndOfTurn), + StaticFilters.FILTER_SPELL_AN_INSTANT_OR_SORCERY, false + )); } private CharmbreakerDevils(final CharmbreakerDevils card) { @@ -63,12 +54,12 @@ public final class CharmbreakerDevils extends CardImpl { class CharmbreakerDevilsEffect extends OneShotEffect { - public CharmbreakerDevilsEffect() { + CharmbreakerDevilsEffect() { super(Outcome.ReturnToHand); this.staticText = "return an instant or sorcery card at random from your graveyard to your hand"; } - public CharmbreakerDevilsEffect(final CharmbreakerDevilsEffect effect) { + private CharmbreakerDevilsEffect(final CharmbreakerDevilsEffect effect) { super(effect); } @@ -80,19 +71,14 @@ class CharmbreakerDevilsEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - FilterCard filter = new FilterCard("instant or sorcery card"); - filter.add(Predicates.or( - CardType.INSTANT.getPredicate(), - CardType.SORCERY.getPredicate())); - Card[] cards = player.getGraveyard().getCards(filter, game).toArray(new Card[0]); - if (cards.length > 0) { - Card card = cards[RandomUtil.nextInt(cards.length)]; - card.moveToZone(Zone.HAND, source, game, true); - game.informPlayers("Charmbreaker Devils: " + card.getName() + " returned to the hand of " + player.getLogName()); - return true; - } + if (player == null || player.getGraveyard().count(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY, game) < 1) { + return false; } - return false; + TargetCard target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_AND_SORCERY); + target.setRandom(true); + target.setNotTarget(true); + player.choose(outcome, target, source.getSourceId(), game); + Card card = game.getCard(target.getFirstTarget()); + return card != null && player.moveCards(card, Zone.HAND, source, game); } } diff --git a/Mage.Sets/src/mage/cards/c/CitanulFlute.java b/Mage.Sets/src/mage/cards/c/CitanulFlute.java index 739e7a47d9..d4cb750b04 100644 --- a/Mage.Sets/src/mage/cards/c/CitanulFlute.java +++ b/Mage.Sets/src/mage/cards/c/CitanulFlute.java @@ -1,35 +1,38 @@ - package mage.cards.c; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.ComparisonType; import mage.constants.Outcome; import mage.constants.Zone; import mage.filter.FilterCard; +import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author Backfir3 */ public final class CitanulFlute extends CardImpl { public CitanulFlute(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ARTIFACT},"{5}"); + super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{5}"); // {X}, {T}: Search your library for a creature card with converted mana cost X or less, reveal it, // and put it into your hand. Then shuffle your library. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CitanulFluteSearchEffect(), new ManaCostsImpl("{X}")); + Ability ability = new SimpleActivatedAbility(new CitanulFluteSearchEffect(), new ManaCostsImpl("{X}")); ability.addCost(new TapSourceCost()); this.addAbility(ability); } @@ -46,12 +49,13 @@ public final class CitanulFlute extends CardImpl { class CitanulFluteSearchEffect extends OneShotEffect { - public CitanulFluteSearchEffect() { + CitanulFluteSearchEffect() { super(Outcome.DrawCard); - staticText = "Search your library for a creature card with converted mana cost X or less, reveal it, and put it into your hand. Then shuffle your library"; + staticText = "Search your library for a creature card with converted mana cost X or less, " + + "reveal it, and put it into your hand. Then shuffle your library"; } - public CitanulFluteSearchEffect(final CitanulFluteSearchEffect effect) { + private CitanulFluteSearchEffect(final CitanulFluteSearchEffect effect) { super(effect); } @@ -66,32 +70,19 @@ class CitanulFluteSearchEffect extends OneShotEffect { if (player == null) { return false; } - - FilterCard filter = new FilterCard("creature card with converted mana cost X or less"); - filter.add(CardType.CREATURE.getPredicate()); + + FilterCard filter = new FilterCreatureCard("creature card with converted mana cost X or less"); //Set the mana cost one higher to 'emulate' a less than or equal to comparison. filter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1)); - - TargetCardInLibrary target = new TargetCardInLibrary(filter); - if (player.searchLibrary(target, source, game)) { - if (!target.getTargets().isEmpty()) { - Card card = player.getLibrary().getCard(target.getFirstTarget(), game); - Cards cards = new CardsImpl(); - if (card != null){ - card.moveToZone(Zone.HAND, source, game, false); - cards.add(card); - } - String name = "Reveal"; - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null) { - name = sourceCard.getName(); - } - player.revealCards(name, cards, game); - } - player.shuffleLibrary(source, game); - return true; + + TargetCardInLibrary target = new TargetCardInLibrary(filter); + player.searchLibrary(target, source, game); + Card card = player.getLibrary().getCard(target.getFirstTarget(), game); + if (card != null) { + player.revealCards(source, new CardsImpl(card), game); + player.moveCards(card, Zone.HAND, source, game); } - player.shuffleLibrary(source, game); - return false; + player.shuffleLibrary(source, game); + return true; } } diff --git a/Mage.Sets/src/mage/cards/c/CruelFate.java b/Mage.Sets/src/mage/cards/c/CruelFate.java index 7ef7e86448..b76e2edb42 100644 --- a/Mage.Sets/src/mage/cards/c/CruelFate.java +++ b/Mage.Sets/src/mage/cards/c/CruelFate.java @@ -6,10 +6,10 @@ import mage.cards.*; import mage.constants.CardType; import mage.constants.Outcome; import mage.constants.Zone; -import mage.filter.FilterCard; import mage.game.Game; import mage.players.Player; import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetOpponent; import java.util.UUID; @@ -25,7 +25,6 @@ public final class CruelFate extends CardImpl { // Look at the top five cards of target opponent's library. Put one of those cards into that player's graveyard and the rest on top of their library in any order. this.getSpellAbility().addEffect(new CruelFateEffect()); this.getSpellAbility().addTarget(new TargetOpponent()); - } private CruelFate(final CruelFate card) { @@ -40,12 +39,13 @@ public final class CruelFate extends CardImpl { class CruelFateEffect extends OneShotEffect { - public CruelFateEffect() { + CruelFateEffect() { super(Outcome.DrawCard); - this.staticText = "Look at the top five cards of target opponent's library. Put one of those cards into that player's graveyard and the rest on top of their library in any order"; + this.staticText = "Look at the top five cards of target opponent's library. " + + "Put one of those cards into that player's graveyard and the rest on top of their library in any order"; } - public CruelFateEffect(final CruelFateEffect effect) { + private CruelFateEffect(final CruelFateEffect effect) { super(effect); } @@ -56,35 +56,25 @@ class CruelFateEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - Card sourceCard = game.getCard(source.getSourceId()); - if (sourceCard != null) { - Player controller = game.getPlayer(source.getControllerId()); - Player targetOpponent = game.getPlayer(getTargetPointer().getFirst(game, source)); - if (targetOpponent != null && controller != null) { - Cards cards = new CardsImpl(targetOpponent.getLibrary().getTopCards(game, 5)); - controller.lookAtCards(source, null, cards, game); - - // card to put into opponent's graveyard - TargetCard target = new TargetCard(Zone.LIBRARY, new FilterCard("card to put into target opponent's graveyard")); - if (targetOpponent.canRespond()) { - if (cards.size() > 1) { - controller.choose(Outcome.Detriment, cards, target, game); - Card card = cards.get(target.getFirstTarget(), game); - if (card != null) { - cards.remove(card); - controller.moveCards(card, Zone.GRAVEYARD, source, game); - } - } else if (cards.size() == 1) { - Card card = cards.get(cards.iterator().next(), game); - controller.moveCards(card, Zone.GRAVEYARD, source, game); - card.moveToZone(Zone.GRAVEYARD, source, game, true); - cards.clear(); - } - } - controller.putCardsOnTopOfLibrary(cards, game, source, true); - return true; - } + Player controller = game.getPlayer(source.getControllerId()); + Player opponent = game.getPlayer(source.getFirstTarget()); + if (controller == null || opponent == null) { + return false; } - return false; + Cards cards = new CardsImpl(opponent.getLibrary().getTopCards(game, 5)); + if (cards.isEmpty()) { + return false; + } + if (cards.size() == 1) { + return controller.moveCards(cards, Zone.GRAVEYARD, source, game); + } + TargetCard targetCard = new TargetCardInLibrary(); + controller.choose(outcome, cards, targetCard, game); + Card card = game.getCard(targetCard.getFirstTarget()); + if (card != null) { + controller.moveCards(card, Zone.GRAVEYARD, source, game); + cards.remove(card); + } + return controller.putCardsOnTopOfLibrary(card, game, source, true); } } diff --git a/Mage.Sets/src/mage/cards/c/CruelRevival.java b/Mage.Sets/src/mage/cards/c/CruelRevival.java index 7c53c94a49..31f10a8675 100644 --- a/Mage.Sets/src/mage/cards/c/CruelRevival.java +++ b/Mage.Sets/src/mage/cards/c/CruelRevival.java @@ -14,6 +14,7 @@ import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.permanent.Permanent; +import mage.players.Player; import mage.target.TargetPermanent; import mage.target.common.TargetCardInYourGraveyard; @@ -36,7 +37,6 @@ public final class CruelRevival extends CardImpl { public CruelRevival(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{4}{B}"); - // Destroy target non-Zombie creature. It can't be regenerated. Return up to one target Zombie card from your graveyard to your hand. this.getSpellAbility().addEffect(new CruelRevivalEffect()); this.getSpellAbility().addTarget(new TargetPermanent(filter)); @@ -55,12 +55,13 @@ public final class CruelRevival extends CardImpl { class CruelRevivalEffect extends OneShotEffect { - public CruelRevivalEffect() { + CruelRevivalEffect() { super(Outcome.DestroyPermanent); - staticText = "Destroy target non-Zombie creature. It can't be regenerated. Return up to one target Zombie card from your graveyard to your hand"; + staticText = "Destroy target non-Zombie creature. It can't be regenerated. " + + "Return up to one target Zombie card from your graveyard to your hand"; } - public CruelRevivalEffect(final CruelRevivalEffect effect) { + private CruelRevivalEffect(final CruelRevivalEffect effect) { super(effect); } @@ -71,9 +72,10 @@ class CruelRevivalEffect extends OneShotEffect { targetDestroy.destroy(source, game, true); } + Player player = game.getPlayer(source.getControllerId()); Card targetRetrieve = game.getCard(source.getTargets().get(1).getFirstTarget()); - if (targetRetrieve != null) { - targetRetrieve.moveToZone(Zone.HAND, source, game, true); + if (player != null && targetRetrieve != null) { + player.moveCards(targetRetrieve, Zone.HAND, source, game); } return true; } @@ -82,4 +84,4 @@ class CruelRevivalEffect extends OneShotEffect { public CruelRevivalEffect copy() { return new CruelRevivalEffect(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/c/CutTheTethers.java b/Mage.Sets/src/mage/cards/c/CutTheTethers.java index 2e544c42db..ff6c7f510c 100644 --- a/Mage.Sets/src/mage/cards/c/CutTheTethers.java +++ b/Mage.Sets/src/mage/cards/c/CutTheTethers.java @@ -5,11 +5,13 @@ import mage.abilities.costs.Cost; import mage.abilities.effects.OneShotEffect; 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.SubType; import mage.constants.Zone; -import mage.filter.common.FilterCreaturePermanent; +import mage.filter.FilterPermanent; import mage.game.Game; import mage.game.permanent.Permanent; import mage.players.Player; @@ -25,7 +27,6 @@ public final class CutTheTethers extends CardImpl { public CutTheTethers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{U}"); - // For each Spirit, return it to its owner's hand unless that player pays {3}. this.getSpellAbility().addEffect(new CutTheTethersEffect()); } @@ -42,18 +43,14 @@ public final class CutTheTethers extends CardImpl { class CutTheTethersEffect extends OneShotEffect { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("Spirit creatures"); + private static final FilterPermanent filter = new FilterPermanent(SubType.SPIRIT, ""); - static { - filter.add(SubType.SPIRIT.getPredicate()); - } - - public CutTheTethersEffect() { + CutTheTethersEffect() { super(Outcome.ReturnToHand); this.staticText = "For each Spirit, return it to its owner's hand unless that player pays {3}"; } - public CutTheTethersEffect(final CutTheTethersEffect effect) { + private CutTheTethersEffect(final CutTheTethersEffect effect) { super(effect); } @@ -64,19 +61,28 @@ class CutTheTethersEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - for (Permanent creature : game.getState().getBattlefield().getActivePermanents(filter, source.getControllerId(), source.getSourceId(), game)) { - Player player = game.getPlayer(creature.getControllerId()); - if (player != null) { - boolean paid = false; - if (player.chooseUse(Outcome.Benefit, "Pay {3} to keep " + creature.getName() + " on the battlefield?", source, game)) { - Cost cost = ManaUtil.createManaCost(3, false); - paid = cost.pay(source, game, source, creature.getControllerId(), false, null); - } - if (!paid) { - creature.moveToZone(Zone.HAND, source, game, true); - } + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Cards toHand = new CardsImpl(); + for (Permanent permanent : game.getBattlefield().getActivePermanents( + filter, source.getControllerId(), source.getSourceId(), game + )) { + Player player = game.getPlayer(permanent.getOwnerId()); + if (player == null) { + continue; + } + boolean paid = false; + if (player.chooseUse(Outcome.Benefit, "Pay {3} to keep " + permanent.getIdName() + " on the battlefield?", source, game)) { + Cost cost = ManaUtil.createManaCost(3, false); + paid = cost.pay(source, game, source, permanent.getControllerId(), false, null); + } + if (!paid) { + toHand.add(permanent); } } + controller.moveCards(toHand, Zone.HAND, source, game); return true; } } diff --git a/Mage.Sets/src/mage/cards/d/DarkTutelage.java b/Mage.Sets/src/mage/cards/d/DarkTutelage.java index 26056b063b..02219d42f3 100644 --- a/Mage.Sets/src/mage/cards/d/DarkTutelage.java +++ b/Mage.Sets/src/mage/cards/d/DarkTutelage.java @@ -1,27 +1,32 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.common.OnEventTriggeredAbility; +import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.cards.*; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.CardsImpl; import mage.constants.CardType; import mage.constants.Outcome; +import mage.constants.TargetController; import mage.constants.Zone; import mage.game.Game; -import mage.game.events.GameEvent.EventType; import mage.players.Player; +import java.util.UUID; + /** - * * @author BetaSteward_at_googlemail.com */ public final class DarkTutelage extends CardImpl { public DarkTutelage(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}"); - this.addAbility(new OnEventTriggeredAbility(EventType.UPKEEP_STEP_PRE, "beginning of your upkeep", new DarkTutelageEffect(), false)); + + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + new DarkTutelageEffect(), TargetController.YOU, false + )); } private DarkTutelage(final DarkTutelage card) { @@ -32,38 +37,39 @@ public final class DarkTutelage extends CardImpl { public DarkTutelage copy() { return new DarkTutelage(this); } - } class DarkTutelageEffect extends OneShotEffect { - public DarkTutelageEffect() { + DarkTutelageEffect() { super(Outcome.DrawCard); staticText = "reveal the top card of your library and put that card into your hand. You lose life equal to its converted mana cost"; } - public DarkTutelageEffect(final DarkTutelageEffect effect) { + private DarkTutelageEffect(final DarkTutelageEffect effect) { super(effect); } @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.revealCards(source, new CardsImpl(card), game); - card.moveToZone(Zone.HAND, source, game, false); - controller.loseLife(card.getConvertedManaCost(), game, source, false); - return true; - } + Player player = game.getPlayer(source.getControllerId()); + if (player == null || !player.getLibrary().hasCards()) { + return false; } - return false; + Card card = player.getLibrary().getFromTop(game); + if (card == null) { + return false; + } + player.revealCards(source, new CardsImpl(card), game); + player.moveCards(card, Zone.HAND, source, game); + if (card.getConvertedManaCost() > 0) { + player.loseLife(card.getConvertedManaCost(), game, source, false); + } + return true; } @Override public DarkTutelageEffect copy() { return new DarkTutelageEffect(this); } - } diff --git a/Mage.Sets/src/mage/cards/d/DecayingSoil.java b/Mage.Sets/src/mage/cards/d/DecayingSoil.java index c570621b9f..90f7f8b8fa 100644 --- a/Mage.Sets/src/mage/cards/d/DecayingSoil.java +++ b/Mage.Sets/src/mage/cards/d/DecayingSoil.java @@ -1,32 +1,25 @@ package mage.cards.d; -import mage.abilities.Ability; -import mage.abilities.TriggeredAbilityImpl; import mage.abilities.common.BeginningOfUpkeepTriggeredAbility; +import mage.abilities.common.DiesCreatureTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.condition.Condition; import mage.abilities.condition.common.CardsInControllerGraveyardCondition; -import mage.abilities.costs.Cost; +import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.decorator.ConditionalContinuousEffect; -import mage.abilities.effects.Effect; -import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ExileTargetEffect; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.ExileFromZoneTargetEffect; +import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; -import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; +import mage.constants.CardType; +import mage.constants.TargetController; +import mage.constants.Zone; +import mage.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.Predicates; import mage.filter.predicate.permanent.TokenPredicate; -import mage.game.Game; -import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; -import mage.game.events.ZoneChangeEvent; -import mage.game.permanent.Permanent; -import mage.players.Player; -import mage.target.common.TargetCardInYourGraveyard; -import mage.target.targetpointer.FixedTarget; -import mage.util.ManaUtil; import java.util.UUID; @@ -35,30 +28,30 @@ import java.util.UUID; */ public final class DecayingSoil extends CardImpl { - private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("nontoken creature"); + private static final FilterPermanent filter = new FilterCreaturePermanent("nontoken creature"); static { filter.add(TargetController.YOU.getOwnerPredicate()); filter.add(Predicates.not(TokenPredicate.instance)); } + private static final Condition condition = new CardsInControllerGraveyardCondition(7); + public DecayingSoil(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}{B}"); - // At the beginning of your upkeep, exile a card from your graveyard. - Ability ability = new BeginningOfUpkeepTriggeredAbility(Zone.BATTLEFIELD, new ExileTargetEffect(), TargetController.YOU, false); - TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(); - ability.addTarget(target); - this.addAbility(ability); + this.addAbility(new BeginningOfUpkeepTriggeredAbility( + Zone.BATTLEFIELD, new ExileFromZoneTargetEffect(Zone.GRAVEYARD, false + ).setText("exile a card from your graveyard"), TargetController.YOU, false, true)); // Threshold - As long as seven or more cards are in your graveyard, Decaying Soil has "Whenever a nontoken creature is put into your graveyard from the battlefield, you may pay {1}. If you do, return that card to your hand." - ability = new SimpleStaticAbility(Zone.BATTLEFIELD, - new ConditionalContinuousEffect(new GainAbilitySourceEffect(new DecayingSoilTriggeredAbility(new DecayingSoilEffect(), filter)), - new CardsInControllerGraveyardCondition(7), - "As long as seven or more cards are in your graveyard, {this} has \"Whenever a nontoken creature is put into your graveyard from the battlefield, you may pay {1}. If you do, return that card to your hand.\"")); - ability.setAbilityWord(AbilityWord.THRESHOLD); - this.addAbility(ability); + this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( + new GainAbilitySourceEffect(new DecayingSoilTriggeredAbility()), + condition, "Threshold — As long as seven or more cards are in your graveyard, " + + "{this} has \"Whenever a nontoken creature is put into your graveyard from the battlefield, " + + "you may pay {1}. If you do, return that card to your hand.\"" + ))); } private DecayingSoil(final DecayingSoil card) { @@ -71,18 +64,21 @@ public final class DecayingSoil extends CardImpl { } } -class DecayingSoilTriggeredAbility extends TriggeredAbilityImpl { +class DecayingSoilTriggeredAbility extends DiesCreatureTriggeredAbility { - protected FilterCreaturePermanent filter; + private static final FilterPermanent filter = new FilterCreaturePermanent(); - public DecayingSoilTriggeredAbility(Effect effect, FilterCreaturePermanent filter) { - super(Zone.BATTLEFIELD, effect, false); - this.filter = filter; + static { + filter.add(TargetController.YOU.getOwnerPredicate()); + filter.add(Predicates.not(TokenPredicate.instance)); } - public DecayingSoilTriggeredAbility(DecayingSoilTriggeredAbility ability) { + DecayingSoilTriggeredAbility() { + super(new DoIfCostPaid(new ReturnFromGraveyardToHandTargetEffect(), new GenericManaCost(1)), false, filter, true); + } + + private DecayingSoilTriggeredAbility(DecayingSoilTriggeredAbility ability) { super(ability); - this.filter = ability.filter; } @Override @@ -90,77 +86,9 @@ class DecayingSoilTriggeredAbility extends TriggeredAbilityImpl { return new DecayingSoilTriggeredAbility(this); } - @Override - public boolean checkEventType(GameEvent event, Game game) { - return event.getType() == GameEvent.EventType.ZONE_CHANGE; - } - - @Override - public boolean checkTrigger(GameEvent event, Game game) { - ZoneChangeEvent zEvent = (ZoneChangeEvent) event; - if (zEvent.isDiesEvent()) { - Permanent permanent = (Permanent) game.getLastKnownInformation(event.getTargetId(), Zone.BATTLEFIELD); - if (permanent != null && filter.match(permanent, this.getSourceId(), this.getControllerId(), game)) { - getEffects().get(0).setTargetPointer(new FixedTarget(permanent, game)); - return true; - } - } - return false; - } - - @Override - public boolean checkInterveningIfClause(Game game) { - Player controller = game.getPlayer(this.getControllerId()); - return controller != null && controller.getGraveyard().contains(this.getSourceId()); - } - - @Override public String getRule() { - return "Whenever a " + filter.getMessage() + " is put into your graveyard from the battlefield, " + super.getRule(); + return "Whenever a nontoken creature is put into your graveyard from the battlefield, " + + "you may pay {1}. If you do, return that card to your hand."; } } - - -class DecayingSoilEffect extends OneShotEffect { - - private final Cost cost = ManaUtil.createManaCost(1, false); - - public DecayingSoilEffect() { - super(Outcome.Benefit); - staticText = "you may pay {1}. If you do, return that card to your hand"; - - } - - public DecayingSoilEffect(final DecayingSoilEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - Player player = game.getPlayer(source.getControllerId()); - if (player != null) { - if (player.chooseUse(Outcome.Benefit, " - Pay " + cost.getText() + '?', source, game)) { - cost.clearPaid(); - if (cost.pay(source, game, source, source.getControllerId(), false, null)) { - UUID target = this.getTargetPointer().getFirst(game, source); - if (target != null) { - Card card = game.getCard(target); - // check if it's still in graveyard - if (card != null && game.getState().getZone(card.getId()) == Zone.GRAVEYARD) { - card.moveToZone(Zone.HAND, source, game, true); - return true; - } - } - } - } - } - return false; - } - - @Override - public DecayingSoilEffect copy() { - return new DecayingSoilEffect(this); - } - -} diff --git a/Mage.Sets/src/mage/cards/d/DecoyGambit.java b/Mage.Sets/src/mage/cards/d/DecoyGambit.java index a7751d6770..0736cdccef 100644 --- a/Mage.Sets/src/mage/cards/d/DecoyGambit.java +++ b/Mage.Sets/src/mage/cards/d/DecoyGambit.java @@ -4,8 +4,11 @@ import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; 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.filter.FilterPermanent; import mage.filter.common.FilterCreaturePermanent; import mage.filter.predicate.permanent.ControllerIdPredicate; @@ -15,14 +18,12 @@ import mage.players.Player; import mage.target.Target; import mage.target.TargetPermanent; import mage.target.targetadjustment.TargetAdjuster; + import java.util.Collection; -import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.UUID; import java.util.stream.Collectors; -import mage.abilities.condition.Condition; -import mage.constants.Zone; /** * @author TheElk801 @@ -88,7 +89,7 @@ class DecoyGambitEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - HashSet permanentToHand = new HashSet(); + Cards permanentToHand = new CardsImpl(); int numberOfCardsToDraw = 0; if (controller == null) { return false; @@ -102,8 +103,6 @@ class DecoyGambitEffect extends OneShotEffect { .filter(Objects::nonNull) .collect(Collectors.toList()); for (Permanent permanent : permanents) { - // If a creature targeted by Decoy Gambit changes controller, it’s no longer a legal target. - new DecoyGambitCondition(permanent).apply(game, source); // save current controller Player player = game.getPlayer(permanent.getControllerId()); if (player == null) { continue; @@ -125,31 +124,7 @@ class DecoyGambitEffect extends OneShotEffect { cards. After you’ve drawn, the appropriate creatures are all simultaneously returned to their owners’ hands. */ controller.drawCards(numberOfCardsToDraw, source, game); - for (Permanent creature : permanentToHand) { - if (creature != null - && new DecoyGambitCondition(creature).apply(game, source)) { // same controller required - creature.moveToZone(Zone.HAND, source, game, false); - } - } + controller.moveCards(permanentToHand, Zone.HAND, source, game); return true; } } - -class DecoyGambitCondition implements Condition { - - private UUID controllerId; - private final Permanent permanent; - - DecoyGambitCondition(Permanent permanent) { - this.permanent = permanent; - } - - @Override - public boolean apply(Game game, Ability source) { - if (controllerId == null) { // is the original controller set - controllerId = permanent.getControllerId(); // original controller set - } - return (permanent != null - && Objects.equals(controllerId, permanent.getControllerId())); - } -} diff --git a/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java b/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java index d7e3edd8be..6e246fb376 100644 --- a/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java +++ b/Mage.Sets/src/mage/cards/d/DiabolicRevelation.java @@ -1,30 +1,25 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; -import mage.abilities.dynamicvalue.common.ManacostVariableValue; import mage.abilities.effects.OneShotEffect; -import mage.cards.Card; -import mage.cards.CardImpl; -import mage.cards.CardSetInfo; +import mage.cards.*; import mage.constants.CardType; 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.common.TargetCardInLibrary; +import java.util.UUID; + /** - * * @author North */ public final class DiabolicRevelation extends CardImpl { public DiabolicRevelation(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{3}{B}{B}"); - + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{3}{B}{B}"); // Search your library for up to X cards and put those cards into your hand. Then shuffle your library. this.getSpellAbility().addEffect(new DiabolicRevelationEffect()); @@ -42,12 +37,12 @@ public final class DiabolicRevelation extends CardImpl { class DiabolicRevelationEffect extends OneShotEffect { - public DiabolicRevelationEffect() { + DiabolicRevelationEffect() { super(Outcome.Benefit); this.staticText = "Search your library for up to X cards and put those cards into your hand. Then shuffle your library"; } - public DiabolicRevelationEffect(final DiabolicRevelationEffect effect) { + private DiabolicRevelationEffect(final DiabolicRevelationEffect effect) { super(effect); } @@ -58,23 +53,24 @@ class DiabolicRevelationEffect extends OneShotEffect { @Override public boolean apply(Game game, Ability source) { - int amount = ManacostVariableValue.instance.calculate(game, source, this); - TargetCardInLibrary target = new TargetCardInLibrary(0, amount, new FilterCard()); - Player player = game.getPlayer(source.getControllerId()); if (player == null) { return false; } - - if (player.searchLibrary(target, source, game)) { - for (UUID cardId : target.getTargets()) { - Card card = player.getLibrary().remove(cardId, game); - if (card != null) { - card.moveToZone(Zone.HAND, source, game, false); - } + TargetCardInLibrary target = new TargetCardInLibrary( + 0, source.getManaCostsToPay().getX(), StaticFilters.FILTER_CARD + ); + player.searchLibrary(target, source, game); + Cards cards = new CardsImpl(); + for (UUID targetId : target.getTargets()) { + Card card = player.getLibrary().getCard(targetId, game); + if (card != null) { + cards.add(card); } } - + if (!cards.isEmpty()) { + player.moveCards(cards, Zone.HAND, source, game); + } player.shuffleLibrary(source, game); return true; } diff --git a/Mage.Sets/src/mage/cards/d/DisplacementWave.java b/Mage.Sets/src/mage/cards/d/DisplacementWave.java index 1640a57fbd..7851fc629f 100644 --- a/Mage.Sets/src/mage/cards/d/DisplacementWave.java +++ b/Mage.Sets/src/mage/cards/d/DisplacementWave.java @@ -1,26 +1,28 @@ - package mage.cards.d; -import java.util.UUID; import mage.abilities.Ability; import mage.abilities.effects.OneShotEffect; 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.Game; import mage.game.permanent.Permanent; +import mage.players.Player; + +import java.util.UUID; /** - * * @author fireshoes */ public final class DisplacementWave extends CardImpl { public DisplacementWave(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{X}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{U}{U}"); // Return all nonland permanents with converted mana cost X or less to their owners' hands. this.getSpellAbility().addEffect(new DisplacementWaveEffect()); @@ -38,27 +40,32 @@ public final class DisplacementWave extends CardImpl { class DisplacementWaveEffect extends OneShotEffect { - public DisplacementWaveEffect() { + DisplacementWaveEffect() { super(Outcome.ReturnToHand); staticText = "Return all nonland permanents with converted mana cost X or less to their owners' hands"; } - public DisplacementWaveEffect(final DisplacementWaveEffect effect) { + private DisplacementWaveEffect(final DisplacementWaveEffect effect) { super(effect); } @Override public DisplacementWaveEffect copy() { return new DisplacementWaveEffect(this); - } - + } + @Override public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getControllerId()); + if (player == null) { + return false; + } + Cards cards = new CardsImpl(); for (Permanent permanent : game.getBattlefield().getActivePermanents(source.getControllerId(), game)) { if (!permanent.isLand() && permanent.getConvertedManaCost() <= source.getManaCostsToPay().getX()) { - permanent.moveToZone(Zone.HAND, source, game, true); + cards.add(permanent); } } - return true; + return player.moveCards(cards, Zone.HAND, source, game); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/d/DrakeFamiliar.java b/Mage.Sets/src/mage/cards/d/DrakeFamiliar.java index 2ed208915a..9f9c46743e 100644 --- a/Mage.Sets/src/mage/cards/d/DrakeFamiliar.java +++ b/Mage.Sets/src/mage/cards/d/DrakeFamiliar.java @@ -1,17 +1,15 @@ - package mage.cards.d; import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.SacrificeSourceEffect; import mage.abilities.keyword.FlyingAbility; 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.StaticFilters; import mage.game.Game; @@ -22,20 +20,19 @@ import mage.target.TargetPermanent; import java.util.UUID; /** - * * @author escplan9 (Derek Monturo - dmontur1 at gmail dot com) */ public final class DrakeFamiliar extends CardImpl { public DrakeFamiliar(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{1}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}"); this.subtype.add(SubType.DRAKE); this.power = new MageInt(2); this.toughness = new MageInt(1); // Flying this.addAbility(FlyingAbility.getInstance()); - + // When Drake Familiar enters the battlefield, sacrifice it unless you return an enchantment to its owner's hand. this.addAbility(new EntersBattlefieldTriggeredAbility(new DrakeFamiliarEffect())); } @@ -52,38 +49,33 @@ public final class DrakeFamiliar extends CardImpl { class DrakeFamiliarEffect extends OneShotEffect { - private static final String effectText = "sacrifice it unless you return an enchantment to its owner's hand."; - - DrakeFamiliarEffect () { + DrakeFamiliarEffect() { super(Outcome.Sacrifice); - staticText = effectText; + staticText = "sacrifice it unless you return an enchantment to its owner's hand."; } - DrakeFamiliarEffect (DrakeFamiliarEffect effect) { + private DrakeFamiliarEffect(DrakeFamiliarEffect effect) { super(effect); } @Override public boolean apply(Game game, Ability source) { Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - boolean targetChosen = false; - TargetPermanent target = new TargetPermanent(1, 1, StaticFilters.FILTER_ENCHANTMENT_PERMANENT, true); - if (target.canChoose(source.getSourceId(), controller.getId(), game) && controller.chooseUse(outcome, "Return an enchantment to its owner's hand?", source, game)) { - controller.chooseTarget(Outcome.Sacrifice, target, source, game); - Permanent permanent = game.getPermanent(target.getFirstTarget()); - if (permanent != null) { - targetChosen = true; - permanent.moveToZone(Zone.HAND, source, game, false); - } - } - - if (!targetChosen) { - new SacrificeSourceEffect().apply(game, source); - } - return true; + if (controller == null) { + return false; } - return false; + TargetPermanent target = new TargetPermanent(StaticFilters.FILTER_ENCHANTMENT_PERMANENT); + target.setNotTarget(true); + if (target.canChoose(source.getSourceId(), controller.getId(), game) + && controller.chooseUse(outcome, "Return an enchantment to its owner's hand?", source, game)) { + controller.chooseTarget(Outcome.ReturnToHand, target, source, game); + Permanent permanent = game.getPermanent(target.getFirstTarget()); + if (permanent != null) { + return controller.moveCards(permanent, Zone.HAND, source, game); + } + } + Permanent permanent = source.getSourcePermanentIfItStillExists(game); + return permanent != null && permanent.sacrifice(source, game); } @Override diff --git a/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java b/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java index 68bcb34ffd..5e9511b209 100644 --- a/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java +++ b/Mage/src/main/java/mage/abilities/common/DiesCreatureTriggeredAbility.java @@ -72,9 +72,7 @@ public class DiesCreatureTriggeredAbility extends TriggeredAbilityImpl { if (zEvent.isDiesEvent()) { if (filter.match(zEvent.getTarget(), sourceId, controllerId, game)) { if (setTargetPointer) { - for (Effect effect : this.getEffects()) { - effect.setTargetPointer(new FixedTarget(event.getTargetId(), game)); - } + this.getEffects().setTargetPointer(new FixedTarget(event.getTargetId(), game)); } return true; }