forked from External/mage
implement [BLB] Dragonhawk, Festival of Embers, Jackdaw Savior, Infamous Cruelclaw (#12906)
* [BLB] Dragonhawk, Fate's Tempest * [BLB] Festival of Embers * [BLB] Jackdaw Savior + test * [BLB] The Infamous Cruelclaw * Dragonhawk changes * Create generic GraveyardFromAnywhereExileReplacementEffect * Hide Cruelclaw Menace reminder text * fix style errors
This commit is contained in:
parent
9fd3f91388
commit
be745cb096
17 changed files with 675 additions and 443 deletions
127
Mage.Sets/src/mage/cards/d/DragonhawkFatesTempest.java
Normal file
127
Mage.Sets/src/mage/cards/d/DragonhawkFatesTempest.java
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
package mage.cards.d;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility;
|
||||
import mage.abilities.common.delayed.AtTheBeginOfNextEndStepDelayedTriggeredAbility;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.common.ExileTopXMayPlayUntilEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.predicate.mageobject.PowerPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.target.targetpointer.FixedTargets;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author notgreat
|
||||
*/
|
||||
public final class DragonhawkFatesTempest extends CardImpl {
|
||||
|
||||
private static final FilterControlledCreaturePermanent filter = new FilterControlledCreaturePermanent("creatures you control with power 4 or greater");
|
||||
|
||||
static {
|
||||
filter.add(new PowerPredicate(ComparisonType.OR_GREATER, 4));
|
||||
}
|
||||
|
||||
public DragonhawkFatesTempest(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}{R}");
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.BIRD);
|
||||
this.subtype.add(SubType.DRAGON);
|
||||
this.power = new MageInt(5);
|
||||
this.toughness = new MageInt(5);
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Whenever Dragonhawk enters or attacks, exile the top X cards of your library, where X is the number of creatures you control with power 4 or greater. You may play those cards until your next end step.
|
||||
// At the beginning of your next end step, Dragonhawk deals 2 damage to each opponent for each of those cards that are still exiled.
|
||||
this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new DragonhawkExileEffect(
|
||||
new PermanentsOnBattlefieldCount(filter, null), Duration.UntilYourNextEndStep)
|
||||
.withTextOptions("those cards", true)));
|
||||
}
|
||||
|
||||
private DragonhawkFatesTempest(final DragonhawkFatesTempest card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DragonhawkFatesTempest copy() {
|
||||
return new DragonhawkFatesTempest(this);
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from ExileTopXMayPlayUntilEffect but with addDelayedTriggeredAbility
|
||||
class DragonhawkExileEffect extends ExileTopXMayPlayUntilEffect {
|
||||
|
||||
public DragonhawkExileEffect(DynamicValue amount, Duration duration) {
|
||||
super(amount, duration);
|
||||
staticText += ". At the beginning of your next end step, " + DragonhawkFatesTempestDamageEffect.STATIC_TEXT;
|
||||
}
|
||||
|
||||
private DragonhawkExileEffect(final DragonhawkExileEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DragonhawkExileEffect copy() {
|
||||
return new DragonhawkExileEffect(this);
|
||||
}
|
||||
|
||||
protected void effectCards(Game game, Ability source, Set<Card> cards) {
|
||||
game.addDelayedTriggeredAbility(new AtTheBeginOfNextEndStepDelayedTriggeredAbility(
|
||||
new DragonhawkFatesTempestDamageEffect(new FixedTargets(cards, game)), TargetController.YOU), source);
|
||||
}
|
||||
}
|
||||
|
||||
class DragonhawkFatesTempestDamageEffect extends OneShotEffect {
|
||||
FixedTargets cards;
|
||||
public static String STATIC_TEXT = "{this} deals 2 damage to each opponent for each of those cards that are still exiled";
|
||||
|
||||
DragonhawkFatesTempestDamageEffect(FixedTargets cards) {
|
||||
super(Outcome.Benefit);
|
||||
this.staticText = STATIC_TEXT;
|
||||
this.cards = cards;
|
||||
}
|
||||
|
||||
private DragonhawkFatesTempestDamageEffect(final DragonhawkFatesTempestDamageEffect effect) {
|
||||
super(effect);
|
||||
cards = effect.cards;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DragonhawkFatesTempestDamageEffect copy() {
|
||||
return new DragonhawkFatesTempestDamageEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player player = game.getPlayer(source.getControllerId());
|
||||
if (player == null) {
|
||||
return false;
|
||||
}
|
||||
int count = cards.getTargets(game, source).size(); //Automatically filters out moved cards
|
||||
if (count < 1) {
|
||||
return false;
|
||||
}
|
||||
for (UUID playerId : game.getOpponents(source.getControllerId())) {
|
||||
player = game.getPlayer(playerId);
|
||||
if (playerId == null) {
|
||||
continue;
|
||||
}
|
||||
player.damage(count * 2, source.getSourceId(), source, game);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,22 +1,16 @@
|
|||
|
||||
package mage.cards.d;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
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.filter.StaticFilters;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
@ -33,7 +27,7 @@ public final class DryadMilitant extends CardImpl {
|
|||
this.toughness = new MageInt(1);
|
||||
|
||||
// If an instant or sorcery card would be put into a graveyard from anywhere, exile it instead.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new DryadMilitantReplacementEffect()));
|
||||
this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY, false)));
|
||||
}
|
||||
|
||||
private DryadMilitant(final DryadMilitant card) {
|
||||
|
|
@ -45,42 +39,3 @@ public final class DryadMilitant extends CardImpl {
|
|||
return new DryadMilitant(this);
|
||||
}
|
||||
}
|
||||
|
||||
class DryadMilitantReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
DryadMilitantReplacementEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Exile);
|
||||
staticText = "If an instant or sorcery card would be put into a graveyard from anywhere, exile it instead";
|
||||
}
|
||||
|
||||
private DryadMilitantReplacementEffect(final DryadMilitantReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DryadMilitantReplacementEffect copy() {
|
||||
return new DryadMilitantReplacementEffect(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) {
|
||||
if (((ZoneChangeEvent)event).getToZone() == Zone.GRAVEYARD) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && (card.isSorcery(game) || card.isInstant(game))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
97
Mage.Sets/src/mage/cards/f/FestivalOfEmbers.java
Normal file
97
Mage.Sets/src/mage/cards/f/FestivalOfEmbers.java
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
package mage.cards.f;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.Costs;
|
||||
import mage.abilities.costs.CostsImpl;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.common.SacrificeSourceEffect;
|
||||
import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author notgreat
|
||||
*/
|
||||
public final class FestivalOfEmbers extends CardImpl {
|
||||
|
||||
public FestivalOfEmbers(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{4}{R}");
|
||||
|
||||
|
||||
// During your turn, you may cast instant and sorcery spells from your graveyard by paying 1 life in addition to their other costs.
|
||||
this.addAbility(new SimpleStaticAbility(new FestivalOfEmbersCastEffect()));
|
||||
|
||||
// If a card or token would be put into your graveyard from anywhere, exile it instead.
|
||||
this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(true, true)));
|
||||
|
||||
// {1}{R}: Sacrifice Festival of Embers.
|
||||
this.addAbility(new SimpleActivatedAbility(new SacrificeSourceEffect(), new ManaCostsImpl<>("{1}{R}")));
|
||||
}
|
||||
|
||||
private FestivalOfEmbers(final FestivalOfEmbers card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FestivalOfEmbers copy() {
|
||||
return new FestivalOfEmbers(this);
|
||||
}
|
||||
}
|
||||
|
||||
//Based on Osteomancer Adept
|
||||
class FestivalOfEmbersCastEffect extends AsThoughEffectImpl {
|
||||
|
||||
FestivalOfEmbersCastEffect() {
|
||||
super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.AIDontUseIt);
|
||||
staticText = "During your turn, you may cast instant and sorcery spells from your graveyard by paying 1 life in addition to their other costs.";
|
||||
}
|
||||
|
||||
private FestivalOfEmbersCastEffect(final FestivalOfEmbersCastEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FestivalOfEmbersCastEffect copy() {
|
||||
return new FestivalOfEmbersCastEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
if (!source.isControlledBy(affectedControllerId)) {
|
||||
return false;
|
||||
}
|
||||
Card card = game.getCard(objectId);
|
||||
Player player = game.getPlayer(affectedControllerId);
|
||||
if (card == null
|
||||
|| player == null
|
||||
|| !game.getActivePlayerId().equals(affectedControllerId)
|
||||
|| !card.isOwnedBy(affectedControllerId)
|
||||
|| !card.isInstantOrSorcery(game)
|
||||
|| !game.getState().getZone(objectId).match(Zone.GRAVEYARD)) {
|
||||
return false;
|
||||
}
|
||||
Costs<Cost> newCosts = new CostsImpl<>();
|
||||
newCosts.addAll(card.getSpellAbility().getCosts());
|
||||
newCosts.add(new PayLifeCost(1));
|
||||
player.setCastSourceIdWithAlternateMana(
|
||||
card.getId(), card.getManaCost(), newCosts
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
|
||||
package mage.cards.f;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
|
|
@ -14,12 +14,11 @@ import mage.constants.Outcome;
|
|||
import mage.constants.Zone;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.players.Player;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Quercitron
|
||||
|
|
@ -30,9 +29,9 @@ public final class ForbiddenCrypt extends CardImpl {
|
|||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{B}{B}");
|
||||
|
||||
// If you would draw a card, return a card from your graveyard to your hand instead. If you can't, you lose the game.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ForbiddenCryptDrawCardReplacementEffect()));
|
||||
this.addAbility(new SimpleStaticAbility(new ForbiddenCryptDrawCardReplacementEffect()));
|
||||
// If a card would be put into your graveyard from anywhere, exile that card instead.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new ForbiddenCryptPutIntoYourGraveyardReplacementEffect()));
|
||||
this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(true, false)));
|
||||
}
|
||||
|
||||
private ForbiddenCrypt(final ForbiddenCrypt card) {
|
||||
|
|
@ -96,47 +95,4 @@ class ForbiddenCryptDrawCardReplacementEffect extends ReplacementEffectImpl {
|
|||
return event.getPlayerId().equals(source.getControllerId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ForbiddenCryptPutIntoYourGraveyardReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
ForbiddenCryptPutIntoYourGraveyardReplacementEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Detriment);
|
||||
this.staticText = "If a card would be put into your graveyard from anywhere, exile that card instead";
|
||||
}
|
||||
|
||||
private ForbiddenCryptPutIntoYourGraveyardReplacementEffect(final ForbiddenCryptPutIntoYourGraveyardReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForbiddenCryptPutIntoYourGraveyardReplacementEffect copy() {
|
||||
return new ForbiddenCryptPutIntoYourGraveyardReplacementEffect(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) {
|
||||
if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && card.isOwnedBy(source.getControllerId())) {
|
||||
Permanent permanent = ((ZoneChangeEvent) event).getTarget();
|
||||
if (!(permanent instanceof PermanentToken)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -1,23 +1,19 @@
|
|||
package mage.cards.g;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect;
|
||||
import mage.abilities.keyword.SuspendAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author weirddan455
|
||||
|
|
@ -36,7 +32,7 @@ public final class GaeasWill extends CardImpl {
|
|||
this.getSpellAbility().addEffect(new GaeasWillGraveyardEffect());
|
||||
|
||||
// If a card would be put into your graveyard from anywhere this turn, exile that card instead.
|
||||
this.getSpellAbility().addEffect(new GaeassWillReplacementEffect());
|
||||
this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(Duration.EndOfTurn)));
|
||||
}
|
||||
|
||||
private GaeasWill(final GaeasWill card) {
|
||||
|
|
@ -79,45 +75,3 @@ class GaeasWillGraveyardEffect extends ContinuousEffectImpl {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class GaeassWillReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
GaeassWillReplacementEffect() {
|
||||
super(Duration.EndOfTurn, Outcome.Detriment);
|
||||
this.staticText = "<br>If a card would be put into your graveyard from anywhere this turn, exile that card instead";
|
||||
}
|
||||
|
||||
private GaeassWillReplacementEffect(final GaeassWillReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GaeassWillReplacementEffect copy() {
|
||||
return new GaeassWillReplacementEffect(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) {
|
||||
if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && card.isOwnedBy(source.getControllerId())) {
|
||||
Permanent permanent = ((ZoneChangeEvent) event).getTarget();
|
||||
if (!(permanent instanceof PermanentToken)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
91
Mage.Sets/src/mage/cards/j/JackdawSavior.java
Normal file
91
Mage.Sets/src/mage/cards/j/JackdawSavior.java
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
package mage.cards.j;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.DiesThisOrAnotherTriggeredAbility;
|
||||
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
|
||||
import mage.abilities.keyword.FlyingAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.ComparisonType;
|
||||
import mage.constants.SubType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterControlledCreaturePermanent;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.AbilityPredicate;
|
||||
import mage.filter.predicate.mageobject.MageObjectReferencePredicate;
|
||||
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.target.common.TargetCardInYourGraveyard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author notgreat
|
||||
*/
|
||||
public final class JackdawSavior extends CardImpl {
|
||||
public JackdawSavior(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
|
||||
|
||||
this.subtype.add(SubType.BIRD);
|
||||
this.subtype.add(SubType.CLERIC);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(1);
|
||||
|
||||
// Flying
|
||||
this.addAbility(FlyingAbility.getInstance());
|
||||
|
||||
// Whenever Jackdaw Savior or another creature you control with flying dies, return another target creature card with lesser mana value from your graveyard to the battlefield.
|
||||
this.addAbility(new JackdawSaviorDiesThisOrAnotherTriggeredAbility());
|
||||
}
|
||||
|
||||
private JackdawSavior(final JackdawSavior card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JackdawSavior copy() {
|
||||
return new JackdawSavior(this);
|
||||
}
|
||||
}
|
||||
|
||||
class JackdawSaviorDiesThisOrAnotherTriggeredAbility extends DiesThisOrAnotherTriggeredAbility {
|
||||
private static final FilterControlledCreaturePermanent flyingFilter = new FilterControlledCreaturePermanent("creature you control with flying");
|
||||
|
||||
static {
|
||||
flyingFilter.add(new AbilityPredicate(FlyingAbility.class));
|
||||
}
|
||||
|
||||
public JackdawSaviorDiesThisOrAnotherTriggeredAbility() {
|
||||
super(new ReturnFromGraveyardToBattlefieldTargetEffect().setText(
|
||||
"return another target creature card with lesser mana value from your graveyard to the battlefield"),
|
||||
false, flyingFilter);
|
||||
}
|
||||
|
||||
protected JackdawSaviorDiesThisOrAnotherTriggeredAbility(final JackdawSaviorDiesThisOrAnotherTriggeredAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JackdawSaviorDiesThisOrAnotherTriggeredAbility copy() {
|
||||
return new JackdawSaviorDiesThisOrAnotherTriggeredAbility(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
if (super.checkTrigger(event, game)) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
FilterCard filter = new FilterCreatureCard();
|
||||
filter.add(Predicates.not(new MageObjectReferencePredicate(zEvent.getTargetId(), game)));
|
||||
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, zEvent.getTarget().getManaValue()));
|
||||
filter.setMessage("target creature card other than "+zEvent.getTarget().getLogName()+" with mana value less than "+zEvent.getTarget().getManaValue());
|
||||
this.getTargets().clear();
|
||||
this.addTarget(new TargetCardInYourGraveyard(filter));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
package mage.cards.m;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
|
|
@ -9,24 +8,15 @@ import mage.abilities.costs.common.ExileSourceCost;
|
|||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
|
|
@ -44,7 +34,7 @@ public final class MagusOfTheWill extends CardImpl {
|
|||
// {2}{B}, {T}, Exile Magus of the Will: Until end of turn, you may play cards from your graveyard.
|
||||
// If a card would be put into your graveyard from anywhere else this turn, exile that card instead.
|
||||
Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CanPlayCardsFromGraveyardEffect(), new ManaCostsImpl<>("{2}{B}"));
|
||||
ability.addEffect(new MagusOfTheWillReplacementEffect());
|
||||
ability.addEffect(new GraveyardFromAnywhereExileReplacementEffect(Duration.EndOfTurn));
|
||||
ability.addCost(new TapSourceCost());
|
||||
ability.addCost(new ExileSourceCost());
|
||||
this.addAbility(ability);
|
||||
|
|
@ -91,46 +81,3 @@ class CanPlayCardsFromGraveyardEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
class MagusOfTheWillReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
MagusOfTheWillReplacementEffect() {
|
||||
super(Duration.EndOfTurn, Outcome.Detriment);
|
||||
this.staticText = "If a card would be put into your graveyard from anywhere else this turn, exile that card instead";
|
||||
}
|
||||
|
||||
private MagusOfTheWillReplacementEffect(final MagusOfTheWillReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MagusOfTheWillReplacementEffect copy() {
|
||||
return new MagusOfTheWillReplacementEffect(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) {
|
||||
if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && card.isOwnedBy(source.getControllerId())) {
|
||||
Permanent permanent = ((ZoneChangeEvent) event).getTarget();
|
||||
if (!(permanent instanceof PermanentToken)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,18 +6,13 @@ import mage.abilities.common.SimpleStaticAbility;
|
|||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.common.PayLifeCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.SkipDrawStepEffect;
|
||||
import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
|
@ -50,7 +45,7 @@ public final class Necrodominance extends CardImpl {
|
|||
));
|
||||
|
||||
// If a card or token would be put into your graveyard from anywhere, exile it instead.
|
||||
this.addAbility(new SimpleStaticAbility(new NecrodominanceReplacementEffect()));
|
||||
this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(true, true)));
|
||||
}
|
||||
|
||||
private Necrodominance(final Necrodominance card) {
|
||||
|
|
@ -95,50 +90,4 @@ class NecrodominanceEffect extends OneShotEffect {
|
|||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Inspired by [Rest in Peace] and [Wheel of Sun and Moon]
|
||||
class NecrodominanceReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
NecrodominanceReplacementEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Exile);
|
||||
staticText = "If a card or token would be put into your graveyard from anywhere, exile it instead";
|
||||
}
|
||||
|
||||
private NecrodominanceReplacementEffect(final NecrodominanceReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NecrodominanceReplacementEffect copy() {
|
||||
return new NecrodominanceReplacementEffect(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;
|
||||
if (zEvent.getToZone() != Zone.GRAVEYARD) {
|
||||
return false;
|
||||
}
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && card.isOwnedBy(source.getControllerId())) {
|
||||
return true;
|
||||
}
|
||||
Permanent token = game.getPermanent(event.getTargetId());
|
||||
if (token != null && token instanceof PermanentToken && token.isOwnedBy(source.getControllerId())) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +1,15 @@
|
|||
|
||||
package mage.cards.r;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.ExileGraveyardAllPlayersEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect;
|
||||
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.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author LevelX2
|
||||
|
|
@ -49,7 +39,7 @@ public final class RestInPeace extends CardImpl {
|
|||
this.addAbility(new EntersBattlefieldTriggeredAbility(new ExileGraveyardAllPlayersEffect()));
|
||||
|
||||
// If a card or token would be put into a graveyard from anywhere, exile it instead.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new RestInPeaceReplacementEffect()));
|
||||
this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(false, true)));
|
||||
}
|
||||
|
||||
private RestInPeace(final RestInPeace card) {
|
||||
|
|
@ -61,36 +51,3 @@ public final class RestInPeace extends CardImpl {
|
|||
return new RestInPeace(this);
|
||||
}
|
||||
}
|
||||
|
||||
class RestInPeaceReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
RestInPeaceReplacementEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Exile);
|
||||
staticText = "If a card or token would be put into a graveyard from anywhere, exile it instead";
|
||||
}
|
||||
|
||||
private RestInPeaceReplacementEffect(final RestInPeaceReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RestInPeaceReplacementEffect copy() {
|
||||
return new RestInPeaceReplacementEffect(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) {
|
||||
return ((ZoneChangeEvent)event).getToZone() == Zone.GRAVEYARD;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
118
Mage.Sets/src/mage/cards/t/TheInfamousCruelclaw.java
Normal file
118
Mage.Sets/src/mage/cards/t/TheInfamousCruelclaw.java
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
package mage.cards.t;
|
||||
|
||||
import mage.ApprovingObject;
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.Costs;
|
||||
import mage.abilities.costs.CostsImpl;
|
||||
import mage.abilities.costs.common.DiscardCardCost;
|
||||
import mage.abilities.effects.OneShotEffect;
|
||||
import mage.abilities.keyword.MenaceAbility;
|
||||
import mage.cards.Card;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author notgreat
|
||||
*/
|
||||
public final class TheInfamousCruelclaw extends CardImpl {
|
||||
|
||||
public TheInfamousCruelclaw(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{R}");
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.WEASEL);
|
||||
this.subtype.add(SubType.MERCENARY);
|
||||
this.power = new MageInt(3);
|
||||
this.toughness = new MageInt(3);
|
||||
|
||||
// Menace
|
||||
this.addAbility(new MenaceAbility(false));
|
||||
|
||||
// Whenever The Infamous Cruelclaw deals combat damage to a player, exile cards from the top of your library until you exile a nonland card. You may cast that card by discarding a card rather than paying its mana cost.
|
||||
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new InfamousCruelclawEffect()));
|
||||
}
|
||||
|
||||
private TheInfamousCruelclaw(final TheInfamousCruelclaw card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TheInfamousCruelclaw copy() {
|
||||
return new TheInfamousCruelclaw(this);
|
||||
}
|
||||
}
|
||||
|
||||
//Based on Amped Raptor
|
||||
class InfamousCruelclawEffect extends OneShotEffect {
|
||||
|
||||
InfamousCruelclawEffect() {
|
||||
super(Outcome.PlayForFree);
|
||||
staticText = "exile cards from the top of your library until you exile a nonland card. "
|
||||
+ "You may cast that card by discarding a card rather than paying its mana cost.";
|
||||
}
|
||||
|
||||
private InfamousCruelclawEffect(final InfamousCruelclawEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InfamousCruelclawEffect copy() {
|
||||
return new InfamousCruelclawEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
if (controller == null || !controller.getLibrary().hasCards()) {
|
||||
return false;
|
||||
}
|
||||
for (Card card : controller.getLibrary().getCards(game)) {
|
||||
controller.moveCards(card, Zone.EXILED, source, game);
|
||||
if (!card.isLand(game)) {
|
||||
List<Card> castableComponents = CardUtil.getCastableComponents(card, null, source, controller, game, null, false);
|
||||
if (castableComponents.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
String partsInfo = castableComponents
|
||||
.stream()
|
||||
.map(MageObject::getLogName)
|
||||
.collect(Collectors.joining(" or "));
|
||||
if (!controller.chooseUse(Outcome.PlayForFree, "Cast spell by discarding a card instead of mana (" + partsInfo + ")?", source, game)) {
|
||||
break;
|
||||
}
|
||||
castableComponents.forEach(partCard -> game.getState().setValue("PlayFromNotOwnHandZone" + partCard.getId(), Boolean.TRUE));
|
||||
SpellAbility chosenAbility = controller.chooseAbilityForCast(card, game, true);
|
||||
if (chosenAbility != null) {
|
||||
Card faceCard = game.getCard(chosenAbility.getSourceId());
|
||||
if (faceCard != null) {
|
||||
// discard instead of mana cost
|
||||
Costs<Cost> newCosts = new CostsImpl<>();
|
||||
newCosts.add(new DiscardCardCost());
|
||||
newCosts.addAll(chosenAbility.getCosts());
|
||||
controller.setCastSourceIdWithAlternateMana(faceCard.getId(), null, newCosts);
|
||||
controller.cast(
|
||||
chosenAbility, game, true,
|
||||
new ApprovingObject(source, game)
|
||||
);
|
||||
}
|
||||
}
|
||||
castableComponents.forEach(partCard -> game.getState().setValue("PlayFromNotOwnHandZone" + partCard.getId(), null));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +1,19 @@
|
|||
|
||||
package mage.cards.y;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.abilities.effects.common.continuous.CantCastMoreThanOneSpellEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.TargetController;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
|
|
@ -34,11 +24,11 @@ public final class YawgmothsAgenda extends CardImpl {
|
|||
super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{3}{B}{B}");
|
||||
|
||||
// You can't cast more than one spell each turn.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new CantCastMoreThanOneSpellEffect(TargetController.YOU)));
|
||||
this.addAbility(new SimpleStaticAbility(new CantCastMoreThanOneSpellEffect(TargetController.YOU)));
|
||||
// You may play cards from your graveyard.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new YawgmothsAgendaCanPlayCardsFromGraveyardEffect()));
|
||||
this.addAbility(new SimpleStaticAbility(new YawgmothsAgendaCanPlayCardsFromGraveyardEffect()));
|
||||
// If a card would be put into your graveyard from anywhere, exile it instead.
|
||||
this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new YawgmothsAgendaReplacementEffect()));
|
||||
this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(true, false)));
|
||||
}
|
||||
|
||||
private YawgmothsAgenda(final YawgmothsAgenda card) {
|
||||
|
|
@ -80,48 +70,4 @@ class YawgmothsAgendaCanPlayCardsFromGraveyardEffect extends ContinuousEffectImp
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class YawgmothsAgendaReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
YawgmothsAgendaReplacementEffect() {
|
||||
super(Duration.WhileOnBattlefield, Outcome.Detriment);
|
||||
this.staticText = "If a card would be put into your graveyard from anywhere, exile it instead";
|
||||
}
|
||||
|
||||
private YawgmothsAgendaReplacementEffect(final YawgmothsAgendaReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public YawgmothsAgendaReplacementEffect copy() {
|
||||
return new YawgmothsAgendaReplacementEffect(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) {
|
||||
if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && card.isOwnedBy(source.getControllerId())) {
|
||||
Permanent permanent = ((ZoneChangeEvent) event).getTarget();
|
||||
if (!(permanent instanceof PermanentToken)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,17 @@
|
|||
|
||||
package mage.cards.y;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ContinuousEffectImpl;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Layer;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.SubLayer;
|
||||
import mage.constants.Zone;
|
||||
import mage.constants.*;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.events.GameEvent.EventType;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.players.Player;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author LevelX2
|
||||
|
|
@ -35,7 +25,7 @@ public final class YawgmothsWill extends CardImpl {
|
|||
this.getSpellAbility().addEffect(new CanPlayCardsFromGraveyardEffect());
|
||||
|
||||
// If a card would be put into your graveyard from anywhere this turn, exile that card instead.
|
||||
this.getSpellAbility().addEffect(new YawgmothsWillReplacementEffect());
|
||||
this.getSpellAbility().addEffect(new GraveyardFromAnywhereExileReplacementEffect(Duration.EndOfTurn).concatBy("<br>"));
|
||||
}
|
||||
|
||||
private YawgmothsWill(final YawgmothsWill card) {
|
||||
|
|
@ -79,46 +69,3 @@ class CanPlayCardsFromGraveyardEffect extends ContinuousEffectImpl {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
class YawgmothsWillReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
YawgmothsWillReplacementEffect() {
|
||||
super(Duration.EndOfTurn, Outcome.Detriment);
|
||||
this.staticText = "If a card would be put into your graveyard from anywhere this turn, exile that card instead";
|
||||
}
|
||||
|
||||
private YawgmothsWillReplacementEffect(final YawgmothsWillReplacementEffect effect) {
|
||||
super(effect);
|
||||
}
|
||||
|
||||
@Override
|
||||
public YawgmothsWillReplacementEffect copy() {
|
||||
return new YawgmothsWillReplacementEffect(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) {
|
||||
if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD) {
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && card.isOwnedBy(source.getControllerId())) {
|
||||
Permanent permanent = ((ZoneChangeEvent) event).getTarget();
|
||||
if (!(permanent instanceof PermanentToken)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ public final class Bloomburrow extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Diresight", 91, Rarity.COMMON, mage.cards.d.Diresight.class));
|
||||
cards.add(new SetCardInfo("Dour Port-Mage", 47, Rarity.RARE, mage.cards.d.DourPortMage.class));
|
||||
cards.add(new SetCardInfo("Downwind Ambusher", 92, Rarity.UNCOMMON, mage.cards.d.DownwindAmbusher.class));
|
||||
cards.add(new SetCardInfo("Dragonhawk, Fate's Tempest", 132, Rarity.MYTHIC, mage.cards.d.DragonhawkFatesTempest.class));
|
||||
cards.add(new SetCardInfo("Dreamdew Entrancer", 211, Rarity.RARE, mage.cards.d.DreamdewEntrancer.class));
|
||||
cards.add(new SetCardInfo("Driftgloom Coyote", 11, Rarity.UNCOMMON, mage.cards.d.DriftgloomCoyote.class));
|
||||
cards.add(new SetCardInfo("Druid of the Spade", 170, Rarity.COMMON, mage.cards.d.DruidOfTheSpade.class));
|
||||
|
|
@ -94,6 +95,7 @@ public final class Bloomburrow extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Fecund Greenshell", 362, Rarity.RARE, mage.cards.f.FecundGreenshell.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Feed the Cycle", 94, Rarity.UNCOMMON, mage.cards.f.FeedTheCycle.class));
|
||||
cards.add(new SetCardInfo("Fell", 95, Rarity.UNCOMMON, mage.cards.f.Fell.class));
|
||||
cards.add(new SetCardInfo("Festival of Embers", 134, Rarity.RARE, mage.cards.f.FestivalOfEmbers.class));
|
||||
cards.add(new SetCardInfo("Finch Formation", 50, Rarity.COMMON, mage.cards.f.FinchFormation.class));
|
||||
cards.add(new SetCardInfo("Finneas, Ace Archer", 212, Rarity.RARE, mage.cards.f.FinneasAceArcher.class));
|
||||
cards.add(new SetCardInfo("Fireglass Mentor", 213, Rarity.UNCOMMON, mage.cards.f.FireglassMentor.class));
|
||||
|
|
@ -135,6 +137,7 @@ public final class Bloomburrow extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Intrepid Rabbit", 17, Rarity.COMMON, mage.cards.i.IntrepidRabbit.class));
|
||||
cards.add(new SetCardInfo("Iridescent Vinelasher", 99, Rarity.RARE, mage.cards.i.IridescentVinelasher.class));
|
||||
cards.add(new SetCardInfo("Island", 266, Rarity.LAND, mage.cards.basiclands.Island.class, FULL_ART_BFZ_VARIOUS));
|
||||
cards.add(new SetCardInfo("Jackdaw Savior", 18, Rarity.RARE, mage.cards.j.JackdawSavior.class));
|
||||
cards.add(new SetCardInfo("Jolly Gerbils", 19, Rarity.UNCOMMON, mage.cards.j.JollyGerbils.class));
|
||||
cards.add(new SetCardInfo("Junkblade Bruiser", 220, Rarity.COMMON, mage.cards.j.JunkbladeBruiser.class));
|
||||
cards.add(new SetCardInfo("Kastral, the Windcrested", 221, Rarity.RARE, mage.cards.k.KastralTheWindcrested.class));
|
||||
|
|
@ -259,6 +262,7 @@ public final class Bloomburrow extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Teapot Slinger", 157, Rarity.UNCOMMON, mage.cards.t.TeapotSlinger.class));
|
||||
cards.add(new SetCardInfo("Tempest Angler", 235, Rarity.COMMON, mage.cards.t.TempestAngler.class));
|
||||
cards.add(new SetCardInfo("Tender Wildguide", 196, Rarity.RARE, mage.cards.t.TenderWildguide.class));
|
||||
cards.add(new SetCardInfo("The Infamous Cruelclaw", 219, Rarity.MYTHIC, mage.cards.t.TheInfamousCruelclaw.class));
|
||||
cards.add(new SetCardInfo("Thieving Otter", 390, Rarity.COMMON, mage.cards.t.ThievingOtter.class));
|
||||
cards.add(new SetCardInfo("Thistledown Players", 35, Rarity.COMMON, mage.cards.t.ThistledownPlayers.class));
|
||||
cards.add(new SetCardInfo("Thornplate Intimidator", 117, Rarity.COMMON, mage.cards.t.ThornplateIntimidator.class));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,90 @@
|
|||
package org.mage.test.cards.single.blb;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author notgreat
|
||||
*/
|
||||
public class JackdawSaviorTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* {@link mage.cards.j.JackdawSavior Jackdaw Savior} {2}{W}
|
||||
* Creature — Bird Cleric
|
||||
* Flying
|
||||
* Whenever Jackdaw Savior or another creature you control with flying dies,
|
||||
* return another target creature card with lesser mana value from your graveyard to the battlefield.
|
||||
* <p>
|
||||
* This card is unusual in that "another" here refers to "other than the creature that just died",
|
||||
* which xmage does not natively support.
|
||||
*/
|
||||
|
||||
@Test
|
||||
public void test_Simultaneous() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Jackdaw Savior"); //MV = 3, flying
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Air Elemental"); //MV = 5, flying
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Memnite"); //MV = 1
|
||||
|
||||
addCard(Zone.HAND, playerA, "Damnation");
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 4);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Damnation");
|
||||
setChoice(playerA, ""); //Order triggers
|
||||
addTarget(playerA, "Jackdaw Savior");
|
||||
addTarget(playerA, "Memnite");
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, 2); //Air Elemental+Damnation
|
||||
assertPermanentCount(playerA, "Jackdaw Savior", 1);
|
||||
assertPermanentCount(playerA, "Memnite", 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_Clones() {
|
||||
setStrictChooseMode(true);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Jackdaw Savior"); //MV = 3, flying
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Air Elemental"); //MV = 5, flying
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Spidersilk Armor"); //+0/+1 to all
|
||||
|
||||
addCard(Zone.HAND, playerA, "Phantasmal Image", 2); //MV = 2, clone
|
||||
addCard(Zone.HAND, playerA, "Murder", 2);
|
||||
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 10);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image");
|
||||
setChoice(playerA, true);
|
||||
setChoice(playerA, "Air Elemental");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder");
|
||||
addTarget(playerA, "Air Elemental[only copy]");
|
||||
// Can't target itself, no valid targets
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phantasmal Image");
|
||||
setChoice(playerA, true);
|
||||
setChoice(playerA, "Air Elemental");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Murder");
|
||||
addTarget(playerA, "Air Elemental[only copy]");
|
||||
addTarget(playerA, "Phantasmal Image"); // Target the previous one
|
||||
setChoice(playerA, false); //Don't copy, stay on battlefield as 0/1
|
||||
|
||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Murder", 2);
|
||||
assertGraveyardCount(playerA, "Phantasmal Image", 1);
|
||||
assertPermanentCount(playerA, "Phantasmal Image", 1);
|
||||
assertPermanentCount(playerA, "Jackdaw Savior", 1);
|
||||
assertPermanentCount(playerA, "Air Elemental", 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -56,19 +56,12 @@ public class DiesThisOrAnotherTriggeredAbility extends TriggeredAbilityImpl {
|
|||
@Override
|
||||
public boolean checkTrigger(GameEvent event, Game game) {
|
||||
ZoneChangeEvent zEvent = (ZoneChangeEvent) event;
|
||||
if (zEvent.isDiesEvent()) {
|
||||
if (zEvent.getTarget() != null) {
|
||||
if (!applyFilterOnSource && zEvent.getTarget().getId().equals(this.getSourceId())) {
|
||||
// TODO: remove this workaround for Basri's Lieutenant
|
||||
return true;
|
||||
} else {
|
||||
if (filter.match(zEvent.getTarget(), getControllerId(), this, game)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!zEvent.isDiesEvent() || zEvent.getTarget() == null) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
// TODO: remove applyFilterOnSource workaround for Basri's Lieutenant
|
||||
return ((!applyFilterOnSource && zEvent.getTarget().getId().equals(this.getSourceId()))
|
||||
|| filter.match(zEvent.getTarget(), getControllerId(), this, game));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class ExileTopXMayPlayUntilEffect extends OneShotEffect {
|
|||
makeText(amount.toString().equals("1") ? "that card" : "those cards", duration == Duration.EndOfTurn);
|
||||
}
|
||||
|
||||
private ExileTopXMayPlayUntilEffect(final ExileTopXMayPlayUntilEffect effect) {
|
||||
protected ExileTopXMayPlayUntilEffect(final ExileTopXMayPlayUntilEffect effect) {
|
||||
super(effect);
|
||||
this.amount = effect.amount.copy();
|
||||
this.duration = effect.duration;
|
||||
|
|
@ -60,10 +60,15 @@ public class ExileTopXMayPlayUntilEffect extends OneShotEffect {
|
|||
if (!cards.isEmpty()) {
|
||||
game.addEffect(new PlayFromNotOwnHandZoneTargetEffect(Zone.EXILED, duration)
|
||||
.setTargetPointer(new FixedTargets(cards, game)), source);
|
||||
effectCards(game, source, cards);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected void effectCards(Game game, Ability source, Set<Card> cards) {
|
||||
//Do nothing, used for derived classes
|
||||
}
|
||||
|
||||
/**
|
||||
* [Until end of turn, ] you may play [refCardText] [this turn]
|
||||
*/
|
||||
|
|
@ -76,7 +81,11 @@ public class ExileTopXMayPlayUntilEffect extends OneShotEffect {
|
|||
String text = "exile the top ";
|
||||
boolean singular = amount.toString().equals("1");
|
||||
text += singular ? "card" : CardUtil.numberToText(amount.toString()) + " cards";
|
||||
text += " of your library. ";
|
||||
if (amount.toString().equals("X")) {
|
||||
text += " of your library, where X is " + amount.getMessage() + ". ";
|
||||
} else {
|
||||
text += " of your library. ";
|
||||
}
|
||||
if (durationRuleAtEnd) {
|
||||
text += "You may play " + refCardText + ' ' + (duration == Duration.EndOfTurn ? "this turn" : duration.toString());
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,92 @@
|
|||
package mage.abilities.effects.common.replacement;
|
||||
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.constants.Zone;
|
||||
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.permanent.Permanent;
|
||||
import mage.game.permanent.PermanentToken;
|
||||
import mage.util.CardUtil;
|
||||
|
||||
/**
|
||||
* @author notgreat
|
||||
*/
|
||||
public class GraveyardFromAnywhereExileReplacementEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final FilterCard filter;
|
||||
private final boolean onlyYou;
|
||||
private final boolean tokens;
|
||||
|
||||
public GraveyardFromAnywhereExileReplacementEffect(FilterCard filter, boolean onlyYou) {
|
||||
this(Duration.WhileOnBattlefield, filter, onlyYou, false);
|
||||
}
|
||||
|
||||
public GraveyardFromAnywhereExileReplacementEffect(boolean onlyYou, boolean tokens) {
|
||||
this(Duration.WhileOnBattlefield, StaticFilters.FILTER_CARD_A, onlyYou, tokens);
|
||||
}
|
||||
|
||||
public GraveyardFromAnywhereExileReplacementEffect(Duration duration) {
|
||||
this(duration, StaticFilters.FILTER_CARD_A, true, false);
|
||||
}
|
||||
protected GraveyardFromAnywhereExileReplacementEffect(Duration duration, FilterCard filter, boolean onlyYou, boolean tokens) {
|
||||
super(duration, Outcome.Exile);
|
||||
this.filter = filter;
|
||||
this.onlyYou = onlyYou;
|
||||
this.tokens = tokens;
|
||||
this.setText();
|
||||
}
|
||||
|
||||
private GraveyardFromAnywhereExileReplacementEffect(final GraveyardFromAnywhereExileReplacementEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
this.onlyYou = effect.onlyYou;
|
||||
this.tokens = effect.tokens;
|
||||
}
|
||||
|
||||
private void setText() {
|
||||
this.staticText = "If " + CardUtil.addArticle(filter.getMessage()) + (tokens ? " or token" : "")
|
||||
+ " would be put into " + (onlyYou ? "your" : "a") + " graveyard from anywhere"
|
||||
+ (duration == Duration.EndOfTurn ? " this turn" : "") + ", exile "
|
||||
+ ((filter == StaticFilters.FILTER_CARD_A && !tokens) ? "that card" : "it") + " instead";
|
||||
}
|
||||
|
||||
@Override
|
||||
public GraveyardFromAnywhereExileReplacementEffect copy() {
|
||||
return new GraveyardFromAnywhereExileReplacementEffect(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;
|
||||
if (zEvent.getToZone() != Zone.GRAVEYARD) {
|
||||
return false;
|
||||
}
|
||||
Card card = game.getCard(event.getTargetId());
|
||||
if (card != null && (!onlyYou || card.isOwnedBy(source.getControllerId())) && (filter == null || filter.match(card, game))) {
|
||||
return true;
|
||||
}
|
||||
Permanent token = game.getPermanent(event.getTargetId());
|
||||
if (tokens && (token instanceof PermanentToken && (!onlyYou || token.isOwnedBy(source.getControllerId())))) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue