[STX] Implemented Mavinda, Students' Advocate

This commit is contained in:
Evan Kranzler 2021-04-15 09:21:01 -04:00
parent 6ad67b340a
commit c408776ad7
4 changed files with 161 additions and 16 deletions

View file

@ -0,0 +1,138 @@
package mage.cards.m;
import mage.MageInt;
import mage.MageObject;
import mage.MageObjectReference;
import mage.abilities.Ability;
import mage.abilities.SpellAbility;
import mage.abilities.common.LimitedTimesPerTurnActivatedAbility;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.CastCardFromGraveyardThenExileItEffect;
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.StaticFilters;
import mage.game.Controllable;
import mage.game.Game;
import mage.target.Target;
import mage.target.common.TargetCardInYourGraveyard;
import mage.util.CardUtil;
import java.util.Collection;
import java.util.Objects;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class MavindaStudentsAdvocate extends CardImpl {
public MavindaStudentsAdvocate(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
this.addSuperType(SuperType.LEGENDARY);
this.subtype.add(SubType.BIRD);
this.subtype.add(SubType.ADVISOR);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Flying
this.addAbility(FlyingAbility.getInstance());
// {0}: You may cast target instant or sorcery card from your graveyard this turn. If that spell doesn't target a creature you control, it costs {8} more to cast this way. If that spell would be put into your graveyard, exile it instead. Activate only once each turn.
Ability ability = new LimitedTimesPerTurnActivatedAbility(
Zone.BATTLEFIELD, new MavindaStudentsAdvocateEffect(), new GenericManaCost(0)
);
ability.addTarget(new TargetCardInYourGraveyard(
StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD
));
this.addAbility(ability);
}
private MavindaStudentsAdvocate(final MavindaStudentsAdvocate card) {
super(card);
}
@Override
public MavindaStudentsAdvocate copy() {
return new MavindaStudentsAdvocate(this);
}
}
class MavindaStudentsAdvocateEffect extends CastCardFromGraveyardThenExileItEffect {
MavindaStudentsAdvocateEffect() {
super();
staticText = "you may cast target instant or sorcery card from your graveyard this turn. " +
"If that spell doesn't target a creature you control, it costs {8} more to cast this way. " +
"If that spell would be put into your graveyard, exile it instead";
}
private MavindaStudentsAdvocateEffect(final MavindaStudentsAdvocateEffect effect) {
super(effect);
}
@Override
public MavindaStudentsAdvocateEffect copy() {
return new MavindaStudentsAdvocateEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
if (!super.apply(game, source)) {
return false;
}
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
if (card == null) {
return false;
}
game.addEffect(new MavindaStudentsAdvocateCostEffect(card, game), source);
return true;
}
}
class MavindaStudentsAdvocateCostEffect extends CostModificationEffectImpl {
private final MageObjectReference mor;
MavindaStudentsAdvocateCostEffect(Card card, Game game) {
super(Duration.EndOfTurn, Outcome.Benefit, CostModificationType.INCREASE_COST);
mor = new MageObjectReference(card, game, 1);
}
private MavindaStudentsAdvocateCostEffect(MavindaStudentsAdvocateCostEffect effect) {
super(effect);
this.mor = effect.mor;
}
@Override
public boolean apply(Game game, Ability source, Ability abilityToModify) {
CardUtil.increaseCost(abilityToModify, 8);
return true;
}
@Override
public boolean applies(Ability abilityToModify, Ability source, Game game) {
return abilityToModify instanceof SpellAbility
&& abilityToModify.isControlledBy(source.getControllerId())
&& mor.refersTo(((SpellAbility) abilityToModify).getCharacteristics(game), game)
&& abilityToModify
.getTargets()
.stream()
.map(Target::getTargets)
.flatMap(Collection::stream)
.map(game::getPermanent)
.filter(Objects::nonNull)
.filter(MageObject::isCreature)
.map(Controllable::getControllerId)
.noneMatch(source::isControlledBy);
}
@Override
public MavindaStudentsAdvocateCostEffect copy() {
return new MavindaStudentsAdvocateCostEffect(this);
}
}

View file

