implement [MH3] Phelia, Exuberant Shepherd

This commit is contained in:
Susucre 2024-05-04 19:27:24 +02:00
parent d8959f1588
commit b9511afa50
3 changed files with 274 additions and 0 deletions

View file

@ -0,0 +1,121 @@
package mage.cards.p;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.ExileTargetEffect;
import mage.abilities.keyword.FlashAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.common.FilterNonlandPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.game.ExileZone;
import mage.game.Game;
import mage.game.permanent.Permanent;
import mage.players.Player;
import mage.target.TargetPermanent;
import mage.util.CardUtil;
import java.util.Set;
import java.util.UUID;
/**
* @author Susucr
*/
public final class PheliaExuberantShepherd extends CardImpl {
private static final FilterPermanent filter = new FilterNonlandPermanent("other target nonland permanent");
static {
filter.add(AnotherPredicate.instance);
}
public PheliaExuberantShepherd(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.DOG);
this.power = new MageInt(2);
this.toughness = new MageInt(2);
// Flash
this.addAbility(FlashAbility.getInstance());
// Whenever Phelia, Exuberant Shepherd attacks, exile up to one other target nonland permanent. At the beginning of the next end step, return that card to the battlefield under its owner's control. If it entered under your control, put a +1/+1 counter on Phelia.
Ability ability = new AttacksTriggeredAbility(new ExileTargetEffect().setToSourceExileZone(true));
ability.addEffect(new CreateDelayedTriggeredAbilityEffect(
new AtTheBeginOfNextEndStepDelayedTriggeredAbility(new PheliaExuberantShepherdEffect()), false
));
ability.addTarget(new TargetPermanent(0, 1, filter));
this.addAbility(ability);
}
private PheliaExuberantShepherd(final PheliaExuberantShepherd card) {
super(card);
}
@Override
public PheliaExuberantShepherd copy() {
return new PheliaExuberantShepherd(this);
}
}
class PheliaExuberantShepherdEffect extends OneShotEffect {
PheliaExuberantShepherdEffect() {
super(Outcome.Benefit);
staticText = "return that card to the battlefield under its owner's control. "
+ "If it entered under your control, put a +1/+1 counter on {this}";
}
private PheliaExuberantShepherdEffect(final PheliaExuberantShepherdEffect effect) {
super(effect);
}
@Override
public PheliaExuberantShepherdEffect copy() {
return new PheliaExuberantShepherdEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
if (player == null) {
return false;
}
UUID zoneId = CardUtil.getExileZoneId(game, source.getSourceId(), source.getSourceObjectZoneChangeCounter());
ExileZone exileZone = game.getExile().getExileZone(zoneId);
if (exileZone == null || exileZone.isEmpty()) {
return false;
}
Set<Card> cards = exileZone.getCards(game);
player.moveCards(cards, Zone.BATTLEFIELD, source, game, false, false, true, null);
game.getState().applyEffects(game);
Permanent phelia = source.getSourcePermanentIfItStillExists(game);
if (phelia == null) {
return true; // If phelia is no longer on the battlefield, the +1/+1 part of the effect does not apply.
}
boolean enteredUnderYourControl = false;
for (Card card : cards) {
// Try to find the permanent that card became
Permanent permanent = game.getPermanent(card.getId());
if (permanent != null && permanent.getControllerId().equals(source.getControllerId())) {
enteredUnderYourControl = true;
break;
}
}
if (!enteredUnderYourControl) {
return true;
}
phelia.addCounters(CounterType.P1P1.createInstance(), source, game);
return true;
}
}

View file

