implement [MH3] Ripples of Undeath

This commit is contained in:
Susucre 2024-05-18 11:52:54 +02:00
parent 876204c7ed
commit a3b7bb785d
3 changed files with 184 additions and 0 deletions

View file

@ -0,0 +1,126 @@
package mage.cards.r;
import mage.abilities.Ability;
import mage.abilities.common.BeginningOfPreCombatMainTriggeredAbility;
import mage.abilities.costs.Costs;
import mage.abilities.costs.CostsImpl;
import mage.abilities.costs.common.PayLifeCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DoIfCostPaid;
import mage.cards.*;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.TargetController;
import mage.constants.Zone;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetCardInGraveyard;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* @author Susucr
*/
public final class RipplesOfUndeath extends CardImpl {
public RipplesOfUndeath(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{B}");
// At the beginning of your precombat main phase, mill three cards. Then you may pay {1} and 3 life. If you do, put a card from among those cards into your hand.
this.addAbility(new BeginningOfPreCombatMainTriggeredAbility(
new RipplesOfUndeathEffect(), TargetController.YOU, false
));
}
private RipplesOfUndeath(final RipplesOfUndeath card) {
super(card);
}
@Override
public RipplesOfUndeath copy() {
return new RipplesOfUndeath(this);
}
}
class RipplesOfUndeathEffect extends OneShotEffect {
RipplesOfUndeathEffect() {
super(Outcome.Benefit);
staticText = "mill three cards. Then you may pay {1} and 3 life. If you do, put a card from among those cards into your hand.";
}
private RipplesOfUndeathEffect(final RipplesOfUndeathEffect effect) {
super(effect);
}
@Override
public RipplesOfUndeathEffect copy() {
return new RipplesOfUndeathEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
Cards milled = controller.millCards(3, source, game);
Costs cost = new CostsImpl();
cost.add(new GenericManaCost(1));
cost.add(new PayLifeCost(3));
new DoIfCostPaid(new RipplesOfUndeathReturnEffect(milled), cost)
.apply(game, source);
return true;
}
}
class RipplesOfUndeathReturnEffect extends OneShotEffect {
private final Set<UUID> milledCards;
RipplesOfUndeathReturnEffect(Set<UUID> milledCards) {
super(Outcome.DrawCard);
staticText = "put a card from among those cards into your hand";
this.milledCards = milledCards;
}
private RipplesOfUndeathReturnEffect(final RipplesOfUndeathReturnEffect effect) {
super(effect);
this.milledCards = new HashSet<>(effect.milledCards);
}
@Override
public RipplesOfUndeathReturnEffect copy() {
return new RipplesOfUndeathReturnEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (milledCards.isEmpty() || controller == null) {
return false;
}
Cards cards = new CardsImpl();
cards.addAll(milledCards);
TargetCardInGraveyard target = new TargetCardInGraveyard();
target.withNotTarget(true);
controller.choose(outcome, cards, target, source, game);
Set<Card> returned = target
.getTargets()
.stream()
.map(game::getCard)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
if (returned.isEmpty()) {
return true;
}
controller.moveCards(returned, Zone.HAND, source, game);
return true;
}
}

View file

@ -118,6 +118,7 @@ public final class ModernHorizons3 extends ExpansionSet {
cards.add(new SetCardInfo("Recruiter of the Guard", 266, Rarity.MYTHIC, mage.cards.r.RecruiterOfTheGuard.class)); cards.add(new SetCardInfo("Recruiter of the Guard", 266, Rarity.MYTHIC, mage.cards.r.RecruiterOfTheGuard.class));
cards.add(new SetCardInfo("Reef Worm", 271, Rarity.UNCOMMON, mage.cards.r.ReefWorm.class)); cards.add(new SetCardInfo("Reef Worm", 271, Rarity.UNCOMMON, mage.cards.r.ReefWorm.class));
cards.add(new SetCardInfo("Revitalizing Repast", 256, Rarity.UNCOMMON, mage.cards.r.RevitalizingRepast.class)); cards.add(new SetCardInfo("Revitalizing Repast", 256, Rarity.UNCOMMON, mage.cards.r.RevitalizingRepast.class));
cards.add(new SetCardInfo("Ripples of Undeath", 107, Rarity.RARE, mage.cards.r.RipplesOfUndeath.class));
cards.add(new SetCardInfo("Roil Cartographer", 67, Rarity.UNCOMMON, mage.cards.r.RoilCartographer.class)); cards.add(new SetCardInfo("Roil Cartographer", 67, Rarity.UNCOMMON, mage.cards.r.RoilCartographer.class));
cards.add(new SetCardInfo("Ruby Medallion", 295, Rarity.RARE, mage.cards.r.RubyMedallion.class)); cards.add(new SetCardInfo("Ruby Medallion", 295, Rarity.RARE, mage.cards.r.RubyMedallion.class));
cards.add(new SetCardInfo("Rush of Inspiration", 257, Rarity.UNCOMMON, mage.cards.r.RushOfInspiration.class)); cards.add(new SetCardInfo("Rush of Inspiration", 257, Rarity.UNCOMMON, mage.cards.r.RushOfInspiration.class));

View file

@ -0,0 +1,57 @@
package org.mage.test.cards.single.mh3;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author Susucr
*/
public class RipplesOfUndeathTest extends CardTestPlayerBase {
/**
* {@link mage.cards.r.RipplesOfUndeath Ripples of Undeath} {1}{B}
* Enchantment
* At the beginning of your precombat main phase, mill three cards. Then you may pay {1} and 3 life. If you do, put a card from among those cards into your hand.
*/
private static final String ripples = "Ripples of Undeath";
@Test
public void test_CantPay() {
setStrictChooseMode(true);
skipInitShuffling();
addCard(Zone.BATTLEFIELD, playerA, ripples);
addCard(Zone.LIBRARY, playerA, "Taiga", 3);
setChoice(playerA, false); // no to "you may pay"
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Taiga", 3);
}
@Test
public void test_Pay() {
setStrictChooseMode(true);
skipInitShuffling();
addCard(Zone.BATTLEFIELD, playerA, ripples);
addCard(Zone.LIBRARY, playerA, "Taiga", 2);
addCard(Zone.LIBRARY, playerA, "Savannah", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains");
setChoice(playerA, true); // yes to "you may pay"
setChoice(playerA, "Savannah"); // return this one
setStopAt(1, PhaseStep.BEGIN_COMBAT);
execute();
assertGraveyardCount(playerA, "Taiga", 2);
assertHandCount(playerA, "Savannah", 1);
assertTappedCount("Plains", true, 1);
assertLife(playerA, 20 - 3);
}
}