diff --git a/Mage.Sets/src/mage/cards/s/SuppressionRay.java b/Mage.Sets/src/mage/cards/s/SuppressionRay.java new file mode 100644 index 00000000000..0364315a1b7 --- /dev/null +++ b/Mage.Sets/src/mage/cards/s/SuppressionRay.java @@ -0,0 +1,142 @@ +package mage.cards.s; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.common.EntersBattlefieldTappedAbility; +import mage.abilities.costs.Cost; +import mage.abilities.costs.common.PayEnergyCost; +import mage.abilities.dynamicvalue.common.SourceControllerCountersCount; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.AddCountersTargetEffect; +import mage.abilities.mana.BlueManaAbility; +import mage.abilities.mana.WhiteManaAbility; +import mage.cards.CardSetInfo; +import mage.cards.ModalDoubleFacedCard; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.SubType; +import mage.counters.CounterType; +import mage.filter.FilterPermanent; +import mage.filter.StaticFilters; +import mage.filter.predicate.permanent.PermanentReferenceInCollectionPredicate; +import mage.game.Game; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.target.TargetPlayer; +import mage.target.targetpointer.FixedTargets; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +/** + * @author Susucr + */ +public final class SuppressionRay extends ModalDoubleFacedCard { + + public SuppressionRay(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, + new CardType[]{CardType.SORCERY}, new SubType[]{}, "{3}{W/U}{W/U}", + "Orderly Plaza", new CardType[]{CardType.LAND}, new SubType[]{}, "" + ); + + // 1. + // Suppression Ray + // Sorcery + + // Tap all creatures target player controls. You may pay X {E}, then choose up to X creatures tapped this way. Put a stun counter on each of them. + this.getLeftHalfCard().getSpellAbility().addEffect(new SuppressionRayTargetEffect()); + this.getLeftHalfCard().getSpellAbility().addTarget(new TargetPlayer()); + + // 2. + // Orderly Plaza + // Land + + // Orderly Plaza enters the battlefield tapped. + this.getRightHalfCard().addAbility(new EntersBattlefieldTappedAbility()); + + // {T}: Add {W} or {U}. + this.getRightHalfCard().addAbility(new WhiteManaAbility()); + this.getRightHalfCard().addAbility(new BlueManaAbility()); + } + + private SuppressionRay(final SuppressionRay card) { + super(card); + } + + @Override + public SuppressionRay copy() { + return new SuppressionRay(this); + } +} + +class SuppressionRayTargetEffect extends OneShotEffect { + + SuppressionRayTargetEffect() { + super(Outcome.Tap); + staticText = "Tap all creatures target player controls." + + "You may pay X {E}, then choose up to X creatures tapped this way. " + + "Put a stun counter on each of them."; + } + + private SuppressionRayTargetEffect(final SuppressionRayTargetEffect effect) { + super(effect); + } + + @Override + public SuppressionRayTargetEffect copy() { + return new SuppressionRayTargetEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player player = game.getPlayer(source.getFirstTarget()); + Player controller = game.getPlayer(source.getControllerId()); + if (player == null || controller == null) { + return false; + } + List tappedThisWay = new ArrayList<>(); + for (Permanent creature : game.getBattlefield().getAllActivePermanents(StaticFilters.FILTER_PERMANENT_CREATURE, player.getId(), game)) { + if (!creature.isTapped()) { + creature.tap(source, game); + if (creature.isTapped()) { + tappedThisWay.add(new MageObjectReference(creature, game)); + } + } + } + int maxEnergy = SourceControllerCountersCount.ENERGY.calculate(game, source, this); + if (maxEnergy == 0) { + // No energy to pay. Stop there. + return true; + } + int numberToPay = controller.getAmount( + 0, maxEnergy, + "How many {E} do you like to pay? (" + tappedThisWay.size() + " creature(s) were tapped)", + game + ); + if (numberToPay == 0) { + // No energy was paid. + return true; + } + Cost cost = new PayEnergyCost(numberToPay); + if (cost.pay(source, game, source, source.getControllerId(), true)) { + FilterPermanent filter = new FilterPermanent("creature tapped this way"); + filter.add(new PermanentReferenceInCollectionPredicate(tappedThisWay)); + TargetPermanent target = new TargetPermanent(0, numberToPay, filter, true); + target.choose(Outcome.Tap, controller.getId(), source.getSourceId(), source, game); + List toPutStunCounterOn = target + .getTargets() + .stream() + .map(id -> new MageObjectReference(id, game)) + .collect(Collectors.toList()); + if (!toPutStunCounterOn.isEmpty()) { + new AddCountersTargetEffect(CounterType.STUN.createInstance()) + .setTargetPointer(new FixedTargets(toPutStunCounterOn)) + .apply(game, source); + } + } + 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 bf7e97ecbdf..b1bb6b6e843 100644 --- a/Mage.Sets/src/mage/sets/ModernHorizons3.java +++ b/Mage.Sets/src/mage/sets/ModernHorizons3.java @@ -101,6 +101,7 @@ public final class ModernHorizons3 extends ExpansionSet { cards.add(new SetCardInfo("Spawn-Gang Commander", 140, Rarity.UNCOMMON, mage.cards.s.SpawnGangCommander.class)); cards.add(new SetCardInfo("Strength of the Harvest", 258, Rarity.UNCOMMON, mage.cards.s.StrengthOfTheHarvest.class)); cards.add(new SetCardInfo("Stump Stomp", 259, Rarity.UNCOMMON, mage.cards.s.StumpStomp.class)); + cards.add(new SetCardInfo("Suppression Ray", 260, Rarity.UNCOMMON, mage.cards.s.SuppressionRay.class)); cards.add(new SetCardInfo("Swamp", 306, Rarity.LAND, mage.cards.basiclands.Swamp.class, FULL_ART_BFZ_VARIOUS)); cards.add(new SetCardInfo("Sylvan Safekeeper", 287, Rarity.RARE, mage.cards.s.SylvanSafekeeper.class)); cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 242, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/SuppressionRayTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/SuppressionRayTest.java new file mode 100644 index 00000000000..17909938b02 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/mh3/SuppressionRayTest.java @@ -0,0 +1,58 @@ +package org.mage.test.cards.single.mh3; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author Susucr + */ +public class SuppressionRayTest extends CardTestPlayerBase { + + /** + * {@link mage.cards.s.SuppressionRay Suppression Ray} {3}{W/U}{W/U} + * Sorcery + * Tap all creatures target player controls. You may pay X {E}, then choose up to X creatures tapped this way. Put a stun counter on each of them. + * Orderly Plaza + * Land + * Orderly Plaza enters the battlefield tapped. + * {T}: Add {W} or {U}. + */ + private static final String ray = "Suppression Ray"; + + @Test + public void test_Simple() { + setStrictChooseMode(true); + + addCard(Zone.BATTLEFIELD, playerA, "Zodiac Dog"); + addCard(Zone.BATTLEFIELD, playerB, "Zodiac Goat"); + addCard(Zone.BATTLEFIELD, playerB, "Zodiac Horse"); + addCard(Zone.BATTLEFIELD, playerB, "Zodiac Rabbit"); + addCard(Zone.BATTLEFIELD, playerB, "Zodiac Pig"); + addCard(Zone.HAND, playerA, "Suppression Ray"); + addCard(Zone.HAND, playerA, "Aethertide Whale"); // etb, you get 6 {E} + addCard(Zone.BATTLEFIELD, playerA, "Island", 11); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Aethertide Whale", true); + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Suppression Ray", playerB); + setChoiceAmount(playerA, 3); // decide to pay 3 energy + setChoice(playerA, "Zodiac Pig^Zodiac Rabbit"); // put stun on those 2 creatures + + setStopAt(1, PhaseStep.BEGIN_COMBAT); + execute(); + + assertTapped("Zodiac Dog", false); + assertTapped("Zodiac Goat", true); + assertTapped("Zodiac Horse", true); + assertTapped("Zodiac Rabbit", true); + assertTapped("Zodiac Pig", true); + assertCounterCount(playerA, "Zodiac Dog", CounterType.STUN, 0); + assertCounterCount(playerB, "Zodiac Goat", CounterType.STUN, 0); + assertCounterCount(playerB, "Zodiac Horse", CounterType.STUN, 0); + assertCounterCount(playerB, "Zodiac Rabbit", CounterType.STUN, 1); + assertCounterCount(playerB, "Zodiac Pig", CounterType.STUN, 1); + assertCounterCount(playerA, CounterType.ENERGY, 6 - 3); + } +} diff --git a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java index f3621d5048e..2e67f2b473b 100644 --- a/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java +++ b/Mage.Tests/src/test/java/org/mage/test/serverside/base/impl/CardTestPlayerAPIImpl.java @@ -1094,11 +1094,11 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement /** * Assert counter count on a permanent * - * @param player Player who owns the card named cardName - * @param cardName Name of the card that should be counted. - * @param counterName Name of the counter that should be counted. - * (for custom ability counters, use getRule() from the ability) - * @param count Expected count. + * @param player Player who owns the card named cardName + * @param cardName Name of the card that should be counted. + * @param counterName Name of the counter that should be counted. + * (for custom ability counters, use getRule() from the ability) + * @param count Expected count. */ public void assertCounterCount(Player player, String cardName, String counterName, int count) throws AssertionError { //Assert.assertNotEquals("", cardName); @@ -1607,6 +1607,7 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement public void assertTopCardRevealed(TestPlayer player, boolean isRevealed) { Assert.assertEquals(isRevealed, player.isTopCardRevealed()); } + /** * Asserts if, or if not, theAttachment is attached to thePermanent. * @@ -1617,14 +1618,14 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement .filter(permanent -> permanent.isControlledBy(thePlayer.getId())) .filter(permanent -> permanent.getName().equals(thePermanent)) .collect(Collectors.toList()); - assertTrue(theAttachment + " was "+ (!isAttached ? "":"not") +" attached to " + thePermanent, + assertTrue(theAttachment + " was " + (!isAttached ? "" : "not") + " attached to " + thePermanent, !isAttached ^ - permanents.stream() - .anyMatch(permanent -> permanent.getAttachments() - .stream() - .map(id -> currentGame.getCard(id)) - .map(MageObject::getName) - .collect(Collectors.toList()).contains(theAttachment))); + permanents.stream() + .anyMatch(permanent -> permanent.getAttachments() + .stream() + .map(id -> currentGame.getCard(id)) + .map(MageObject::getName) + .collect(Collectors.toList()).contains(theAttachment))); }