@ -40,6 +40,7 @@ public final class ModernHorizons3 extends ExpansionSet {
cards.add(new SetCardInfo("Null Elemental Blast", 12, Rarity.UNCOMMON, mage.cards.n.NullElementalBlast.class));
cards.add(new SetCardInfo("Nulldrifter", 13, Rarity.RARE, mage.cards.n.Nulldrifter.class));
cards.add(new SetCardInfo("Orim's Chant", 265, Rarity.RARE, mage.cards.o.OrimsChant.class));
cards.add(new SetCardInfo("Phelia, Exuberant Shepherd", 40, Rarity.RARE, mage.cards.p.PheliaExuberantShepherd.class));
cards.add(new SetCardInfo("Plains", 304, Rarity.LAND, mage.cards.basiclands.Plains.class, FULL_ART_BFZ_VARIOUS));
cards.add(new SetCardInfo("Polluted Delta", 224, Rarity.RARE, mage.cards.p.PollutedDelta.class));
cards.add(new SetCardInfo("Priest of Titania", 286, Rarity.UNCOMMON, mage.cards.p.PriestOfTitania.class));

View file

@ -0,0 +1,152 @@
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 PheliaExuberantShepherdTest extends CardTestPlayerBase {
/**
* {@link mage.cards.p.PheliaExuberantShepherd Phelia, Exuberant Sheperd} {1}{W}
* Legendary Creature Dog
* Flash
* Whenever Phelia, Exuberant Shepherd attacks, exile up to one other target nonland permanent. At the beginning of the next end step, return that card to the battlefield under its owners control. If it entered under your control, put a +1/+1 counter on Phelia.
* 2/2
*/
private static final String phelia = "Phelia, Exuberant Shepherd";
@Test
public void test_Simple_Opponent() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, phelia, 1);
addCard(Zone.BATTLEFIELD, playerB, "Memnite", 1);
attack(1, playerA, phelia, playerB);
addTarget(playerA, "Memnite");
checkExileCount("Memnite got exiled", 1, PhaseStep.POSTCOMBAT_MAIN, playerB, "Memnite", 1);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, phelia, 1);
assertPowerToughness(playerA, phelia, 2 + 0, 2 + 0);
assertPermanentCount(playerB, "Memnite", 1);
}
@Test
public void test_Simple_Owned() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, phelia, 1);
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
attack(1, playerA, phelia, playerB);
addTarget(playerA, "Memnite");
checkExileCount("Memnite got exiled", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Memnite", 1);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, phelia, 1);
assertPowerToughness(playerA, phelia, 2 + 1, 2 + 1);
assertPermanentCount(playerA, "Memnite", 1);
}
@Test
public void test_Killed_OnTrigger() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, phelia, 1);
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
addCard(Zone.HAND, playerA, "Doom Blade", 1);
attack(1, playerA, phelia, playerB);
addTarget(playerA, "Memnite");
castSpell(1, PhaseStep.DECLARE_ATTACKERS, playerA, "Doom Blade", phelia); // the attack trigger on the stack.
checkExileCount("Memnite got exiled", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Memnite", 1);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, phelia, 0);
assertPermanentCount(playerA, "Memnite", 1);
}
@Test
public void test_Killed_AfterTrigger() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, phelia, 1);
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 2);
addCard(Zone.HAND, playerA, "Doom Blade", 1);
attack(1, playerA, phelia, playerB);
addTarget(playerA, "Memnite");
castSpell(1, PhaseStep.DECLARE_BLOCKERS, playerA, "Doom Blade", phelia);
checkExileCount("Memnite got exiled", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Memnite", 1);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, phelia, 0);
assertPermanentCount(playerA, "Memnite", 1);
}
@Test
public void test_Blink_OnTrigger() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, phelia, 1);
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.HAND, playerA, "Ephemerate", 1);
attack(1, playerA, phelia, playerB);
addTarget(playerA, "Memnite");
castSpell(1, PhaseStep.DECLARE_ATTACKERS, playerA, "Ephemerate", phelia); // the attack trigger on the stack.
checkExileCount("Memnite got exiled", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Memnite", 1);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, phelia, 1);
assertPowerToughness(playerA, phelia, 2 + 0, 2 + 0);
assertPermanentCount(playerA, "Memnite", 1);
}
@Test
public void test_Blink_AfterTrigger() {
setStrictChooseMode(true);
addCard(Zone.BATTLEFIELD, playerA, phelia, 1);
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
addCard(Zone.HAND, playerA, "Ephemerate", 1);
attack(1, playerA, phelia, playerB);
addTarget(playerA, "Memnite");
castSpell(1, PhaseStep.DECLARE_BLOCKERS, playerA, "Ephemerate", phelia);
checkExileCount("Memnite got exiled", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Memnite", 1);
setStopAt(2, PhaseStep.UPKEEP);
execute();
assertPermanentCount(playerA, phelia, 1);
assertPowerToughness(playerA, phelia, 2 + 0, 2 + 0);
assertPermanentCount(playerA, "Memnite", 1);
}
}