diff --git a/Mage.Sets/src/mage/cards/b/BirthingRitual.java b/Mage.Sets/src/mage/cards/b/BirthingRitual.java new file mode 100644 index 00000000000..93f7e994b12 --- /dev/null +++ b/Mage.Sets/src/mage/cards/b/BirthingRitual.java @@ -0,0 +1,114 @@ +package mage.cards.b; + +import mage.abilities.Ability; +import mage.abilities.common.BeginningOfEndStepTriggeredAbility; +import mage.abilities.condition.Condition; +import mage.abilities.condition.common.PermanentsOnTheBattlefieldCondition; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.hint.ConditionHint; +import mage.abilities.hint.Hint; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.cards.Cards; +import mage.cards.CardsImpl; +import mage.constants.*; +import mage.filter.FilterCard; +import mage.filter.FilterPermanent; +import mage.filter.common.FilterCreatureCard; +import mage.filter.common.FilterCreaturePermanent; +import mage.filter.predicate.mageobject.ManaValuePredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetCard; +import mage.target.TargetPermanent; +import mage.target.common.TargetControlledCreaturePermanent; + +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author Susucr + */ +public final class BirthingRitual extends CardImpl { + + private static final FilterPermanent filter + = new FilterCreaturePermanent("if you control a creature"); + + private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter); + private static final Hint hint = new ConditionHint(condition); + + public BirthingRitual(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}"); + + // At the beginning of your end step, if you control a creature, look at the top seven cards of your library. Then you may sacrifice a creature. If you do, you may put a creature card with mana value X or less from among those cards onto the battlefield, where X is 1 plus the sacrificed creature's mana value. Put the rest on the bottom of your library in a random order. + this.addAbility(new BeginningOfEndStepTriggeredAbility( + new BirthingRitualEffect(), TargetController.YOU, condition, false + ).addHint(hint)); + } + + private BirthingRitual(final BirthingRitual card) { + super(card); + } + + @Override + public BirthingRitual copy() { + return new BirthingRitual(this); + } +} + +class BirthingRitualEffect extends OneShotEffect { + + BirthingRitualEffect() { + super(Outcome.Benefit); + this.staticText = "look at the top seven cards of your library. Then you may sacrifice a creature. " + + "If you do, you may put a creature card with mana value X or less from among those cards onto the battlefield, " + + "where X is 1 plus the sacrificed creature's mana value. Put the rest on the bottom of your library in a random order."; + } + + private BirthingRitualEffect(final BirthingRitualEffect effect) { + super(effect); + } + + @Override + public BirthingRitualEffect copy() { + return new BirthingRitualEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + // Look at the top seven cards of your library. + Cards cards = new CardsImpl(controller.getLibrary().getTopCards(game, 7)); + controller.lookAtCards(source, null, cards, game); + + // Then you may sacrifice a creature. + TargetPermanent sacrificeTarget = new TargetControlledCreaturePermanent(0, 1); + sacrificeTarget.withNotTarget(true); + controller.choose(Outcome.Sacrifice, sacrificeTarget, source, game); + Permanent sacrificed = game.getPermanent(sacrificeTarget.getFirstTarget()); + if (sacrificed == null || !sacrificed.sacrifice(source, game)) { + return endOfApply(cards, controller, game, source); + } + int mv = 1 + sacrificed.getManaValue(); + // If you do, you may put a creature card with mana value X or less from among those cards onto the battlefield, where X is 1 plus the sacrificed creature's mana value. + FilterCard filter = new FilterCreatureCard("a creature card with mana value " + mv + " or less"); + filter.add(new ManaValuePredicate(ComparisonType.OR_LESS, mv)); + TargetCard target = new TargetCard(0, 1, Zone.LIBRARY, filter); + target.withNotTarget(true); + controller.choose(Outcome.PutCreatureInPlay, target, source, game); + controller.moveCards(target.getTargets().stream().map(game::getCard).collect(Collectors.toSet()), Zone.BATTLEFIELD, source, game); + return endOfApply(cards, controller, game, source); + } + + private boolean endOfApply(Cards cards, Player controller, Game game, Ability source) { + // Put the rest on the bottom of your library in a random order. + cards.retainZone(Zone.LIBRARY, game); + controller.putCardsOnBottomOfLibrary(cards, game, source, false); + return true; + } +} \ No newline at end of file diff --git a/Mage.Sets/src/mage/sets/ModernHorizons3.java b/Mage.Sets/src/mage/sets/ModernHorizons3.java index d64fcdc34c1..2fa4910931b 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons3.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons3.java @@ -33,6 +33,7 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Barbarian Ring", 299, Rarity.UNCOMMON, mage.cards.b.BarbarianRing.class)); cards.add(new SetCardInfo("Basking Broodscale", 145, Rarity.COMMON, mage.cards.b.BaskingBroodscale.class)); cards.add(new SetCardInfo("Bespoke Battlewagon", 52, Rarity.UNCOMMON, mage.cards.b.BespokeBattlewagon.class)); + cards.add(new SetCardInfo("Birthing Ritual", 146, Rarity.MYTHIC, mage.cards.b.BirthingRitual.class)); cards.add(new SetCardInfo("Bloodsoaked Insight", 252, Rarity.UNCOMMON, mage.cards.b.BloodsoakedInsight.class)); cards.add(new SetCardInfo("Bloodstained Mire", 216, Rarity.RARE, mage.cards.b.BloodstainedMire.class)); cards.add(new SetCardInfo("Boggart Trawler", 243, Rarity.UNCOMMON, mage.cards.b.BoggartTrawler.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/BirthingRitualTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/BirthingRitualTest.java new file mode 100644 index 00000000000..7c1dd3c76ab --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/BirthingRitualTest.java @@ -0,0 +1,133 @@ +package org.mage.test.cards.single.mh3; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import org.junit.Assert; +import org.junit.Test; +import org.mage.test.player.TestPlayer; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author Susucr + */ +public class BirthingRitualTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.b.BirthingRitual Birthing Ritual} {1}{G} + * Enchantment + * At the beginning of your end step, if you control a creature, look at the top seven cards of your library. + * Then you may sacrifice a creature. If you do, you may put a creature card with mana value X or less from + * among those cards onto the battlefield, where X is 1 plus the sacrificed creature’s mana value. + * Put the rest on the bottom of your library in a random order. + */ + private static final String ritual = "Birthing Ritual"; + + @Test + public void test_NoCreature_NoTrigger() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, ritual); + + // No trigger. + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + } + + @Test + public void test_Trigger_NoSacrifice() { + setStrictChooseMode(true); + skipInitShuffling(); + + addCard(Zone.BATTLEFIELD, playerA, ritual); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + addCard(Zone.LIBRARY, playerA, "Memnite", 4); + addCard(Zone.LIBRARY, playerA, "Plains", 4); + + setChoice(playerA, TestPlayer.CHOICE_SKIP); // no sacrifice + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, "Grizzly Bears", 1); + assertPermanentCount(playerA, "Memnite", 0); + } + + @Test + public void test_Trigger_Sacrifice_NoChoice() { + setStrictChooseMode(true); + skipInitShuffling(); + + addCard(Zone.BATTLEFIELD, playerA, ritual); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + addCard(Zone.LIBRARY, playerA, "Memnite", 4); + addCard(Zone.LIBRARY, playerA, "Plains", 4); + + setChoice(playerA, "Grizzly Bears"); // sacrifice the Bears + setChoice(playerA, TestPlayer.CHOICE_SKIP); // don't choose a creature to put in play + + setStopAt(2, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, "Grizzly Bears", 0); + assertPermanentCount(playerA, "Memnite", 0); + } + + @Test + public void test_Trigger_Sacrifice_Choice() { + setStrictChooseMode(true); + skipInitShuffling(); + + addCard(Zone.BATTLEFIELD, playerA, ritual); + addCard(Zone.BATTLEFIELD, playerA, "Grizzly Bears"); + addCard(Zone.LIBRARY, playerA, "Centaur Courser", 8); + addCard(Zone.LIBRARY, playerA, "Memnite", 8); + + // Choice for the turn 1 turigger: + setChoice(playerA, "Grizzly Bears"); + setChoice(playerA, "Centaur Courser"); + + checkPermanentCount("3: Courser in play", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Centaur Courser", 1); + checkGraveyardCount("3: Bears in graveyard", 3, PhaseStep.PRECOMBAT_MAIN, playerA, "Grizzly Bears", 1); + + // Choice for the turn 3 trigger: + setChoice(playerA, "Centaur Courser"); + setChoice(playerA, "Memnite"); + + setStopAt(4, PhaseStep.UPKEEP); + execute(); + + assertPermanentCount(playerA, "Centaur Courser", 0); + assertPermanentCount(playerA, "Grizzly Bears", 0); + assertPermanentCount(playerA, "Memnite", 1); + assertGraveyardCount(playerA, 2); + assertGraveyardCount(playerA, "Centaur Courser", 1); + assertGraveyardCount(playerA, "Grizzly Bears", 1); + assertHandCount(playerA, 1); + assertHandCount(playerA, "Memnite", 1); + } + + @Test + public void test_Trigger_Sacrifice_MVRestriction() { + setStrictChooseMode(true); + skipInitShuffling(); + + addCard(Zone.BATTLEFIELD, playerA, ritual); + addCard(Zone.BATTLEFIELD, playerA, "Elite Vanguard"); + addCard(Zone.LIBRARY, playerA, "Memnite", 4); + addCard(Zone.LIBRARY, playerA, "Baneslayer Angel", 4); + + setChoice(playerA, "Elite Vanguard"); // sacrifice the Vanguard + setChoice(playerA, "Baneslayer Angel"); + + setStopAt(2, PhaseStep.UPKEEP); + try { + execute(); + Assert.fail("should not have execute"); + } catch (Throwable e) { + if (!e.getMessage().contains("Select up to one a creature card with mana value 2 or less")) { + Assert.fail("must throw error about missing choice:\n" + e.getMessage()); + } + } + } +}