From 327062240f1b2f0452bef186a3e7b4b219bd119e Mon Sep 17 00:00:00 2001 From: jmharmon <37360760+jmharmon@users.noreply.github.com> Date: Wed, 17 Jun 2020 15:34:17 -0700 Subject: [PATCH] Implement Four Cards for M21 (#6651) * Implement Four Cards for M21 Sanctum of Calm Waters Sanctum of Shattered Heights Transmogrify Watcher of the Spheres * Implement Sanctum of Calm Waters * Implement Sanctum of Shattered Heights * Implement Transmogrify * Implement Watcher of the Spheres * Add ability text and minimize number of lines * Add ability text * Clean up a few lines of code * Update SanctumOfCalmWaters.java * Update SanctumOfShatteredHeights.java Co-authored-by: Evan Kranzler --- .../src/mage/cards/s/SanctumOfCalmWaters.java | 46 ++++++++++ .../cards/s/SanctumOfShatteredHeights.java | 56 +++++++++++ Mage.Sets/src/mage/cards/t/Transmogrify.java | 92 +++++++++++++++++++ .../src/mage/cards/w/WatcherOfTheSpheres.java | 64 +++++++++++++ Mage.Sets/src/mage/sets/CoreSet2021.java | 4 + 5 files changed, 262 insertions(+) create mode 100644 Mage.Sets/src/mage/cards/s/SanctumOfCalmWaters.java create mode 100644 Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java create mode 100644 Mage.Sets/src/mage/cards/t/Transmogrify.java create mode 100644 Mage.Sets/src/mage/cards/w/WatcherOfTheSpheres.java diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfCalmWaters.java b/Mage.Sets/src/mage/cards/s/SanctumOfCalmWaters.java new file mode 100644 index 00000000000..e07cc5d225d --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SanctumOfCalmWaters.java @@ -0,0 +1,46 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfPreCombatMainTriggeredAbility; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.effects.common.discard.DiscardControllerEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.TargetController; +import mage.filter.common.FilterControlledPermanent; + +import java.util.UUID; + +/** + * @author jmharmon + */ + +public final class SanctumOfCalmWaters extends CardImpl { + + public SanctumOfCalmWaters(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{U}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SHRINE); + + // At the beginning of your precombat main phase, you may draw X cards, where X is the number of Shrines you control. If you do, discard a card. + Ability ability = new BeginningOfPreCombatMainTriggeredAbility(new DrawCardSourceControllerEffect(new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.SHRINE))) + .setText("At the beginning of your precombat main phase, you may draw X cards, where X is the number of Shrines you control"), + TargetController.YOU, true); + ability.addEffect(new DiscardControllerEffect(1).setText("If you do, discard a card")); + this.addAbility(ability); + } + + public SanctumOfCalmWaters(final SanctumOfCalmWaters card) { + super(card); + } + + @Override + public SanctumOfCalmWaters copy() { + return new SanctumOfCalmWaters(this); + } +} diff --git a/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java b/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java new file mode 100644 index 00000000000..7bc906a3d5e --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SanctumOfShatteredHeights.java @@ -0,0 +1,56 @@ +package mage.cards.s; + +import mage.abilities.Ability; +import mage.abilities.common.SimpleActivatedAbility; +import mage.abilities.costs.common.DiscardTargetCost; +import mage.abilities.costs.mana.ManaCostsImpl; +import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; +import mage.abilities.effects.common.DamageTargetEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.SubType; +import mage.constants.SuperType; +import mage.constants.Zone; +import mage.filter.FilterCard; +import mage.filter.common.FilterControlledPermanent; +import mage.filter.predicate.Predicates; +import mage.target.common.TargetCardInHand; + +import java.util.UUID; + +/** + * @author jmharmon + */ + +public final class SanctumOfShatteredHeights extends CardImpl { + + private static final FilterCard filter = new FilterCard("a land card or Shrine card"); + + static { + filter.add(Predicates.or(CardType.LAND.getPredicate(), SubType.SHRINE.getPredicate())); + } + + public SanctumOfShatteredHeights(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{R}"); + + this.addSuperType(SuperType.LEGENDARY); + this.subtype.add(SubType.SHRINE); + + // {1}, Discard a land card or Shrine card: Sanctum of Shattered Heights deals X damage to target creature or planeswalker, where X is the number of Shrines you control. + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new DamageTargetEffect(new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.SHRINE))) + .setText("Sanctum of Shattered Heights deals X damage to target creature or planeswalker, where X is the number of Shrines you control"), + new ManaCostsImpl("{1}")); + ability.addCost(new DiscardTargetCost(new TargetCardInHand(filter))); + this.addAbility(ability); + } + + public SanctumOfShatteredHeights(final SanctumOfShatteredHeights card) { + super(card); + } + + @Override + public SanctumOfShatteredHeights copy() { + return new SanctumOfShatteredHeights(this); + } +} diff --git a/Mage.Sets/src/mage/cards/t/Transmogrify.java b/Mage.Sets/src/mage/cards/t/Transmogrify.java new file mode 100644 index 00000000000..c21b545bb02 --- /dev/null +++ b/Mage.Sets/src/mage/cards/t/Transmogrify.java @@ -0,0 +1,92 @@ +package mage.cards.t; + +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.ExileTargetEffect; +import mage.cards.*; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.Zone; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Library; +import mage.players.Player; +import mage.target.common.TargetCreaturePermanent; + +import java.util.UUID; + +/** + * @author jmharmon + */ + +public final class Transmogrify extends CardImpl { + + public Transmogrify(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{R}"); + + // Exile target creature. + this.getSpellAbility().addTarget(new TargetCreaturePermanent()); + this.getSpellAbility().addEffect(new ExileTargetEffect()); + // That creature’s controller reveals cards from the top of their library until they reveal a creature card. + // That player puts that card onto the battlefield, then shuffles the rest into their library. + this.getSpellAbility().addEffect(new TransmogrifyEffect()); + } + + public Transmogrify(final Transmogrify card) { + super(card); + } + + @Override + public Transmogrify copy() { + return new Transmogrify(this); + } +} + +class TransmogrifyEffect extends OneShotEffect { + + public TransmogrifyEffect() { + super(Outcome.PutCreatureInPlay); + staticText = "That creature’s controller reveals cards from the top of their library until they reveal a creature card. That player puts that card onto the battlefield, then shuffles the rest into their library"; + } + + public TransmogrifyEffect(final TransmogrifyEffect effect) { + super(effect); + } + + @Override + public TransmogrifyEffect copy() { + return new TransmogrifyEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Permanent permanent = game.getPermanentOrLKIBattlefield(getTargetPointer().getFirst(game, source)); + if (permanent != null) { + Player player = game.getPlayer(permanent.getControllerId()); + if (player != null) { + Library library = player.getLibrary(); + if (library.hasCards()) { + Cards cards = new CardsImpl(); + Card toBattlefield = null; + for (Card card : library.getCards(game)) { + cards.add(card); + if (card.isCreature()) { + toBattlefield = card; + break; + } + } + if (toBattlefield != null) { + player.moveCards(toBattlefield, Zone.BATTLEFIELD, source, game); + } + player.revealCards(source, cards, game); + cards.remove(toBattlefield); + if (!cards.isEmpty()) { + player.shuffleLibrary(source, game); + } + } + return true; + } + } + return false; + } +} diff --git a/Mage.Sets/src/mage/cards/w/WatcherOfTheSpheres.java b/Mage.Sets/src/mage/cards/w/WatcherOfTheSpheres.java new file mode 100644 index 00000000000..461db887420 --- /dev/null +++ b/Mage.Sets/src/mage/cards/w/WatcherOfTheSpheres.java @@ -0,0 +1,64 @@ +package mage.cards.w; + +import mage.MageInt; +import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.effects.common.continuous.BoostSourceEffect; +import mage.abilities.effects.common.cost.SpellsCostReductionControllerEffect; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterControlledCreaturePermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.predicate.mageobject.AbilityPredicate; +import mage.filter.predicate.permanent.AnotherPredicate; + +import java.util.UUID; + +/** + * @author jmharmon + */ + +public final class WatcherOfTheSpheres extends CardImpl { + + private static final FilterCreatureCard filter = new FilterCreatureCard("Creature spells with flying"); + private static final FilterPermanent filter1 = new FilterControlledCreaturePermanent("another creature with flying"); + + static { + filter.add(new AbilityPredicate(FlyingAbility.class)); + filter1.add(AnotherPredicate.instance); + filter1.add(new AbilityPredicate(FlyingAbility.class)); + } + + public WatcherOfTheSpheres(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{B}"); + + this.subtype.add(SubType.BIRD); + this.subtype.add(SubType.WIZARD); + this.power = new MageInt(2); + this.toughness = new MageInt(2); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Creature spells with flying you cast cost {1} less to cast. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new SpellsCostReductionControllerEffect(filter, 1))); + + // Whenever another creature with flying enters the battlefield under your control, Watcher of the Spheres gets +1/+1 until end of turn. + this.addAbility(new EntersBattlefieldControlledTriggeredAbility(Zone.BATTLEFIELD, new BoostSourceEffect(1, 1, Duration.EndOfTurn), filter1, false)); + } + + public WatcherOfTheSpheres(final WatcherOfTheSpheres card) { + super(card); + } + + @Override + public WatcherOfTheSpheres copy() { + return new WatcherOfTheSpheres(this); + } +} diff --git a/Mage.Sets/src/mage/sets/CoreSet2021.java b/Mage.Sets/src/mage/sets/CoreSet2021.java index 5dee9f04c0f..b507af7427e 100644 --- a/Mage.Sets/src/mage/sets/CoreSet2021.java +++ b/Mage.Sets/src/mage/sets/CoreSet2021.java @@ -206,6 +206,8 @@ public final class CoreSet2021 extends ExpansionSet { cards.add(new SetCardInfo("Rugged Highlands", 249, Rarity.COMMON, mage.cards.r.RuggedHighlands.class)); cards.add(new SetCardInfo("Runed Halo", 32, Rarity.RARE, mage.cards.r.RunedHalo.class)); cards.add(new SetCardInfo("Sabertooth Mauler", 202, Rarity.COMMON, mage.cards.s.SabertoothMauler.class)); + cards.add(new SetCardInfo("Sanctum of Calm Waters", 68, Rarity.UNCOMMON, mage.cards.s.SanctumOfCalmWaters.class)); + cards.add(new SetCardInfo("Sanctum of Shattered Heights", 157, Rarity.UNCOMMON, mage.cards.s.SanctumOfShatteredHeights.class)); cards.add(new SetCardInfo("Scavenging Ooze", 204, Rarity.RARE, mage.cards.s.ScavengingOoze.class)); cards.add(new SetCardInfo("Scorching Dragonfire", 158, Rarity.COMMON, mage.cards.s.ScorchingDragonfire.class)); cards.add(new SetCardInfo("Scoured Barrens", 250, Rarity.COMMON, mage.cards.s.ScouredBarrens.class)); @@ -262,6 +264,7 @@ public final class CoreSet2021 extends ExpansionSet { cards.add(new SetCardInfo("Tolarian Kraken", 80, Rarity.UNCOMMON, mage.cards.t.TolarianKraken.class)); cards.add(new SetCardInfo("Tormod's Crypt", 241, Rarity.UNCOMMON, mage.cards.t.TormodsCrypt.class)); cards.add(new SetCardInfo("Traitorous Greed", 166, Rarity.UNCOMMON, mage.cards.t.TraitorousGreed.class)); + cards.add(new SetCardInfo("Transmogrify", 167, Rarity.RARE, mage.cards.t.Transmogrify.class)); cards.add(new SetCardInfo("Tranquil Cove", 258, Rarity.COMMON, mage.cards.t.TranquilCove.class)); cards.add(new SetCardInfo("Trufflesnout", 212, Rarity.COMMON, mage.cards.t.Trufflesnout.class)); cards.add(new SetCardInfo("Turn to Slag", 168, Rarity.COMMON, mage.cards.t.TurnToSlag.class)); @@ -282,6 +285,7 @@ public final class CoreSet2021 extends ExpansionSet { cards.add(new SetCardInfo("Wall of Runes", 85, Rarity.COMMON, mage.cards.w.WallOfRunes.class)); cards.add(new SetCardInfo("Warded Battlements", 44, Rarity.COMMON, mage.cards.w.WardedBattlements.class)); cards.add(new SetCardInfo("Warden of the Woods", 213, Rarity.UNCOMMON, mage.cards.w.WardenOfTheWoods.class)); + cards.add(new SetCardInfo("Watcher of the Spheres", 227, Rarity.UNCOMMON, mage.cards.w.WatcherOfTheSpheres.class)); cards.add(new SetCardInfo("Wildwood Patrol", 339, Rarity.COMMON, mage.cards.w.WildwoodPatrol.class)); cards.add(new SetCardInfo("Wildwood Scourge", 214, Rarity.UNCOMMON, mage.cards.w.WildwoodScourge.class)); cards.add(new SetCardInfo("Wind-Scarred Crag", 259, Rarity.COMMON, mage.cards.w.WindScarredCrag.class));