forked from External/mage
refactor effects "you may cast... from... graveyard... exile it instead" (#10926)
* cleanup exiling cast spells * common class MayCastTargetThenExileEffect * fix zcc check * add test suite
This commit is contained in:
parent
570b47705a
commit
4af977289e
23 changed files with 461 additions and 1252 deletions
|
|
@ -4,13 +4,15 @@ import mage.ObjectColor;
|
|||
import mage.abilities.Ability;
|
||||
import mage.abilities.LoyaltyAbility;
|
||||
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
|
||||
import mage.abilities.effects.*;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.InfoEffect;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.effects.common.SacrificeTargetEffect;
|
||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||
import mage.abilities.effects.common.counter.AddCountersAllEffect;
|
||||
import mage.abilities.keyword.HasteAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
|
|
@ -22,8 +24,6 @@ import mage.filter.common.FilterInstantOrSorceryCard;
|
|||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.token.RedElementalToken;
|
||||
import mage.game.permanent.token.Token;
|
||||
|
|
@ -33,14 +33,14 @@ import mage.target.targetpointer.FixedTarget;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* @author TheElk801, xenohedron
|
||||
*/
|
||||
public final class ChandraAcolyteOfFlame extends CardImpl {
|
||||
|
||||
private static final FilterPermanent filter
|
||||
= new FilterControlledPlaneswalkerPermanent("red planeswalker you control");
|
||||
private static final FilterCard filter2
|
||||
= new FilterInstantOrSorceryCard("instant or sorcery card with mana value 3 or less");
|
||||
= new FilterInstantOrSorceryCard("instant or sorcery card with mana value 3 or less from your graveyard");
|
||||
|
||||
static {
|
||||
filter.add(new ColorPredicate(ObjectColor.RED));
|
||||
|
|
@ -61,7 +61,7 @@ public final class ChandraAcolyteOfFlame extends CardImpl {
|
|||
this.addAbility(new LoyaltyAbility(new ChandraAcolyteOfFlameEffect(), 0));
|
||||
|
||||
// -2: You may cast target instant or sorcery card with converted mana cost 3 or less from your graveyard. If that card would be put into your graveyard this turn, exile it instead.
|
||||
Ability ability = new LoyaltyAbility(new ChandraAcolyteOfFlameGraveyardEffect(), -2);
|
||||
Ability ability = new LoyaltyAbility(new MayCastTargetThenExileEffect(false), -2);
|
||||
ability.addTarget(new TargetCardInYourGraveyard(filter2));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
|
@ -119,101 +119,3 @@ class ChandraAcolyteOfFlameEffect extends OneShotEffect {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class ChandraAcolyteOfFlameGraveyardEffect extends OneShotEffect {
|
||||
|
||||
ChandraAcolyteOfFlameGraveyardEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "You may cast target instant or sorcery card " +
|
||||
"with mana value 3 or less from your graveyard this turn. " +
|
||||
"If that card would be put into your graveyard this turn, exile it instead";
|
||||
}
|
||||
|
||||
private ChandraAcolyteOfFlameGraveyardEffect(final ChandraAcolyteOfFlameGraveyardEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChandraAcolyteOfFlameGraveyardEffect copy() {
|
||||
return new ChandraAcolyteOfFlameGraveyardEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
||||
if (card != null) {
|
||||
ContinuousEffect effect = new ChandraAcolyteOfFlameCastFromGraveyardEffect();
|
||||
effect.setTargetPointer(new FixedTarget(card, game));
|
||||
game.addEffect(effect, source);
|
||||
effect = new ChandraAcolyteOfFlameReplacementEffect(card.getId());
|
||||
game.addEffect(effect, source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class ChandraAcolyteOfFlameCastFromGraveyardEffect extends AsThoughEffectImpl {
|
||||
|
||||
ChandraAcolyteOfFlameCastFromGraveyardEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
|
||||
}
|
||||
|
||||
private ChandraAcolyteOfFlameCastFromGraveyardEffect(final ChandraAcolyteOfFlameCastFromGraveyardEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChandraAcolyteOfFlameCastFromGraveyardEffect copy() {
|
||||
return new ChandraAcolyteOfFlameCastFromGraveyardEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
return objectId.equals(this.getTargetPointer().getFirst(game, source)) && affectedControllerId.equals(source.getControllerId());
|
||||
}
|
||||
}
|
||||
|
||||
class ChandraAcolyteOfFlameReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID cardId;
|
||||
|
||||
ChandraAcolyteOfFlameReplacementEffect(UUID cardId) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.cardId = cardId;
|
||||
staticText = "If that card would be put into your graveyard this turn, exile it instead";
|
||||
}
|
||||
|
||||
private ChandraAcolyteOfFlameReplacementEffect(final ChandraAcolyteOfFlameReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ChandraAcolyteOfFlameReplacementEffect copy() {
|
||||
return new ChandraAcolyteOfFlameReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& zEvent.getTargetId().equals(this.cardId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ package mage.cards.c;
|
|||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.LoyaltyAbility;
|
||||
import mage.abilities.effects.CastCardFromGraveyardThenExileItEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.DamagePlayersEffect;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.effects.common.continuous.CastFromHandWithoutPayingManaCostEffect;
|
||||
import mage.abilities.effects.common.discard.DiscardHandControllerEffect;
|
||||
import mage.cards.CardImpl;
|
||||
|
|
@ -14,23 +14,21 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.common.FilterInstantOrSorceryCard;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author htrajan
|
||||
* @author htrajan, xenohedron
|
||||
*/
|
||||
public final class ChandraFlamesCatalyst extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard();
|
||||
private static final FilterCard filter = new FilterInstantOrSorceryCard("red instant or sorcery card from your graveyard");
|
||||
|
||||
static {
|
||||
filter.add(new ColorPredicate(ObjectColor.RED));
|
||||
filter.add(Predicates.or(CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate()));
|
||||
}
|
||||
|
||||
public ChandraFlamesCatalyst(UUID ownerId, CardSetInfo setInfo) {
|
||||
|
|
@ -44,9 +42,7 @@ public final class ChandraFlamesCatalyst extends CardImpl {
|
|||
this.addAbility(new LoyaltyAbility(new DamagePlayersEffect(3, TargetController.OPPONENT), 1));
|
||||
|
||||
// −2: You may cast target red instant or sorcery card from your graveyard. If that spell would be put into your graveyard this turn, exile it instead.
|
||||
CastCardFromGraveyardThenExileItEffect minusEffect = new CastCardFromGraveyardThenExileItEffect();
|
||||
minusEffect.setText("You may cast target red instant or sorcery card from your graveyard. If that spell would be put into your graveyard this turn, exile it instead");
|
||||
Ability ability = new LoyaltyAbility(minusEffect, -2);
|
||||
Ability ability = new LoyaltyAbility(new MayCastTargetThenExileEffect(false), -2);
|
||||
ability.addTarget(new TargetCardInYourGraveyard(filter));
|
||||
this.addAbility(ability);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
package mage.cards.d;
|
||||
|
||||
import mage.ApprovingObject;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.common.SimpleEvasionAbility;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.effects.common.combat.CantBeBlockedByCreaturesSourceEffect;
|
||||
import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect;
|
||||
import mage.abilities.keyword.CrewAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
|
|
@ -21,15 +17,14 @@ import mage.filter.predicate.card.OwnerIdPredicate;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.DamagedPlayerEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetCardInGraveyard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* @author TheElk801, Grath, xenohedron
|
||||
*/
|
||||
public final class DeluxeDragster extends CardImpl {
|
||||
|
||||
|
|
@ -69,11 +64,15 @@ public final class DeluxeDragster extends CardImpl {
|
|||
|
||||
class DeluxeDragsterTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public DeluxeDragsterTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new DeluxeDragsterEffect(), true);
|
||||
DeluxeDragsterTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new MayCastTargetThenExileEffect(true)
|
||||
.setText("you may cast target instant or sorcery card from "
|
||||
+ "that player's graveyard without paying its mana cost. "
|
||||
+ ThatSpellGraveyardExileReplacementEffect.RULE_A), false);
|
||||
setTriggerPhrase("Whenever {this} deals combat damage to a player, ");
|
||||
}
|
||||
|
||||
public DeluxeDragsterTriggeredAbility(final DeluxeDragsterTriggeredAbility ability) {
|
||||
private DeluxeDragsterTriggeredAbility(final DeluxeDragsterTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
|
|
@ -96,102 +95,15 @@ class DeluxeDragsterTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (damagedPlayer == null) {
|
||||
return false;
|
||||
}
|
||||
FilterCard filter = new FilterCard("instant or sorcery in " + damagedPlayer.getName() + "'s graveyard");
|
||||
filter.add(Predicates.or(CardType.INSTANT.getPredicate(), CardType.SORCERY.getPredicate()));
|
||||
FilterCard filter = new FilterCard("instant or sorcery card from that player's graveyard");
|
||||
filter.add(new OwnerIdPredicate(damagedPlayer.getId()));
|
||||
TargetCardInGraveyard target = new TargetCardInGraveyard(filter);
|
||||
filter.add(Predicates.or(
|
||||
CardType.INSTANT.getPredicate(),
|
||||
CardType.SORCERY.getPredicate()
|
||||
));
|
||||
Target target = new TargetCardInGraveyard(filter);
|
||||
this.getTargets().clear();
|
||||
this.addTarget(target);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever {this} deals combat damage to a player, "
|
||||
+ "you may cast target instant or sorcery card from "
|
||||
+ "that player's graveyard without paying its mana "
|
||||
+ "cost. If that spell would be put into a graveyard, "
|
||||
+ "exile it instead.";
|
||||
}
|
||||
}
|
||||
|
||||
class DeluxeDragsterEffect extends OneShotEffect {
|
||||
|
||||
public DeluxeDragsterEffect() {
|
||||
super(Outcome.PlayForFree);
|
||||
this.staticText = "you may cast target instant or sorcery card from "
|
||||
+ "that player's graveyard without paying its mana "
|
||||
+ "cost. If that spell would be put into a graveyard, "
|
||||
+ "exile it instead";
|
||||
}
|
||||
|
||||
public DeluxeDragsterEffect(final DeluxeDragsterEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeluxeDragsterEffect copy() {
|
||||
return new DeluxeDragsterEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Card targetCard = game.getCard(source.getFirstTarget());
|
||||
if (targetCard != null) {
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + targetCard.getId(), Boolean.TRUE);
|
||||
Boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(targetCard, game, true),
|
||||
game, true, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + targetCard.getId(), null);
|
||||
if (cardWasCast) {
|
||||
ContinuousEffect effect = new DeluxeDragsterReplacementEffect();
|
||||
effect.setTargetPointer(new FixedTarget(targetCard.getId(), game.getState().getZoneChangeCounter(targetCard.getId())));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class DeluxeDragsterReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
public DeluxeDragsterReplacementEffect() {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
staticText = "If that spell would be put into a graveyard this turn, exile it instead";
|
||||
}
|
||||
|
||||
public DeluxeDragsterReplacementEffect(final DeluxeDragsterReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeluxeDragsterReplacementEffect copy() {
|
||||
return new DeluxeDragsterReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& event.getTargetId().equals(getTargetPointer().getFirst(game, source));
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect;
|
||||
import mage.abilities.keyword.FirstStrikeAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
|
|
@ -14,8 +14,6 @@ import mage.constants.*;
|
|||
import mage.filter.FilterCard;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInOpponentsGraveyard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
|
@ -67,14 +65,14 @@ public final class DireFleetDaredevil extends CardImpl {
|
|||
|
||||
class DireFleetDaredevilEffect extends OneShotEffect {
|
||||
|
||||
public DireFleetDaredevilEffect() {
|
||||
DireFleetDaredevilEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "exile target instant or sorcery card from an opponent's graveyard. " +
|
||||
"You may cast it this turn, and you may spend mana as though it were mana of any type " +
|
||||
"to cast that spell. If that spell would be put into a graveyard this turn, exile it instead";
|
||||
"You may cast it this turn, and mana of any type can be spent to cast that spell. "
|
||||
+ ThatSpellGraveyardExileReplacementEffect.RULE_A;
|
||||
}
|
||||
|
||||
public DireFleetDaredevilEffect(final DireFleetDaredevilEffect effect) {
|
||||
private DireFleetDaredevilEffect(final DireFleetDaredevilEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
|
|
@ -86,64 +84,22 @@ class DireFleetDaredevilEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Card targetCard = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
if (targetCard != null) {
|
||||
if (controller.moveCards(targetCard, Zone.EXILED, source, game)) {
|
||||
targetCard = game.getCard(targetCard.getId());
|
||||
if (targetCard != null) {
|
||||
// you may play and spend any mana
|
||||
CardUtil.makeCardPlayable(game, source, targetCard, Duration.EndOfTurn, true);
|
||||
// exile from graveyard
|
||||
ContinuousEffect effect = new DireFleetDaredevilReplacementEffect();
|
||||
effect.setTargetPointer(new FixedTarget(targetCard, game));
|
||||
game.addEffect(effect, source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
Card targetCard = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
if (controller == null || targetCard == null) {
|
||||
return false;
|
||||
}
|
||||
if (controller.moveCards(targetCard, Zone.EXILED, source, game)) {
|
||||
Card card = game.getCard(targetCard.getId());
|
||||
if (card != null) {
|
||||
// you may play and spend any mana
|
||||
CardUtil.makeCardPlayable(game, source, card, Duration.EndOfTurn, true);
|
||||
// exile from graveyard
|
||||
ContinuousEffect effect = new ThatSpellGraveyardExileReplacementEffect(false);
|
||||
effect.setTargetPointer(new FixedTarget(card, game));
|
||||
game.addEffect(effect, source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class DireFleetDaredevilReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
public DireFleetDaredevilReplacementEffect() {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
staticText = "If that card would be put into a graveyard this turn, exile it instead";
|
||||
}
|
||||
|
||||
public DireFleetDaredevilReplacementEffect(final DireFleetDaredevilReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DireFleetDaredevilReplacementEffect copy() {
|
||||
return new DireFleetDaredevilReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (card != null && controller != null) {
|
||||
return controller.moveCards(card, Zone.EXILED, source, game);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& event.getTargetId().equals(((FixedTarget) getTargetPointer()).getTarget())
|
||||
&& ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1
|
||||
== game.getState().getZoneChangeCounter(event.getTargetId());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,36 +3,30 @@ package mage.cards.d;
|
|||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterInstantOrSorceryCard;
|
||||
import mage.filter.predicate.ObjectSourcePlayer;
|
||||
import mage.filter.predicate.ObjectSourcePlayerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ApprovingObject;
|
||||
|
||||
/**
|
||||
* @author TheElk801
|
||||
* @author TheElk801, xenohedron
|
||||
*/
|
||||
public final class DreadhordeArcanist extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterInstantOrSorceryCard(
|
||||
"instant or sorcery card with mana value less than or equal to this creature's power"
|
||||
"instant or sorcery card with mana value less than or equal to {this}'s power from your graveyard"
|
||||
);
|
||||
|
||||
static {
|
||||
|
|
@ -50,11 +44,9 @@ public final class DreadhordeArcanist extends CardImpl {
|
|||
// Trample
|
||||
this.addAbility(TrampleAbility.getInstance());
|
||||
|
||||
// Whenever Dreadhorde Arcanist attacks, you may cast target instant or
|
||||
// sorcery card with converted mana cost less than or equal to Dreadhorde Arcanist's
|
||||
// power from your graveyard without paying its mana cost. If that card would be put
|
||||
// into your graveyard this turn, exile it instead.
|
||||
Ability ability = new AttacksTriggeredAbility(new DreadhordeArcanistEffect(), false);
|
||||
// Whenever Dreadhorde Arcanist attacks, you may cast target instant or sorcery card with converted mana cost less than or equal to Dreadhorde Arcanist's power from your graveyard without paying its mana cost.
|
||||
// If that card would be put into your graveyard this turn, exile it instead.
|
||||
Ability ability = new AttacksTriggeredAbility(new MayCastTargetThenExileEffect(true), false);
|
||||
ability.addTarget(new TargetCardInYourGraveyard(filter));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
|
@ -79,81 +71,3 @@ enum DreadhordeArcanistPredicate implements ObjectSourcePlayerPredicate<Card> {
|
|||
&& input.getObject().getManaValue() <= sourcePermanent.getPower().getValue();
|
||||
}
|
||||
}
|
||||
|
||||
class DreadhordeArcanistEffect extends OneShotEffect {
|
||||
|
||||
DreadhordeArcanistEffect() {
|
||||
super(Outcome.PlayForFree);
|
||||
this.staticText = "you may cast target instant or sorcery card with mana value "
|
||||
+ "less than or equal to {this}'s power from your graveyard without paying its mana cost. "
|
||||
+ "If that spell would be put into your graveyard this turn, exile it instead.";
|
||||
}
|
||||
|
||||
private DreadhordeArcanistEffect(final DreadhordeArcanistEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DreadhordeArcanistEffect copy() {
|
||||
return new DreadhordeArcanistEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null) {
|
||||
return false;
|
||||
}
|
||||
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
||||
if (card != null
|
||||
&& controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + '?', source, game)) {
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||
controller.cast(controller.chooseAbilityForCast(card, game, true),
|
||||
game, true, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
|
||||
}
|
||||
ContinuousEffect effect = new DreadhordeArcanistReplacementEffect(card.getId());
|
||||
effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId())));
|
||||
game.addEffect(effect, source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class DreadhordeArcanistReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID cardId;
|
||||
|
||||
DreadhordeArcanistReplacementEffect(UUID cardId) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.cardId = cardId;
|
||||
staticText = "If that card would be put into your graveyard this turn, exile it instead";
|
||||
}
|
||||
|
||||
private DreadhordeArcanistReplacementEffect(final DreadhordeArcanistReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DreadhordeArcanistReplacementEffect copy() {
|
||||
return new DreadhordeArcanistReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& zEvent.getTargetId().equals(this.cardId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,28 +1,21 @@
|
|||
package mage.cards.e;
|
||||
|
||||
import mage.ApprovingObject;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.ExileCardEnteringGraveyardReplacementEffect;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.keyword.DoubleStrikeAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author htrajan
|
||||
* @author xenohedron
|
||||
*/
|
||||
public final class EfreetFlamepainter extends CardImpl {
|
||||
|
||||
|
|
@ -38,8 +31,8 @@ public final class EfreetFlamepainter extends CardImpl {
|
|||
this.addAbility(DoubleStrikeAbility.getInstance());
|
||||
|
||||
// Whenever Efreet Flamepainter deals combat damage to a player, you may cast target instant or sorcery card from your graveyard without paying its mana cost. If that spell would be put into your graveyard, exile it instead.
|
||||
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new EfreetFlamepainterEffect(), false);
|
||||
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY));
|
||||
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new MayCastTargetThenExileEffect(true), false);
|
||||
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
||||
|
|
@ -52,37 +45,3 @@ public final class EfreetFlamepainter extends CardImpl {
|
|||
return new EfreetFlamepainter(this);
|
||||
}
|
||||
}
|
||||
|
||||
class EfreetFlamepainterEffect extends OneShotEffect {
|
||||
|
||||
EfreetFlamepainterEffect() {
|
||||
super(Outcome.PlayForFree);
|
||||
staticText = "you may cast target instant or sorcery card from your graveyard without paying its mana cost. If that spell would be put into your graveyard, exile it instead";
|
||||
}
|
||||
|
||||
EfreetFlamepainterEffect(EfreetFlamepainterEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
UUID targetId = source.getFirstTarget();
|
||||
if (targetId != null) {
|
||||
Card card = game.getCard(targetId);
|
||||
if (card != null && controller.chooseUse(outcome, "Cast " + card.getName() + " without paying its mana cost?", source, game)) {
|
||||
game.addEffect(new ExileCardEnteringGraveyardReplacementEffect(card.getId()), source);
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||
controller.cast(controller.chooseAbilityForCast(card, game, true),
|
||||
game, true, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EfreetFlamepainterEffect copy() {
|
||||
return new EfreetFlamepainterEffect(this);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,40 +1,28 @@
|
|||
package mage.cards.g;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ApprovingObject;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.keyword.MenaceAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterInstantOrSorceryCard;
|
||||
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
* @author xenohedron
|
||||
*/
|
||||
public final class GoblinDarkDwellers extends CardImpl {
|
||||
|
||||
private static final FilterInstantOrSorceryCard filter
|
||||
= new FilterInstantOrSorceryCard("instant or sorcery card with mana value 3 or less");
|
||||
= new FilterInstantOrSorceryCard("instant or sorcery card with mana value 3 or less from your graveyard");
|
||||
|
||||
static {
|
||||
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 4));
|
||||
|
|
@ -49,9 +37,9 @@ public final class GoblinDarkDwellers extends CardImpl {
|
|||
// Menace
|
||||
this.addAbility(new MenaceAbility(false));
|
||||
|
||||
// When Goblin Dark-Dwellers enters the battlefield, you may cast target instant or sorcery card with converted mana cost 3 or less
|
||||
// from your graveyard without paying its mana cost. If that card would be put into your graveyard this turn, exile it instead.
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new GoblinDarkDwellersEffect());
|
||||
// When Goblin Dark-Dwellers enters the battlefield, you may cast target instant or sorcery card with converted mana cost 3 or less from your graveyard without paying its mana cost.
|
||||
// If that card would be put into your graveyard this turn, exile it instead.
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new MayCastTargetThenExileEffect(true));
|
||||
ability.addTarget(new TargetCardInYourGraveyard(filter));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
|
@ -65,84 +53,3 @@ public final class GoblinDarkDwellers extends CardImpl {
|
|||
return new GoblinDarkDwellers(this);
|
||||
}
|
||||
}
|
||||
|
||||
class GoblinDarkDwellersEffect extends OneShotEffect {
|
||||
|
||||
GoblinDarkDwellersEffect() {
|
||||
super(Outcome.PlayForFree);
|
||||
this.staticText = "you may cast target instant or sorcery card with "
|
||||
+ "mana value 3 or less from your graveyard without paying its mana cost. "
|
||||
+ "If that spell would be put into your graveyard, exile it instead";
|
||||
}
|
||||
|
||||
GoblinDarkDwellersEffect(final GoblinDarkDwellersEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoblinDarkDwellersEffect copy() {
|
||||
return new GoblinDarkDwellersEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
||||
if (card != null) {
|
||||
if (controller.chooseUse(Outcome.PlayForFree, "Cast " + card.getLogName() + '?', source, game)) {
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||
boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
|
||||
game, true, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
|
||||
if (cardWasCast) {
|
||||
ContinuousEffect effect = new GoblinDarkDwellersReplacementEffect(card.getId());
|
||||
effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId())));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class GoblinDarkDwellersReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID cardId;
|
||||
|
||||
GoblinDarkDwellersReplacementEffect(UUID cardId) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.cardId = cardId;
|
||||
staticText = "If that card would be put into your graveyard this turn, exile it instead";
|
||||
}
|
||||
|
||||
GoblinDarkDwellersReplacementEffect(final GoblinDarkDwellersReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public GoblinDarkDwellersReplacementEffect copy() {
|
||||
return new GoblinDarkDwellersReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& zEvent.getTargetId().equals(this.cardId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,27 @@
|
|||
package mage.cards.h;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.costs.mana.ManaCosts;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.cards.CardsImpl;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterInstantOrSorceryCard;
|
||||
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInGraveyard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -64,8 +61,8 @@ class HaloForagerPayEffect extends OneShotEffect {
|
|||
HaloForagerPayEffect() {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "you may pay {X}. When you do, you may cast target instant or sorcery card " +
|
||||
"with mana value X from a graveyard without paying its mana cost. " +
|
||||
"If that spell would be put into a graveyard, exile it instead.";
|
||||
"with mana value X from a graveyard without paying its mana cost. "
|
||||
+ ThatSpellGraveyardExileReplacementEffect.RULE_A;
|
||||
}
|
||||
|
||||
private HaloForagerPayEffect(final HaloForagerPayEffect effect) {
|
||||
|
|
@ -105,7 +102,7 @@ class HaloForagerCastEffect extends OneShotEffect {
|
|||
HaloForagerCastEffect(int costX) {
|
||||
super(Outcome.Benefit);
|
||||
staticText = "You may cast target instant or sorcery card with mana value " + costX + " from a graveyard " +
|
||||
"without paying its mana cost. If that spell would be put into a graveyard, exile it instead";
|
||||
"without paying its mana cost. " + ThatSpellGraveyardExileReplacementEffect.RULE_A;
|
||||
}
|
||||
|
||||
private HaloForagerCastEffect(final HaloForagerCastEffect effect) {
|
||||
|
|
@ -121,65 +118,12 @@ class HaloForagerCastEffect extends OneShotEffect {
|
|||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
return player != null && card != null
|
||||
&& CardUtil.castSpellWithAttributesForFree(
|
||||
player, source, game, new CardsImpl(card),
|
||||
StaticFilters.FILTER_CARD, HaloForagerTracker.instance
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
enum HaloForagerTracker implements CardUtil.SpellCastTracker {
|
||||
instance;
|
||||
|
||||
@Override
|
||||
public boolean checkCard(Card card, Game game) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCard(Card card, Ability source, Game game) {
|
||||
game.addEffect(new HaloForagerReplacementEffect(card, game), source);
|
||||
}
|
||||
}
|
||||
|
||||
class HaloForagerReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final MageObjectReference mor;
|
||||
|
||||
HaloForagerReplacementEffect(Card card, Game game) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.mor = new MageObjectReference(card.getMainCard(), game);
|
||||
}
|
||||
|
||||
private HaloForagerReplacementEffect(final HaloForagerReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.mor = effect.mor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HaloForagerReplacementEffect copy() {
|
||||
return new HaloForagerReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Card card = mor.getCard(game);
|
||||
return controller != null
|
||||
&& card != null
|
||||
&& controller.moveCards(card, Zone.EXILED, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& zEvent.getTargetId().equals(mor.getSourceId());
|
||||
if (player == null || card == null) {
|
||||
return false;
|
||||
}
|
||||
ContinuousEffect effect = new ThatSpellGraveyardExileReplacementEffect(false);
|
||||
effect.setTargetPointer(new FixedTarget(card, game));
|
||||
game.addEffect(effect, source);
|
||||
return CardUtil.castSpellWithAttributesForFree(player, source, game, card);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import mage.abilities.Ability;
|
|||
import mage.abilities.LoyaltyAbility;
|
||||
import mage.abilities.effects.*;
|
||||
import mage.abilities.effects.common.GetEmblemEffect;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
|
@ -12,7 +13,7 @@ import mage.constants.CardType;
|
|||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.common.FilterInstantOrSorceryCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.command.emblems.JaceTelepathUnboundEmblem;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
|
@ -41,10 +42,8 @@ public final class JaceTelepathUnbound extends CardImpl {
|
|||
this.addAbility(ability);
|
||||
|
||||
// -3: You may cast target instant or sorcery card from your graveyard this turn. If that card would be put into your graveyard this turn, exile it instead.
|
||||
CastCardFromGraveyardThenExileItEffect minusEffect = new CastCardFromGraveyardThenExileItEffect();
|
||||
minusEffect.setText("You may cast target instant or sorcery card from your graveyard this turn. If that spell would be put into your graveyard, exile it instead");
|
||||
ability = new LoyaltyAbility(minusEffect, -3);
|
||||
ability.addTarget(new TargetCardInYourGraveyard(new FilterInstantOrSorceryCard()));
|
||||
ability = new LoyaltyAbility(new MayCastTargetThenExileEffect(Duration.EndOfTurn), -3);
|
||||
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD));
|
||||
this.addAbility(ability);
|
||||
|
||||
// −9: You get an emblem with "Whenever you cast a spell, target opponent mills five cards."
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ 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.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.Card;
|
||||
|
|
@ -61,10 +61,10 @@ public final class MavindaStudentsAdvocate extends CardImpl {
|
|||
}
|
||||
}
|
||||
|
||||
class MavindaStudentsAdvocateEffect extends CastCardFromGraveyardThenExileItEffect {
|
||||
class MavindaStudentsAdvocateEffect extends MayCastTargetThenExileEffect {
|
||||
|
||||
MavindaStudentsAdvocateEffect() {
|
||||
super();
|
||||
super(Duration.EndOfTurn);
|
||||
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";
|
||||
|
|
|
|||
|
|
@ -1,30 +1,26 @@
|
|||
package mage.cards.m;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.common.FilterInstantOrSorceryCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author TheElk801
|
||||
* @author TheElk801, xenohedron
|
||||
*/
|
||||
public final class MissionBriefing extends CardImpl {
|
||||
|
||||
|
|
@ -47,15 +43,14 @@ public final class MissionBriefing extends CardImpl {
|
|||
|
||||
class MissionBriefingEffect extends OneShotEffect {
|
||||
|
||||
public MissionBriefingEffect() {
|
||||
MissionBriefingEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "Surveil 2, then choose an instant or sorcery card "
|
||||
+ "in your graveyard. You may cast that card this turn. "
|
||||
+ "If that card would be put into your graveyard this turn, "
|
||||
+ "exile it instead";
|
||||
+ "in your graveyard. You may cast it this turn. "
|
||||
+ ThatSpellGraveyardExileReplacementEffect.RULE_YOUR;
|
||||
}
|
||||
|
||||
public MissionBriefingEffect(final MissionBriefingEffect effect) {
|
||||
private MissionBriefingEffect(final MissionBriefingEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
|
|
@ -71,65 +66,11 @@ class MissionBriefingEffect extends OneShotEffect {
|
|||
return false;
|
||||
}
|
||||
player.surveil(2, source, game);
|
||||
Target target = new TargetCardInYourGraveyard(
|
||||
new FilterInstantOrSorceryCard("instant or sorcery card from your graveyard"));
|
||||
if (!player.choose(outcome, target, source, game)) {
|
||||
return true;
|
||||
}
|
||||
Card card = game.getCard(target.getFirstTarget());
|
||||
if (card != null) {
|
||||
ContinuousEffect effect = new PlayFromNotOwnHandZoneTargetEffect();
|
||||
effect.setTargetPointer(new FixedTarget(card, game));
|
||||
game.addEffect(effect, source);
|
||||
effect = new MissionBriefingReplacementEffect(card.getId());
|
||||
game.addEffect(effect, source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class MissionBriefingReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID cardId;
|
||||
|
||||
public MissionBriefingReplacementEffect(UUID cardId) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.cardId = cardId;
|
||||
staticText = "If that card would be put into your graveyard this turn, "
|
||||
+ "exile it instead";
|
||||
}
|
||||
|
||||
public MissionBriefingReplacementEffect(final MissionBriefingReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MissionBriefingReplacementEffect copy() {
|
||||
return new MissionBriefingReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
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) {
|
||||
controller.moveCardsToExile(card, source, game, true, null, "");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& zEvent.getTargetId().equals(this.cardId);
|
||||
Target target = new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD);
|
||||
player.choose(outcome, target, source, game);
|
||||
Effect effect = new MayCastTargetThenExileEffect(Duration.EndOfTurn);
|
||||
effect.setTargetPointer(new FixedTarget(target.getFirstTarget(), game));
|
||||
effect.apply(game, source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,8 @@ import mage.abilities.common.delayed.ReflexiveTriggeredAbility;
|
|||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||
import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect;
|
||||
import mage.abilities.keyword.FirstStrikeAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
|
|
@ -18,8 +18,6 @@ import mage.constants.*;
|
|||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterInstantOrSorceryCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
|
@ -64,9 +62,10 @@ class OgreBattlecasterEffect extends OneShotEffect {
|
|||
|
||||
OgreBattlecasterEffect() {
|
||||
super(Outcome.PlayForFree);
|
||||
this.staticText = "you may cast target instant or sorcery card from your graveyard " +
|
||||
"by paying {R}{R} in addition to its other costs. If that spell would be put into a graveyard, exile it instead. " +
|
||||
"When you cast that spell, {this} gets +X/+0 until end of turn, where X is that spell's mana value";
|
||||
this.staticText = "you may cast target instant or sorcery card from your graveyard "
|
||||
+ "by paying {R}{R} in addition to its other costs. "
|
||||
+ ThatSpellGraveyardExileReplacementEffect.RULE_A
|
||||
+ " When you cast that spell, {this} gets +X/+0 until end of turn, where X is that spell's mana value";
|
||||
}
|
||||
|
||||
private OgreBattlecasterEffect(final OgreBattlecasterEffect effect) {
|
||||
|
|
@ -81,7 +80,7 @@ class OgreBattlecasterEffect extends OneShotEffect {
|
|||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
if (controller == null || card == null) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -98,49 +97,10 @@ class OgreBattlecasterEffect extends OneShotEffect {
|
|||
game.fireReflexiveTriggeredAbility(new ReflexiveTriggeredAbility(effect, false,
|
||||
"When you cast that spell, {this} gets +X/+0 until end of turn, where X is that spell's mana value"), source);
|
||||
}
|
||||
ContinuousEffect effect = new ThatSpellGraveyardExileReplacementEffect(false);
|
||||
effect.setTargetPointer(new FixedTarget(card, game));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
ContinuousEffect effect = new OgreBattlecasterReplacementEffect(card.getId());
|
||||
effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId())));
|
||||
game.addEffect(effect, source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class OgreBattlecasterReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID cardId;
|
||||
|
||||
OgreBattlecasterReplacementEffect(UUID cardId) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.cardId = cardId;
|
||||
staticText = "if that spell would be put into a graveyard, exile it instead";
|
||||
}
|
||||
|
||||
private OgreBattlecasterReplacementEffect(final OgreBattlecasterReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OgreBattlecasterReplacementEffect copy() {
|
||||
return new OgreBattlecasterReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& zEvent.getTargetId().equals(this.cardId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
|
||||
package mage.cards.s;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.ExileSourceEffect;
|
||||
import mage.abilities.effects.common.ExileSpellEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
|
@ -39,7 +38,7 @@ public final class ShredsOfSanity extends CardImpl {
|
|||
this.getSpellAbility().addEffect(new ShredsOfSanityEffect());
|
||||
this.getSpellAbility().addTarget(new TargetCard(0, 1, Zone.GRAVEYARD, filterInstant));
|
||||
this.getSpellAbility().addTarget(new TargetCard(0, 1, Zone.GRAVEYARD, filterSorcery));
|
||||
this.getSpellAbility().addEffect(new ExileSourceEffect());
|
||||
this.getSpellAbility().addEffect(new ExileSpellEffect());
|
||||
}
|
||||
|
||||
private ShredsOfSanity(final ShredsOfSanity card) {
|
||||
|
|
|
|||
|
|
@ -1,25 +1,18 @@
|
|||
|
||||
package mage.cards.s;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.ExileCardEnteringGraveyardReplacementEffect;
|
||||
import mage.abilities.effects.common.ExileSourceEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.abilities.effects.common.ExileSpellEffect;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.common.FilterInstantOrSorceryCard;
|
||||
import mage.game.Game;
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneTargetEffect;
|
||||
|
||||
/**
|
||||
* @author emerald000
|
||||
* @author xenohedron
|
||||
*/
|
||||
public final class SinsOfThePast extends CardImpl {
|
||||
|
||||
|
|
@ -27,9 +20,11 @@ public final class SinsOfThePast extends CardImpl {
|
|||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{4}{B}{B}");
|
||||
|
||||
// Until end of turn, you may cast target instant or sorcery card from your graveyard without paying its mana cost. If that card would be put into your graveyard this turn, exile it instead. Exile Sins of the Past.
|
||||
this.getSpellAbility().addEffect(new SinsOfThePastEffect());
|
||||
this.getSpellAbility().addEffect(new ExileSourceEffect());
|
||||
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(new FilterInstantOrSorceryCard()));
|
||||
this.getSpellAbility().addEffect(new MayCastTargetThenExileEffect(true)
|
||||
.setText("Until end of turn, you may cast target instant or sorcery card from your graveyard without paying its mana cost. "
|
||||
+ ThatSpellGraveyardExileReplacementEffect.RULE_YOUR));
|
||||
this.getSpellAbility().addEffect(new ExileSpellEffect());
|
||||
this.getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD));
|
||||
}
|
||||
|
||||
private SinsOfThePast(final SinsOfThePast card) {
|
||||
|
|
@ -41,34 +36,3 @@ public final class SinsOfThePast extends CardImpl {
|
|||
return new SinsOfThePast(this);
|
||||
}
|
||||
}
|
||||
|
||||
class SinsOfThePastEffect extends OneShotEffect {
|
||||
|
||||
SinsOfThePastEffect() {
|
||||
super(Outcome.PlayForFree);
|
||||
this.staticText = "Until end of turn, you may cast target instant or sorcery card from your graveyard without paying its mana cost. If that spell would be put into your graveyard, exile it instead";
|
||||
}
|
||||
|
||||
SinsOfThePastEffect(final SinsOfThePastEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SinsOfThePastEffect copy() {
|
||||
return new SinsOfThePastEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
||||
if (card != null) {
|
||||
ContinuousEffect effect = new PlayFromNotOwnHandZoneTargetEffect(Zone.GRAVEYARD, TargetController.YOU, Duration.EndOfTurn, true);
|
||||
effect.setTargetPointer(new FixedTarget(card, game));
|
||||
game.addEffect(effect, source);
|
||||
effect = new ExileCardEnteringGraveyardReplacementEffect(card.getId());
|
||||
game.addEffect(effect, source);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,29 +1,21 @@
|
|||
package mage.cards.t;
|
||||
|
||||
import mage.ApprovingObject;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.keyword.FlashAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author fireshoes
|
||||
* @author xenohedron
|
||||
*/
|
||||
public final class TorrentialGearhulk extends CardImpl {
|
||||
|
||||
|
|
@ -45,7 +37,7 @@ public final class TorrentialGearhulk extends CardImpl {
|
|||
// When Torrential Gearhulk enters the battlefield, you may cast target
|
||||
// instant card from your graveyard without paying its mana cost.
|
||||
// If that card would be put into your graveyard this turn, exile it instead.
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new TorrentialGearhulkEffect());
|
||||
Ability ability = new EntersBattlefieldTriggeredAbility(new MayCastTargetThenExileEffect(true));
|
||||
ability.addTarget(new TargetCardInYourGraveyard(filter));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
|
@ -59,81 +51,3 @@ public final class TorrentialGearhulk extends CardImpl {
|
|||
return new TorrentialGearhulk(this);
|
||||
}
|
||||
}
|
||||
|
||||
class TorrentialGearhulkEffect extends OneShotEffect {
|
||||
|
||||
TorrentialGearhulkEffect() {
|
||||
super(Outcome.PlayForFree);
|
||||
this.staticText = "you may cast target instant card from your graveyard without paying its mana cost. "
|
||||
+ "If that spell would be put into your graveyard, exile it instead";
|
||||
}
|
||||
|
||||
TorrentialGearhulkEffect(final TorrentialGearhulkEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TorrentialGearhulkEffect copy() {
|
||||
return new TorrentialGearhulkEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
||||
if (controller != null && card != null) {
|
||||
if (controller.chooseUse(outcome, "Cast " + card.getLogName() + '?', source, game)) {
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||
boolean cardWasCast = controller.cast(controller.chooseAbilityForCast(card, game, true),
|
||||
game, true, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
|
||||
if (cardWasCast) {
|
||||
ContinuousEffect effect = new TorrentialGearhulkReplacementEffect(card.getId());
|
||||
effect.setTargetPointer(new FixedTarget(card.getId(), game.getState().getZoneChangeCounter(card.getId())));
|
||||
game.addEffect(effect, source);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class TorrentialGearhulkReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID cardId;
|
||||
|
||||
TorrentialGearhulkReplacementEffect(UUID cardId) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.cardId = cardId;
|
||||
staticText = "If that card would be put into your graveyard this turn, exile it instead";
|
||||
}
|
||||
|
||||
TorrentialGearhulkReplacementEffect(final TorrentialGearhulkReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TorrentialGearhulkReplacementEffect copy() {
|
||||
return new TorrentialGearhulkReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& zEvent.getTargetId().equals(this.cardId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,30 @@
|
|||
package mage.cards.t;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ApprovingObject;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.DiesCreatureTriggeredAbility;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect;
|
||||
import mage.abilities.keyword.BushidoAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
* @author xenohedron
|
||||
*/
|
||||
public final class ToshiroUmezawa extends CardImpl {
|
||||
private static final FilterCard filterInstant = new FilterCard("instant card from your graveyard");
|
||||
private static final FilterCard filter = new FilterCard("instant card from your graveyard");
|
||||
|
||||
static {
|
||||
filterInstant.add(CardType.INSTANT.getPredicate());
|
||||
filter.add(CardType.INSTANT.getPredicate());
|
||||
}
|
||||
|
||||
public ToshiroUmezawa(UUID ownerId, CardSetInfo setInfo) {
|
||||
|
|
@ -44,11 +38,12 @@ public final class ToshiroUmezawa extends CardImpl {
|
|||
|
||||
// Bushido 1
|
||||
this.addAbility(new BushidoAbility(1));
|
||||
// Whenever a creature an opponent controls dies, you may cast target
|
||||
// instant card from your graveyard. If that card would be put into a
|
||||
// graveyard this turn, exile it instead.
|
||||
Ability ability = new DiesCreatureTriggeredAbility(new ToshiroUmezawaEffect(), true, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE);
|
||||
ability.addTarget(new TargetCardInYourGraveyard(1, 1, filterInstant));
|
||||
// Whenever a creature an opponent controls dies, you may cast target instant card from your graveyard. If that card would be put into a graveyard this turn, exile it instead.
|
||||
Ability ability = new DiesCreatureTriggeredAbility(new MayCastTargetThenExileEffect(false)
|
||||
.setText("you may cast target instant card from your graveyard. "
|
||||
+ ThatSpellGraveyardExileReplacementEffect.RULE_A),
|
||||
true, StaticFilters.FILTER_OPPONENTS_PERMANENT_A_CREATURE);
|
||||
ability.addTarget(new TargetCardInYourGraveyard(filter));
|
||||
this.addAbility(ability);
|
||||
|
||||
}
|
||||
|
|
@ -62,86 +57,3 @@ public final class ToshiroUmezawa extends CardImpl {
|
|||
return new ToshiroUmezawa(this);
|
||||
}
|
||||
}
|
||||
|
||||
class ToshiroUmezawaEffect extends OneShotEffect {
|
||||
|
||||
public ToshiroUmezawaEffect() {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = "you may cast target instant card from your graveyard. "
|
||||
+ "If that spell would be put into a graveyard, exile it instead";
|
||||
}
|
||||
|
||||
public ToshiroUmezawaEffect(final ToshiroUmezawaEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToshiroUmezawaEffect copy() {
|
||||
return new ToshiroUmezawaEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller != null) {
|
||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
if (card != null
|
||||
&& controller.getGraveyard().contains(card.getId())) { // must be in graveyard
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||
controller.cast(controller.chooseAbilityForCast(card, game, false),
|
||||
game, false, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
|
||||
game.addEffect(new ToshiroUmezawaReplacementEffect(card.getId()), source);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class ToshiroUmezawaReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID cardId;
|
||||
|
||||
public ToshiroUmezawaReplacementEffect(UUID cardId) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.cardId = cardId;
|
||||
}
|
||||
|
||||
public ToshiroUmezawaReplacementEffect(final ToshiroUmezawaReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToshiroUmezawaReplacementEffect copy() {
|
||||
return new ToshiroUmezawaReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
UUID eventObject = event.getTargetId();
|
||||
StackObject stackObject = game.getStack().getStackObject(eventObject);
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (stackObject != null && controller != null) {
|
||||
if (stackObject instanceof Spell) {
|
||||
game.rememberLKI(stackObject.getId(), Zone.STACK, stackObject);
|
||||
}
|
||||
if (stackObject instanceof Card && eventObject.equals(cardId)) {
|
||||
return controller.moveCards((Card) stackObject, Zone.EXILED, source, game);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& event.getTargetId().equals(cardId);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,15 +8,12 @@ import mage.abilities.common.SimpleActivatedAbility;
|
|||
import mage.abilities.costs.common.SacrificeSourceCost;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.GenericManaCost;
|
||||
import mage.abilities.effects.CastCardFromGraveyardThenExileItEffect;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.*;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
|
@ -42,9 +39,8 @@ public final class VoharVodalianDesecrator extends CardImpl {
|
|||
this.addAbility(new SimpleActivatedAbility(new VoharVodalianDesecratorEffect(), new TapSourceCost()));
|
||||
|
||||
// {2}, Sacrifice Vohar, Vodalian Desecrator: You may cast target instant or sorcery card from your graveyard this turn. If that spell would be put into your graveyard, exile it instead. Activate only as a sorcery.
|
||||
Ability ability = new ActivateAsSorceryActivatedAbility(new CastCardFromGraveyardThenExileItEffect()
|
||||
.setText("You may cast target instant or sorcery card from your graveyard this turn. If that spell would be put into your graveyard, exile it instead."),
|
||||
new GenericManaCost(2)
|
||||
Ability ability = new ActivateAsSorceryActivatedAbility(
|
||||
new MayCastTargetThenExileEffect(Duration.EndOfTurn), new GenericManaCost(2)
|
||||
);
|
||||
ability.addCost(new SacrificeSourceCost());
|
||||
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD));
|
||||
|
|
|
|||
|
|
@ -1,15 +1,11 @@
|
|||
package mage.cards.w;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ApprovingObject;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.TriggeredAbilityImpl;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.MayCastTargetThenExileEffect;
|
||||
import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect;
|
||||
import mage.abilities.keyword.IslandwalkAbility;
|
||||
import mage.abilities.keyword.SwampwalkAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
|
|
@ -19,15 +15,14 @@ import mage.filter.predicate.card.OwnerIdPredicate;
|
|||
import mage.game.Game;
|
||||
import mage.game.events.DamagedPlayerEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.stack.StackObject;
|
||||
import mage.players.Player;
|
||||
import mage.target.Target;
|
||||
import mage.target.common.TargetCardInGraveyard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jeffwadsworth
|
||||
* @author jeffwadsworth, xenohedron
|
||||
*/
|
||||
public final class WrexialTheRisenDeep extends CardImpl {
|
||||
|
||||
|
|
@ -44,10 +39,8 @@ public final class WrexialTheRisenDeep extends CardImpl {
|
|||
// Swampwalk
|
||||
this.addAbility(new SwampwalkAbility());
|
||||
|
||||
// Whenever Wrexial, the Risen Deep deals combat damage to a player,
|
||||
// you may cast target instant or sorcery card from that player's graveyard
|
||||
// without paying its mana cost. If that card would be put into a graveyard
|
||||
// this turn, exile it instead.
|
||||
// Whenever Wrexial, the Risen Deep deals combat damage to a player, you may cast target instant or sorcery card from that player's graveyard without paying its mana cost.
|
||||
// If that card would be put into a graveyard this turn, exile it instead.
|
||||
this.addAbility(new WrexialTheRisenDeepTriggeredAbility());
|
||||
}
|
||||
|
||||
|
|
@ -63,11 +56,15 @@ public final class WrexialTheRisenDeep extends CardImpl {
|
|||
|
||||
class WrexialTheRisenDeepTriggeredAbility extends TriggeredAbilityImpl {
|
||||
|
||||
public WrexialTheRisenDeepTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new WrexialTheRisenDeepEffect(), true);
|
||||
WrexialTheRisenDeepTriggeredAbility() {
|
||||
super(Zone.BATTLEFIELD, new MayCastTargetThenExileEffect(true)
|
||||
.setText("you may cast target instant or sorcery card from "
|
||||
+ "that player's graveyard without paying its mana cost. "
|
||||
+ ThatSpellGraveyardExileReplacementEffect.RULE_A), false);
|
||||
setTriggerPhrase("Whenever {this} deals combat damage to a player, ");
|
||||
}
|
||||
|
||||
public WrexialTheRisenDeepTriggeredAbility(final WrexialTheRisenDeepTriggeredAbility ability) {
|
||||
private WrexialTheRisenDeepTriggeredAbility(final WrexialTheRisenDeepTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
|
|
@ -90,105 +87,15 @@ class WrexialTheRisenDeepTriggeredAbility extends TriggeredAbilityImpl {
|
|||
if (damagedPlayer == null) {
|
||||
return false;
|
||||
}
|
||||
FilterCard filter = new FilterCard("target instant or sorcery card from "
|
||||
+ damagedPlayer.getName() + "'s graveyard");
|
||||
FilterCard filter = new FilterCard("instant or sorcery card from that player's graveyard");
|
||||
filter.add(new OwnerIdPredicate(damagedPlayer.getId()));
|
||||
filter.add(Predicates.or(
|
||||
CardType.INSTANT.getPredicate(),
|
||||
CardType.SORCERY.getPredicate()));
|
||||
|
||||
CardType.SORCERY.getPredicate()
|
||||
));
|
||||
Target target = new TargetCardInGraveyard(filter);
|
||||
this.getTargets().clear();
|
||||
this.addTarget(target);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRule() {
|
||||
return "Whenever {this} deals combat damage to a player, "
|
||||
+ "you may cast target instant or sorcery card "
|
||||
+ "from that player's graveyard without paying its mana cost. "
|
||||
+ "If that spell would be put into a graveyard, exile it instead.";
|
||||
}
|
||||
}
|
||||
|
||||
class WrexialTheRisenDeepEffect extends OneShotEffect {
|
||||
|
||||
public WrexialTheRisenDeepEffect() {
|
||||
super(Outcome.PlayForFree);
|
||||
staticText = "you may cast target instant or sorcery card from "
|
||||
+ "that player's graveyard without paying its mana cost. "
|
||||
+ "If that spell would be put into a graveyard this turn, exile it instead";
|
||||
}
|
||||
|
||||
public WrexialTheRisenDeepEffect(final WrexialTheRisenDeepEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrexialTheRisenDeepEffect copy() {
|
||||
return new WrexialTheRisenDeepEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Card card = game.getCard(source.getFirstTarget());
|
||||
if (controller == null
|
||||
|| card == null) {
|
||||
return false;
|
||||
}
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||
controller.cast(controller.chooseAbilityForCast(card, game, true),
|
||||
game, true, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
|
||||
game.addEffect(new WrexialReplacementEffect(card.getId()), source);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class WrexialReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID cardid;
|
||||
|
||||
public WrexialReplacementEffect(UUID cardid) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.cardid = cardid;
|
||||
}
|
||||
|
||||
public WrexialReplacementEffect(final WrexialReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.cardid = effect.cardid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WrexialReplacementEffect copy() {
|
||||
return new WrexialReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& event.getTargetId().equals(cardid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
UUID eventObject = event.getTargetId();
|
||||
StackObject card = game.getStack().getStackObject(eventObject);
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (card != null && controller != null) {
|
||||
if (card instanceof Card) {
|
||||
return controller.moveCards((Card) card, Zone.EXILED, source, game);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,136 @@
|
|||
package org.mage.test.cards.replacement;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public class MayCastTargetThenExileTest extends CardTestPlayerBase {
|
||||
|
||||
private static final String spike = "Lava Spike"; // Sorcery {R}; deals 3 damage to target player or planeswalker
|
||||
|
||||
@Test
|
||||
public void testWrexial() {
|
||||
String wrexial = "Wrexial, the Risen Deep"; // 5/8
|
||||
/* Whenever Wrexial, the Risen Deep deals combat damage to a player,
|
||||
* you may cast target instant or sorcery card from that player’s graveyard without paying its mana cost.
|
||||
* If that spell would be put into a graveyard, exile it instead.
|
||||
*/
|
||||
addCard(Zone.BATTLEFIELD, playerA, wrexial);
|
||||
addCard(Zone.GRAVEYARD, playerB, spike);
|
||||
|
||||
attack(1, playerA, wrexial, playerB);
|
||||
setChoice(playerA, true);
|
||||
addTarget(playerA, spike);
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 20 - 5 - 3);
|
||||
assertExileCount(spike, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForager() {
|
||||
String forager = "Halo Forager"; // 3/1
|
||||
/*
|
||||
* When Halo Forager enters the battlefield, you may pay {X}.
|
||||
* When you do, you may cast target instant or sorcery card with mana value X from a graveyard without paying its mana cost.
|
||||
* If that spell would be put into a graveyard, exile it instead.
|
||||
*/
|
||||
addCard(Zone.HAND, playerA, forager);
|
||||
addCard(Zone.GRAVEYARD, playerB, spike);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 4);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, forager);
|
||||
setChoice(playerA, true);
|
||||
setChoice(playerA, "X=1");
|
||||
addTarget(playerA, spike);
|
||||
setChoice(playerA, true);
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 20 - 3);
|
||||
assertExileCount(spike, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVohar() {
|
||||
String vohar = "Vohar, Vodalian Desecrator"; // 1/2
|
||||
/*
|
||||
* {2}, Sacrifice Vohar, Vodalian Desecrator: You may cast target instant or sorcery card from your graveyard this turn.
|
||||
* If that spell would be put into your graveyard, exile it instead. Activate only as a sorcery.
|
||||
*/
|
||||
addCard(Zone.BATTLEFIELD, playerA, vohar);
|
||||
addCard(Zone.GRAVEYARD, playerA, spike);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}, Sacrifice");
|
||||
addTarget(playerA, spike);
|
||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, spike, playerB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 20 - 3);
|
||||
assertExileCount(spike, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDreadhordeArcanist() {
|
||||
String arcanist = "Dreadhorde Arcanist"; // 1/3
|
||||
/*
|
||||
* Whenever Dreadhorde Arcanist attacks, you may cast target instant or sorcery card with mana value
|
||||
* less than or equal to Dreadhorde Arcanist’s power from your graveyard without paying its mana cost.
|
||||
* If that spell would be put into your graveyard, exile it instead.
|
||||
*/
|
||||
addCard(Zone.BATTLEFIELD, playerA, arcanist);
|
||||
addCard(Zone.GRAVEYARD, playerA, spike);
|
||||
|
||||
attack(1, playerA, arcanist, playerB);
|
||||
setChoice(playerA, true);
|
||||
addTarget(playerA, spike);
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 20 - 1 - 3);
|
||||
assertExileCount(spike, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChandra() {
|
||||
String chandra = "Chandra, Acolyte of Flame"; // 4 loyalty
|
||||
/*
|
||||
* −2: You may cast target instant or sorcery card with mana value 3 or less from your graveyard.
|
||||
* If that spell would be put into your graveyard, exile it instead.
|
||||
*/
|
||||
addCard(Zone.BATTLEFIELD, playerA, chandra);
|
||||
addCard(Zone.GRAVEYARD, playerA, spike);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
||||
|
||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-2: You may cast");
|
||||
addTarget(playerA, spike);
|
||||
setChoice(playerA, true);
|
||||
addTarget(playerA, playerB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.END_TURN);
|
||||
execute();
|
||||
|
||||
assertLife(playerB, 20 - 3);
|
||||
assertExileCount(spike, 1);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
package mage.abilities.effects;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.AsThoughEffectType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class CastCardFromGraveyardThenExileItEffect extends OneShotEffect {
|
||||
|
||||
public CastCardFromGraveyardThenExileItEffect() {
|
||||
super(Outcome.Benefit);
|
||||
}
|
||||
|
||||
protected CastCardFromGraveyardThenExileItEffect(final CastCardFromGraveyardThenExileItEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastCardFromGraveyardThenExileItEffect copy() {
|
||||
return new CastCardFromGraveyardThenExileItEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(this.getTargetPointer().getFirst(game, source));
|
||||
if (card == null) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
class CastCardFromGraveyardEffect extends AsThoughEffectImpl {
|
||||
|
||||
CastCardFromGraveyardEffect() {
|
||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit);
|
||||
this.staticText = "You may cast target card from your graveyard";
|
||||
}
|
||||
|
||||
private CastCardFromGraveyardEffect(final CastCardFromGraveyardEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastCardFromGraveyardEffect copy() {
|
||||
return new CastCardFromGraveyardEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
return objectId.equals(this.getTargetPointer().getFirst(game, source))
|
||||
&& affectedControllerId.equals(source.getControllerId());
|
||||
}
|
||||
}
|
||||
|
||||
class ExileReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID cardId;
|
||||
|
||||
ExileReplacementEffect(UUID cardId) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.cardId = cardId;
|
||||
this.staticText = "If that card would be put into your graveyard this turn, exile it instead";
|
||||
}
|
||||
|
||||
private ExileReplacementEffect(final ExileReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExileReplacementEffect copy() {
|
||||
return new ExileReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Card card = game.getCard(this.cardId);
|
||||
return controller != null
|
||||
&& card != null
|
||||
&& controller.moveCards(card, Zone.EXILED, source, game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& zEvent.getTargetId().equals(this.cardId);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ExileCardEnteringGraveyardReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final UUID cardId;
|
||||
|
||||
public ExileCardEnteringGraveyardReplacementEffect(UUID cardId) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
this.cardId = cardId;
|
||||
}
|
||||
|
||||
ExileCardEnteringGraveyardReplacementEffect(final ExileCardEnteringGraveyardReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.cardId = effect.cardId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExileCardEnteringGraveyardReplacementEffect copy() {
|
||||
return new ExileCardEnteringGraveyardReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& zEvent.getTargetId().equals(this.cardId);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,98 @@
|
|||
package mage.abilities.effects.common;
|
||||
|
||||
import mage.ApprovingObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.Mode;
|
||||
import mage.abilities.effects.ContinuousEffect;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.replacement.ThatSpellGraveyardExileReplacementEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public class MayCastTargetThenExileEffect extends OneShotEffect {
|
||||
|
||||
private final Duration duration;
|
||||
private final boolean noMana;
|
||||
|
||||
/**
|
||||
* Allows to cast the target card immediately, either for its cost or for free.
|
||||
* If resulting spell would be put into graveyard, exiles it instead.
|
||||
*/
|
||||
public MayCastTargetThenExileEffect(boolean noMana) {
|
||||
super(Outcome.Benefit);
|
||||
this.duration = Duration.OneUse;
|
||||
this.noMana = noMana;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the target card playable for the specified duration as long as it remains in that zone.
|
||||
* If resulting spell would be put into graveyard, exiles it instead.
|
||||
*/
|
||||
public MayCastTargetThenExileEffect(Duration duration) {
|
||||
super(Outcome.Benefit);
|
||||
this.duration = duration;
|
||||
this.noMana = false;
|
||||
}
|
||||
|
||||
protected MayCastTargetThenExileEffect(final MayCastTargetThenExileEffect effect) {
|
||||
super(effect);
|
||||
this.duration = effect.duration;
|
||||
this.noMana = effect.noMana;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MayCastTargetThenExileEffect copy() {
|
||||
return new MayCastTargetThenExileEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Card card = game.getCard(getTargetPointer().getFirst(game, source));
|
||||
if (card == null) {
|
||||
return false;
|
||||
}
|
||||
FixedTarget fixedTarget = new FixedTarget(card, game);
|
||||
if (duration == Duration.OneUse) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null || !controller.chooseUse(outcome, "Cast " + card.getLogName() + '?', source, game)) {
|
||||
return false;
|
||||
}
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), Boolean.TRUE);
|
||||
controller.cast(controller.chooseAbilityForCast(card, game, noMana),
|
||||
game, noMana, new ApprovingObject(source, game));
|
||||
game.getState().setValue("PlayFromNotOwnHandZone" + card.getId(), null);
|
||||
} else {
|
||||
CardUtil.makeCardPlayable(game, source, card, duration, false);
|
||||
}
|
||||
ContinuousEffect effect = new ThatSpellGraveyardExileReplacementEffect(true);
|
||||
effect.setTargetPointer(fixedTarget);
|
||||
game.addEffect(effect, source);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText(Mode mode) {
|
||||
if (staticText != null && !staticText.isEmpty()) {
|
||||
return staticText;
|
||||
}
|
||||
String text = "you may cast " + getTargetPointer().describeTargets(mode.getTargets(), "it");
|
||||
if (duration == Duration.EndOfTurn) {
|
||||
text += " this turn";
|
||||
} else if (!duration.toString().isEmpty()) {
|
||||
text += duration.toString();
|
||||
}
|
||||
if (noMana) {
|
||||
text += " without paying its mana cost";
|
||||
}
|
||||
return text + ". " + ThatSpellGraveyardExileReplacementEffect.RULE_YOUR;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package mage.abilities.effects.common.replacement;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.target.targetpointer.FixedTarget;
|
||||
|
||||
/**
|
||||
* @author xenohedron
|
||||
*/
|
||||
public class ThatSpellGraveyardExileReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
public static final String RULE_A = "If that spell would be put into a graveyard, exile it instead.";
|
||||
public static final String RULE_YOUR = "If that spell would be put into your graveyard, exile it instead.";
|
||||
|
||||
/**
|
||||
* If that spell would be put into a graveyard, exiles it instead.
|
||||
* Must set target pointer to fixed target.
|
||||
*/
|
||||
public ThatSpellGraveyardExileReplacementEffect(boolean yourGraveyard) {
|
||||
super(Duration.EndOfTurn, Outcome.Exile);
|
||||
staticText = yourGraveyard ? RULE_YOUR : RULE_A;
|
||||
}
|
||||
|
||||
protected ThatSpellGraveyardExileReplacementEffect(final ThatSpellGraveyardExileReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ThatSpellGraveyardExileReplacementEffect copy() {
|
||||
return new ThatSpellGraveyardExileReplacementEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
((ZoneChangeEvent) event).setToZone(Zone.EXILED);
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ZONE_CHANGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
return zEvent.getToZone() == Zone.GRAVEYARD
|
||||
&& zEvent.getTargetId().equals(((FixedTarget) getTargetPointer()).getTarget())
|
||||
&& ((FixedTarget) getTargetPointer()).getZoneChangeCounter() + 1
|
||||
== game.getState().getZoneChangeCounter(zEvent.getTargetId());
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue