From 391c01c87d0eb9ebc4dcaa92b5e0553fe6f13391 Mon Sep 17 00:00:00 2001 From: xenohedron Date: Sat, 15 Jun 2024 14:43:19 -0400 Subject: [PATCH] implement [MH3] Herigast, Erupting Nullkite --- .../cards/h/HerigastEruptingNullkite.java | 120 ++++++++++++++++++ Mage.Sets/src/mage/sets/ModernHorizons3.java | 1 + .../cards/abilities/keywords/EmergeTest.java | 24 +++- .../abilities/costs/common/ExileHandCost.java | 49 +++++++ 4 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 Mage.Sets/src/mage/cards/h/HerigastEruptingNullkite.java create mode 100644 Mage/src/main/java/mage/abilities/costs/common/ExileHandCost.java diff --git a/Mage.Sets/src/mage/cards/h/HerigastEruptingNullkite.java b/Mage.Sets/src/mage/cards/h/HerigastEruptingNullkite.java new file mode 100644 index 00000000000..4fdba0df37c --- /dev/null +++ b/Mage.Sets/src/mage/cards/h/HerigastEruptingNullkite.java @@ -0,0 +1,120 @@ +package mage.cards.h; + +import mage.MageInt; +import mage.abilities.Ability; +import mage.abilities.common.SimpleStaticAbility; +import mage.abilities.costs.common.ExileHandCost; +import mage.abilities.effects.ContinuousEffectImpl; +import mage.abilities.effects.common.CastSourceTriggeredAbility; +import mage.abilities.effects.common.DoIfCostPaid; +import mage.abilities.effects.common.DrawCardSourceControllerEffect; +import mage.abilities.keyword.EmergeAbility; +import mage.abilities.keyword.FlyingAbility; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.*; +import mage.filter.StaticFilters; +import mage.game.Game; +import mage.game.stack.Spell; +import mage.players.Player; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; + +/** + * @author xenohedron + */ +public final class HerigastEruptingNullkite extends CardImpl { + + public HerigastEruptingNullkite(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{9}"); + + this.supertype.add(SuperType.LEGENDARY); + this.subtype.add(SubType.ELDRAZI); + this.subtype.add(SubType.DRAGON); + this.power = new MageInt(6); + this.toughness = new MageInt(6); + + // Emerge {6}{R}{R} + this.addAbility(new EmergeAbility(this, "{6}{R}{R}")); + + // When you cast this spell, you may exile your hand. If you do, draw three cards. + this.addAbility(new CastSourceTriggeredAbility(new DoIfCostPaid( + new DrawCardSourceControllerEffect(3), + new ExileHandCost() + ))); + + // Flying + this.addAbility(FlyingAbility.getInstance()); + + // Each creature spell you cast has emerge. The emerge cost is equal to its mana cost. + this.addAbility(new SimpleStaticAbility(new HerigastEruptingNullkiteEffect())); + } + + private HerigastEruptingNullkite(final HerigastEruptingNullkite card) { + super(card); + } + + @Override + public HerigastEruptingNullkite copy() { + return new HerigastEruptingNullkite(this); + } +} + +class HerigastEruptingNullkiteEffect extends ContinuousEffectImpl { + + HerigastEruptingNullkiteEffect() { + super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); + staticText = "Each creature spell you cast has emerge. The emerge cost is equal to its mana cost."; + } + + private HerigastEruptingNullkiteEffect(final HerigastEruptingNullkiteEffect effect) { + super(effect); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + Set cardsToGainEmerge = new HashSet<>(); + cardsToGainEmerge.addAll(controller.getHand().getCards(StaticFilters.FILTER_CARD_CREATURE, game)); + cardsToGainEmerge.addAll(controller.getGraveyard().getCards(StaticFilters.FILTER_CARD_CREATURE, game)); + controller.getLibrary().getCards(game).stream() + .filter(c -> StaticFilters.FILTER_CARD_CREATURE.match(c, game)) + .forEach(cardsToGainEmerge::add); + game.getExile().getAllCardsByRange(game, controller.getId()).stream() + .filter(c -> StaticFilters.FILTER_CARD_CREATURE.match(c, game)) + .forEach(cardsToGainEmerge::add); + game.getCommanderCardsFromCommandZone(controller, CommanderCardType.ANY) + .stream() + .filter(card -> StaticFilters.FILTER_CARD_CREATURE.match(card, game)) + .forEach(cardsToGainEmerge::add); + game.getStack().stream() + .filter(Spell.class::isInstance) + .filter(s -> s.isControlledBy(controller.getId())) + .filter(s -> StaticFilters.FILTER_CARD_CREATURE.match((Spell) s, game)) + .map(s -> game.getCard(s.getSourceId())) + .filter(Objects::nonNull) + .forEach(cardsToGainEmerge::add); + for (Card card : cardsToGainEmerge) { + if (card.getManaCost().getText().isEmpty()) { + continue; // card must have a mana cost + } + Ability ability = new EmergeAbility(card, card.getManaCost().getText()); + ability.setSourceId(card.getId()); + ability.setControllerId(card.getControllerOrOwnerId()); + game.getState().addOtherAbility(card, ability); + } + return true; + } + + @Override + public HerigastEruptingNullkiteEffect copy() { + return new HerigastEruptingNullkiteEffect(this); + } +} diff --git a/Mage.Sets/src/mage/sets/ModernHorizons3.java b/Mage.Sets/src/mage/sets/ModernHorizons3.java index 2cf1a96dc4b..aee850f48b1 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons3.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons3.java @@ -152,6 +152,7 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Guardian of the Forgotten", 28, Rarity.UNCOMMON, mage.cards.g.GuardianOfTheForgotten.class)); cards.add(new SetCardInfo("Guide of Souls", 29, Rarity.RARE, mage.cards.g.GuideOfSouls.class)); cards.add(new SetCardInfo("Harbinger of the Seas", 63, Rarity.RARE, mage.cards.h.HarbingerOfTheSeas.class)); + cards.add(new SetCardInfo("Herigast, Erupting Nullkite", 8, Rarity.MYTHIC, mage.cards.h.HerigastEruptingNullkite.class)); cards.add(new SetCardInfo("Hexgold Slith", 30, Rarity.COMMON, mage.cards.h.HexgoldSlith.class)); cards.add(new SetCardInfo("Hope-Ender Coatl", 64, Rarity.UNCOMMON, mage.cards.h.HopeEnderCoatl.class)); cards.add(new SetCardInfo("Horrid Shadowspinner", 188, Rarity.UNCOMMON, mage.cards.h.HorridShadowspinner.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EmergeTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EmergeTest.java index b2f71f7e174..6ee57e8fa7b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EmergeTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/abilities/keywords/EmergeTest.java @@ -1,4 +1,3 @@ - package org.mage.test.cards.abilities.keywords; import mage.constants.PhaseStep; @@ -37,4 +36,27 @@ public class EmergeTest extends CardTestPlayerBase { assertPermanentCount(playerA, "Wretched Gryff", 1); } + @Test + public void testGainEmerge() { + String herigast = "Herigast, Erupting Nullkite"; // {9} 6/6 Flying + // Each creature spell you cast has emerge. The emerge cost is equal to its mana cost. + String gorger = "Vastwood Gorger"; // 5G 5/6 + String elemental = "Air Elemental"; // 3UU 4/4 Flying + + addCard(Zone.BATTLEFIELD, playerA, herigast); + addCard(Zone.BATTLEFIELD, playerA, "Forest"); + addCard(Zone.BATTLEFIELD, playerA, elemental); + addCard(Zone.HAND, playerA, gorger); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Vastwood Gorger with emerge"); + setChoice(playerA, elemental); + + setStrictChooseMode(true); + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertGraveyardCount(playerA, elemental, 1); + assertPermanentCount(playerA, gorger, 1); + } + } diff --git a/Mage/src/main/java/mage/abilities/costs/common/ExileHandCost.java b/Mage/src/main/java/mage/abilities/costs/common/ExileHandCost.java new file mode 100644 index 00000000000..9c82ac42353 --- /dev/null +++ b/Mage/src/main/java/mage/abilities/costs/common/ExileHandCost.java @@ -0,0 +1,49 @@ +package mage.abilities.costs.common; + +import mage.abilities.Ability; +import mage.abilities.costs.Cost; +import mage.abilities.costs.CostImpl; +import mage.constants.Zone; +import mage.game.Game; +import mage.players.Player; + +import java.util.UUID; + +/** + * @author xenohedron + */ +public class ExileHandCost extends CostImpl { + + public ExileHandCost() { + } + + private ExileHandCost(final ExileHandCost cost) { + super(cost); + } + + @Override + public ExileHandCost copy() { + return new ExileHandCost(this); + } + + @Override + public boolean canPay(Ability ability, Ability source, UUID controllerId, Game game) { + return true; + } + + @Override + public boolean pay(Ability ability, Game game, Ability source, UUID controllerId, boolean noMana, Cost costToPay) { + Player player = game.getPlayer(controllerId); + if (player == null) { + return paid; + } + player.moveCards(player.getHand(), Zone.EXILED, source, game); + paid = true; + return paid; + } + + @Override + public String getText() { + return "exile your hand"; + } +}