diff --git a/Mage.Sets/src/mage/cards/r/RipplesOfPotential.java b/Mage.Sets/src/mage/cards/r/RipplesOfPotential.java new file mode 100644 index 00000000000..076b64fd9ba --- /dev/null +++ b/Mage.Sets/src/mage/cards/r/RipplesOfPotential.java @@ -0,0 +1,138 @@ +package mage.cards.r; + +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; + +import mage.MageObjectReference; +import mage.abilities.Ability; +import mage.abilities.effects.OneShotEffect; +import mage.abilities.effects.common.counter.ProliferateEffect; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; +import mage.constants.CardType; +import mage.constants.Outcome; +import mage.constants.WatcherScope; +import mage.filter.FilterPermanent; +import mage.filter.predicate.Predicates; +import mage.filter.predicate.permanent.PermanentIdPredicate; +import mage.game.Game; +import mage.game.events.GameEvent; +import mage.game.permanent.Permanent; +import mage.players.Player; +import mage.target.TargetPermanent; +import mage.watchers.Watcher; + +/** + * Ripples of Potential {1}{U} + * Instant + * Proliferate, then choose any number of permanents you control that had a counter put on them this way. Those permanents phase out. + * + * @author DominionSpy + */ +public class RipplesOfPotential extends CardImpl { + + public RipplesOfPotential(UUID ownerId, CardSetInfo setInfo) { + super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{1}{U}"); + + // Proliferate, then choose any number of permanents you control that had a counter put on them this way. Those permanents phase out. + // A watcher is required as another effect may prevent counters from being put on permanents (e.g. Solemnity) + this.getSpellAbility().addEffect(new ProliferateEffect()); + this.getSpellAbility().addEffect(new RipplesOfPotentialEffect()); + this.getSpellAbility().addWatcher(new RipplesOfPotentialWatcher()); + } + + private RipplesOfPotential(final RipplesOfPotential card) { + super(card); + } + + @Override + public RipplesOfPotential copy() { + return new RipplesOfPotential(this); + } +} + +class RipplesOfPotentialEffect extends OneShotEffect { + + public RipplesOfPotentialEffect() { + super(Outcome.Benefit); + staticText = ", then choose any number of permanents you control that had a counter put on them this way. Those permanents phase out."; + } + + private RipplesOfPotentialEffect(final RipplesOfPotentialEffect effect) { + super(effect); + } + + @Override + public RipplesOfPotentialEffect copy() { + return new RipplesOfPotentialEffect(this); + } + + @Override + public boolean apply(Game game, Ability source) { + Player controller = game.getPlayer(source.getControllerId()); + if (controller == null) { + return false; + } + + RipplesOfPotentialWatcher watcher = game.getState().getWatcher(RipplesOfPotentialWatcher.class, source.getSourceId()); + if (watcher == null) { + return false; + } + + FilterPermanent filter = new FilterPermanent("permanents"); + filter.add(Predicates.or( + watcher + .getProliferatedPermanents() + .stream() + .map(mor -> mor.getPermanentOrLKIBattlefield(game)) + .filter(Objects::nonNull) + .filter(permanent -> permanent.isControlledBy(source.getControllerId())) + .map(Permanent::getId) + .map(PermanentIdPredicate::new) + .collect(Collectors.toSet()) + )); + TargetPermanent target = new TargetPermanent(0, Integer.MAX_VALUE, filter, true); + controller.choose(outcome, target.withChooseHint("to phase out"), source, game); + for (UUID targetId : target.getTargets()) { + Permanent permanent = game.getPermanent(targetId); + if (permanent != null) { + permanent.phaseOut(game); + } + } + watcher.reset(); + return true; + } +} + +class RipplesOfPotentialWatcher extends Watcher { + + private final Set proliferatedPermanents = new HashSet<>(); + + RipplesOfPotentialWatcher() { + super(WatcherScope.CARD); + } + + @Override + public void watch(GameEvent event, Game game) { + if (event.getType() == GameEvent.EventType.COUNTER_ADDED) { + MageObjectReference mor = new MageObjectReference(event.getTargetId(), game); + Permanent permanent = game.getPermanent(event.getTargetId()); + if (sourceId.equals(event.getSourceId()) && permanent != null) { + proliferatedPermanents.add(mor); + } + } + } + + @Override + public void reset() { + super.reset(); + proliferatedPermanents.clear(); + } + + Set getProliferatedPermanents() { + return proliferatedPermanents; + } +} diff --git a/Mage.Sets/src/mage/sets/LostCavernsOfIxalanCommander.java b/Mage.Sets/src/mage/sets/LostCavernsOfIxalanCommander.java index 5e27fde1841..f3cdacde6be 100644 --- a/Mage.Sets/src/mage/sets/LostCavernsOfIxalanCommander.java +++ b/Mage.Sets/src/mage/sets/LostCavernsOfIxalanCommander.java @@ -231,6 +231,7 @@ public final class LostCavernsOfIxalanCommander extends ExpansionSet { cards.add(new SetCardInfo("Return to Dust", 136, Rarity.UNCOMMON, mage.cards.r.ReturnToDust.class)); cards.add(new SetCardInfo("Rhythm of the Wild", 287, Rarity.UNCOMMON, mage.cards.r.RhythmOfTheWild.class)); cards.add(new SetCardInfo("Ripjaw Raptor", 253, Rarity.RARE, mage.cards.r.RipjawRaptor.class)); + cards.add(new SetCardInfo("Ripples of Potential", 77, Rarity.RARE, mage.cards.r.RipplesOfPotential.class)); cards.add(new SetCardInfo("Rishkar's Expertise", 254, Rarity.RARE, mage.cards.r.RishkarsExpertise.class)); cards.add(new SetCardInfo("Rogue's Passage", 349, Rarity.UNCOMMON, mage.cards.r.RoguesPassage.class)); cards.add(new SetCardInfo("Ruinous Intrusion", 255, Rarity.RARE, mage.cards.r.RuinousIntrusion.class)); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/single/lcc/RipplesOfPotentialTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/single/lcc/RipplesOfPotentialTest.java new file mode 100644 index 00000000000..15473da96c3 --- /dev/null +++ b/Mage.Tests/src/test/java/org/mage/test/cards/single/lcc/RipplesOfPotentialTest.java @@ -0,0 +1,47 @@ +package org.mage.test.cards.single.lcc; + +import mage.constants.PhaseStep; +import mage.constants.Zone; +import mage.counters.CounterType; +import org.junit.Test; +import org.mage.test.serverside.base.CardTestPlayerBase; + +/** + * @author DominionSpy + */ +public class RipplesOfPotentialTest extends CardTestPlayerBase { + + /** + * Ripples of Potential + * {1}{U} + * Instant + * Proliferate, then choose any number of permanents you control that had a counter put on them this way. Those permanents phase out. + */ + @Test + public void test_RipplesOfPotential() { + addCard(Zone.BATTLEFIELD, playerA, "Island", 2); + addCard(Zone.BATTLEFIELD, playerA, "Blast Zone"); + addCard(Zone.BATTLEFIELD, playerA, "Arcbound Javelineer"); + addCard(Zone.BATTLEFIELD, playerA, "Chandra, Pyromaster"); + addCard(Zone.BATTLEFIELD, playerA, "Atraxa's Skitterfang"); + + addCard(Zone.HAND, playerA, "Ripples of Potential"); + + castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Ripples of Potential"); + // Proliferate choice + setChoice(playerA, "Blast Zone^Arcbound Javelineer^Chandra, Pyromaster^Atraxa's Skitterfang"); + // Phase out choice + setChoice(playerA, "Blast Zone^Arcbound Javelineer^Chandra, Pyromaster"); + + setStrictChooseMode(true); + setChoice(playerA, false); // Atraxa's Skitterfang ability + setStopAt(1, PhaseStep.END_TURN); + execute(); + + assertPermanentCount(playerA, "Blast Zone", 0); + assertPermanentCount(playerA, "Arcbound Javelineer", 0); + assertPermanentCount(playerA, "Chandra, Pyromaster", 0); + assertPermanentCount(playerA, "Atraxa's Skitterfang", 1); + assertCounterCount("Atraxa's Skitterfang", CounterType.OIL, 4); + } +}