@ -178,6 +178,7 @@ public final class StrixhavenSchoolOfMages extends ExpansionSet {
cards.add(new SetCardInfo("Mascot Exhibition", 5, Rarity.MYTHIC, mage.cards.m.MascotExhibition.class));
cards.add(new SetCardInfo("Mascot Interception", 110, Rarity.UNCOMMON, mage.cards.m.MascotInterception.class));
cards.add(new SetCardInfo("Master Symmetrist", 138, Rarity.UNCOMMON, mage.cards.m.MasterSymmetrist.class));
cards.add(new SetCardInfo("Mavinda, Students' Advocate", 21, Rarity.MYTHIC, mage.cards.m.MavindaStudentsAdvocate.class));
cards.add(new SetCardInfo("Mentor's Guidance", 46, Rarity.UNCOMMON, mage.cards.m.MentorsGuidance.class));
cards.add(new SetCardInfo("Mercurial Transformation", 47, Rarity.UNCOMMON, mage.cards.m.MercurialTransformation.class));
cards.add(new SetCardInfo("Mila, Crafty Companion", 153, Rarity.MYTHIC, mage.cards.m.MilaCraftyCompanion.class));

View file

@ -20,7 +20,7 @@ public class CastCardFromGraveyardThenExileItEffect extends OneShotEffect {
super(Outcome.Benefit);
}
CastCardFromGraveyardThenExileItEffect(final CastCardFromGraveyardThenExileItEffect effect) {
protected CastCardFromGraveyardThenExileItEffect(final CastCardFromGraveyardThenExileItEffect effect) {
super(effect);
}
@ -32,15 +32,15 @@ public class CastCardFromGraveyardThenExileItEffect extends OneShotEffect {
@Override
public boolean apply(Game game, Ability source) {
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
if (card != null) {
ContinuousEffect effect = new CastCardFromGraveyardEffect();
effect.setTargetPointer(new FixedTarget(card, game));
game.addEffect(effect, source);
effect = new ExileReplacementEffect(card.getId());
game.addEffect(effect, source);
return true;
if (card == null) {
return false;
}
return false;
ContinuousEffect effect = new CastCardFromGraveyardEffect();
effect.setTargetPointer(new FixedTarget(card, game));
game.addEffect(effect, source);
effect = new ExileReplacementEffect(card.getId());
game.addEffect(effect, source);
return true;
}
}
@ -51,7 +51,7 @@ class CastCardFromGraveyardEffect extends AsThoughEffectImpl {
this.staticText = "You may cast target card from your graveyard";
}
CastCardFromGraveyardEffect(final CastCardFromGraveyardEffect effect) {
private CastCardFromGraveyardEffect(final CastCardFromGraveyardEffect effect) {
super(effect);
}
@ -67,7 +67,8 @@ class CastCardFromGraveyardEffect extends AsThoughEffectImpl {
@Override
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
return objectId.equals(this.getTargetPointer().getFirst(game, source)) && affectedControllerId.equals(source.getControllerId());
return objectId.equals(this.getTargetPointer().getFirst(game, source))
&& affectedControllerId.equals(source.getControllerId());
}
}
@ -81,7 +82,7 @@ class ExileReplacementEffect extends ReplacementEffectImpl {
this.staticText = "If that card would be put into your graveyard this turn, exile it instead";
}
ExileReplacementEffect(final ExileReplacementEffect effect) {
private ExileReplacementEffect(final ExileReplacementEffect effect) {
super(effect);
this.cardId = effect.cardId;
}
@ -95,10 +96,9 @@ class ExileReplacementEffect extends ReplacementEffectImpl {
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Player controller = game.getPlayer(source.getControllerId());
Card card = game.getCard(this.cardId);
if (controller != null && card != null) {
return controller.moveCards(card, Zone.EXILED, source, game);
}
return false;
return controller != null
&& card != null
&& controller.moveCards(card, Zone.EXILED, source, game);
}
@Override

View file

@ -114,6 +114,12 @@ public final class StaticFilters {
FILTER_CARD_FROM_YOUR_GRAVEYARD.setLockedFilter(true);
}
public static final FilterCard FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD = new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard");
static {
FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD.setLockedFilter(true);
}
public static final FilterNoncreatureCard FILTER_CARD_NON_CREATURE = new FilterNoncreatureCard();
static {