From fcf3fb672b26cfcd9fcb9270c2be2b65286b2b25 Mon Sep 17 00:00:00 2001 From: "antonig@sas.upenn.edu" Date: Fri, 19 Apr 2019 02:42:30 -0400 Subject: [PATCH] implemented and tested Finale of Devastation. --- .../src/mage/cards/f/FinaleOfDevastation.java | 80 ++++++++++++++++ Mage.Sets/src/mage/sets/WarOfTheSpark.java | 1 + ...raryGraveyardPutOntoBattlefieldEffect.java | 91 +++++++++++++++++++ ...ibraryGraveyardWithLessCMCPutIntoPlay.java | 87 ++++++++++++++++++ 4 files changed, 259 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/f/FinaleOfDevastation.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutOntoBattlefieldEffect.java create mode 100644 Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardWithLessCMCPutIntoPlay.java diff --git a/Mage.Sets/src/mage/cards/f/FinaleOfDevastation.java b/Mage.Sets/src/mage/cards/f/FinaleOfDevastation.java new file mode 100644 index 00000000000..7afc58140a8 --- /dev/null +++ b/Mage.Sets/src/mage/cards/f/FinaleOfDevastation.java @@ -0,0 +1,80 @@ +package mage.cards.f; + +import java.util.UUID; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; + +import mage.abilities.Ability; +import mage.constants.Outcome; +import mage.game.Game; +import mage.filter.FilterCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.constants.CardType; +import mage.filter.predicate.mageobject.CardTypePredicate; +import mage.abilities.effects.common.search.SearchLibraryGraveyardWithLessCMCPutIntoPlay; +import mage.abilities.effects.ContinuousEffect; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.continuous.BoostControlledEffect; +import mage.constants.Duration; +import mage.abilities.effects.common.continuous.GainAbilityControlledEffect; +import mage.abilities.keyword.HasteAbility; + + +/** + * + * @author antoni-g + */ +public final class FinaleOfDevastation extends CardImpl { + + private static final FilterCard filter = new FilterCard("creature"); + + static { + filter.add(new CardTypePredicate(CardType.CREATURE)); + } + + public FinaleOfDevastation(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{X}{G}{G}"); + // Search your library and/or graveyard for a creature card with converted mana cost X or less and put it onto the battlefield. If you search your library this way, shuffle it. + this.getSpellAbility().addEffect(new SearchLibraryGraveyardWithLessCMCPutIntoPlay(filter)); + // If X is 10 or more, creatures you control get +X/+X and gain haste until end of turn. + this.getSpellAbility().addEffect(new FinaleOfDevastationEffect()); + } + + private FinaleOfDevastation(final FinaleOfDevastation card) { + super(card); + } + + @Override + public FinaleOfDevastation copy() { + return new FinaleOfDevastation(this); + } +} + +class FinaleOfDevastationEffect extends OneShotEffect { + + FinaleOfDevastationEffect() { + super(Outcome.Benefit); + staticText = "If X is 10 or more, creatures you control get +X/+X and gain haste until end of turn."; + } + + private FinaleOfDevastationEffect(final FinaleOfDevastationEffect effect) { + super(effect); + } + + @Override + public FinaleOfDevastationEffect copy() { + return new FinaleOfDevastationEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + int xValue = source.getManaCostsToPay().getX(); + if (xValue >= 10) { + ContinuousEffect effect1 = new BoostControlledEffect(xValue, xValue, Duration.EndOfTurn); + game.addEffect(effect1, source); + ContinuousEffect effect2 = new GainAbilityControlledEffect(HasteAbility.getInstance(), Duration.EndOfTurn, new FilterCreaturePermanent()); + game.addEffect(effect2, source); + } + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/WarOfTheSpark.java b/Mage.Sets/src/mage/sets/WarOfTheSpark.java index 82adc5a388d..eabfd287252 100644 --- a/Mage.Sets/src/mage/sets/WarOfTheSpark.java +++ b/Mage.Sets/src/mage/sets/WarOfTheSpark.java @@ -89,6 +89,7 @@ public final class WarOfTheSpark extends ExpansionSet { cards.add(new SetCardInfo("Evolution Sage", 159, Rarity.UNCOMMON, mage.cards.e.EvolutionSage.class)); cards.add(new SetCardInfo("Fblthp, the Lost", 50, Rarity.RARE, mage.cards.f.FblthpTheLost.class)); cards.add(new SetCardInfo("Feather, the Redeemed", 197, Rarity.RARE, mage.cards.f.FeatherTheRedeemed.class)); + cards.add(new SetCardInfo("Finale of Devastation", 160, Rarity.MYTHIC, mage.cards.f.FinaleOfDevastation.class)); cards.add(new SetCardInfo("Finale of Glory", 12, Rarity.MYTHIC, mage.cards.f.FinaleOfGlory.class)); cards.add(new SetCardInfo("Finale of Revelation", 51, Rarity.MYTHIC, mage.cards.f.FinaleOfRevelation.class)); cards.add(new SetCardInfo("Firemind Vessel", 237, Rarity.UNCOMMON, mage.cards.f.FiremindVessel.class)); diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutOntoBattlefieldEffect.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutOntoBattlefieldEffect.java new file mode 100644 index 00000000000..627244f47b5 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardPutOntoBattlefieldEffect.java @@ -0,0 +1,91 @@ +package mage.abilities.effects.common.search; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardsImpl; +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; + +/** + * + * @author Styxo + */ +public class SearchLibraryGraveyardPutOntoBattlefieldEffect extends OneShotEffect { + + private FilterCard filter; + private boolean forceToSearchBoth; + + public SearchLibraryGraveyardPutOntoBattlefieldEffect(FilterCard filter) { + this(filter, false); + } + + public SearchLibraryGraveyardPutOntoBattlefieldEffect(FilterCard filter, boolean forceToSearchBoth) { + this(filter, forceToSearchBoth, false); + } + + public SearchLibraryGraveyardPutOntoBattlefieldEffect(FilterCard filter, boolean forceToSearchBoth, boolean youMay) { + super(Outcome.Benefit); + this.filter = filter; + this.forceToSearchBoth = forceToSearchBoth; + staticText = (youMay ? "You may" : "") + " search your library and" + (forceToSearchBoth ? "" : "/or") + " graveyard for a card named " + filter.getMessage() + + ", reveal it, and put it into your hand. " + (forceToSearchBoth ? "Then shuffle your library" : "If you search your library this way, shuffle it"); + } + + public SearchLibraryGraveyardPutOntoBattlefieldEffect(final SearchLibraryGraveyardPutOntoBattlefieldEffect effect) { + super(effect); + this.filter = effect.filter; + this.forceToSearchBoth = effect.forceToSearchBoth; + + } + + @Override + public SearchLibraryGraveyardPutOntoBattlefieldEffect copy() { + return new SearchLibraryGraveyardPutOntoBattlefieldEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + Card cardFound = null; + if (controller != null && sourceObject != null) { + if (forceToSearchBoth || controller.chooseUse(outcome, "Search your library for a card named " + filter.getMessage() + '?', source, game)) { + TargetCardInLibrary target = new TargetCardInLibrary(0, 1, filter); + target.clearChosen(); + if (controller.searchLibrary(target, source, game)) { + if (!target.getTargets().isEmpty()) { + cardFound = game.getCard(target.getFirstTarget()); + } + } + controller.shuffleLibrary(source, game); + } + + if (cardFound == null && controller.chooseUse(outcome, "Search your graveyard for a card named " + filter.getMessage() + '?', source, game)) { + TargetCard target = new TargetCard(0, 1, Zone.GRAVEYARD, filter); + target.clearChosen(); + if (controller.choose(outcome, controller.getGraveyard(), target, game)) { + if (!target.getTargets().isEmpty()) { + cardFound = game.getCard(target.getFirstTarget()); + } + } + } + + if (cardFound != null) { + controller.revealCards(sourceObject.getIdName(), new CardsImpl(cardFound), game); + controller.moveCards(cardFound, Zone.BATTLEFIELD, source, game); + } + + return true; + } + + return false; + } + +} diff --git a/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardWithLessCMCPutIntoPlay.java b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardWithLessCMCPutIntoPlay.java new file mode 100644 index 00000000000..09754429ba9 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/effects/common/search/SearchLibraryGraveyardWithLessCMCPutIntoPlay.java @@ -0,0 +1,87 @@ +package mage.abilities.effects.common.search; + +import mage.MageObject; +import mage.abilities.Ability; +import mage.constants.ComparisonType; +import mage.abilities.effects.OneShotEffect; +import mage.cards.Card; +import mage.cards.CardsImpl; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.predicate.mageobject.ConvertedManaCostPredicate; +import mage.game.Game; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.common.TargetCardInLibrary; + +/** + * + * @author antoni-g + */ +public class SearchLibraryGraveyardWithLessCMCPutIntoPlay extends OneShotEffect { + + private final FilterCard filter; + + public SearchLibraryGraveyardWithLessCMCPutIntoPlay() { + this(new FilterCard()); + } + + public SearchLibraryGraveyardWithLessCMCPutIntoPlay(FilterCard filter) { + super(Outcome.PutCreatureInPlay); + this.filter = filter; + staticText = "Search your library or graveyard for a " + filter.getMessage() + " with converted mana cost X or less, put it onto the battlefield, then shuffle your library"; + } + + public SearchLibraryGraveyardWithLessCMCPutIntoPlay(final SearchLibraryGraveyardWithLessCMCPutIntoPlay effect) { + super(effect); + this.filter = effect.filter; + } + + @Override + public SearchLibraryGraveyardWithLessCMCPutIntoPlay copy() { + return new SearchLibraryGraveyardWithLessCMCPutIntoPlay(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + MageObject sourceObject = source.getSourceObject(game); + Card cardFound = null; + if (controller != null && sourceObject != null) { + // create x cost filter + FilterCard advancedFilter = filter.copy(); // never change static objects so copy the object here before + advancedFilter.add(new ConvertedManaCostPredicate(ComparisonType.FEWER_THAN, source.getManaCostsToPay().getX() + 1)); + + if (controller.chooseUse(outcome, "Search your library for a " + filter.getMessage() + " with CMC X or less" + '?', source, game)) { + TargetCardInLibrary target = new TargetCardInLibrary(advancedFilter); + target.clearChosen(); + if (controller.searchLibrary(target, source, game)) { + if (!target.getTargets().isEmpty()) { + cardFound = game.getCard(target.getFirstTarget()); + } + } + controller.shuffleLibrary(source, game); + } + + if (cardFound == null && controller.chooseUse(outcome, "Search your graveyard for a " + filter.getMessage() + " with CMC X or less" + '?', source, game)) { + TargetCard target = new TargetCard(0, 1, Zone.GRAVEYARD, advancedFilter); + target.clearChosen(); + if (controller.choose(outcome, controller.getGraveyard(), target, game)) { + if (!target.getTargets().isEmpty()) { + cardFound = game.getCard(target.getFirstTarget()); + } + } + } + + if (cardFound != null) { + controller.revealCards(sourceObject.getIdName(), new CardsImpl(cardFound), game); + controller.moveCards(cardFound, Zone.BATTLEFIELD, source, game); + } + + return true; + } + return false; + } + +}