forked from External/mage
implement [FIC] Edgar, Master Machinist (#13676)
This commit is contained in:
parent
0ac37617d1
commit
ba395c8385
23 changed files with 580 additions and 244 deletions
|
|
@ -2,7 +2,7 @@ package mage.cards.a;
|
|||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.CastFromGraveyardOnceEachTurnAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceDuringEachOfYourTurnAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.common.DrawDiscardControllerEffect;
|
||||
|
|
@ -24,14 +24,13 @@ import mage.game.permanent.Permanent;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author justinjohnson14
|
||||
*/
|
||||
public final class ArcadeGannon extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("an artifact or Human spell from your graveyard with mana value less than or equal to the number of quest counters on {this}");
|
||||
|
||||
static{
|
||||
static {
|
||||
filter.add(Predicates.or(
|
||||
CardType.ARTIFACT.getPredicate(),
|
||||
SubType.HUMAN.getPredicate()
|
||||
|
|
@ -41,7 +40,7 @@ public final class ArcadeGannon extends CardImpl {
|
|||
|
||||
public ArcadeGannon(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}{U}");
|
||||
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.DOCTOR);
|
||||
|
|
@ -49,12 +48,12 @@ public final class ArcadeGannon extends CardImpl {
|
|||
this.toughness = new MageInt(3);
|
||||
|
||||
// {T}: Draw a card, then discard a card. Put a quest counter on Arcade Gannon.
|
||||
Ability ability = (new SimpleActivatedAbility(new DrawDiscardControllerEffect(1,1), new TapSourceCost()));
|
||||
Ability ability = (new SimpleActivatedAbility(new DrawDiscardControllerEffect(1, 1), new TapSourceCost()));
|
||||
ability.addEffect(new AddCountersSourceEffect(CounterType.QUEST.createInstance(1)));
|
||||
this.addAbility(ability);
|
||||
|
||||
// For Auld Lang Syne -- Once during each of your turns, you may cast an artifact or Human spell from your graveyard with mana value less than or equal to the number of quest counters on Arcade Gannon.
|
||||
this.addAbility(new CastFromGraveyardOnceEachTurnAbility(filter).withFlavorWord("For Auld Lang Syne"));
|
||||
this.addAbility(new CastFromGraveyardOnceDuringEachOfYourTurnAbility(filter).withFlavorWord("For Auld Lang Syne"));
|
||||
}
|
||||
|
||||
private ArcadeGannon(final ArcadeGannon card) {
|
||||
|
|
|
|||
|
|
@ -1,26 +1,27 @@
|
|||
package mage.cards.b;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceEachTurnAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceDuringEachOfYourTurnAbility;
|
||||
import mage.abilities.costs.CompositeCost;
|
||||
import mage.abilities.costs.common.DiscardCardCost;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.filter.predicate.Predicate;
|
||||
import mage.game.Game;
|
||||
import mage.watchers.common.CardsPutIntoGraveyardWatcher;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author balazskristof
|
||||
*/
|
||||
|
|
@ -36,7 +37,7 @@ public final class BanonTheReturnersLeader extends CardImpl {
|
|||
|
||||
public BanonTheReturnersLeader(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}");
|
||||
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.CLERIC);
|
||||
|
|
@ -45,7 +46,7 @@ public final class BanonTheReturnersLeader extends CardImpl {
|
|||
this.toughness = new MageInt(3);
|
||||
|
||||
// Pray -- Once during each of your turns, you may cast a creature spell from among cards in your graveyard that were put there from anywhere other than the battlefield this turn.
|
||||
Ability ability = new CastFromGraveyardOnceEachTurnAbility(filter).withFlavorWord("Pray");
|
||||
Ability ability = new CastFromGraveyardOnceDuringEachOfYourTurnAbility(filter).withFlavorWord("Pray");
|
||||
ability.addWatcher(new CardsPutIntoGraveyardWatcher());
|
||||
this.addAbility(ability);
|
||||
// Whenever you attack, you may pay {1} and discard a card. If you do, draw a card.
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import mage.constants.Duration;
|
|||
import mage.constants.Outcome;
|
||||
import mage.constants.SetTargetPointer;
|
||||
import mage.counters.CounterType;
|
||||
import mage.filter.common.FilterCreatureSpell;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.EntersTheBattlefieldEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
|
|
@ -28,8 +28,6 @@ import java.util.UUID;
|
|||
*/
|
||||
public final class CommunalBrewing extends CardImpl {
|
||||
|
||||
private static final FilterCreatureSpell filter = new FilterCreatureSpell("a creature spell");
|
||||
|
||||
public CommunalBrewing(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{G}");
|
||||
|
||||
|
|
@ -41,7 +39,11 @@ public final class CommunalBrewing extends CardImpl {
|
|||
|
||||
// Whenever you cast a creature spell, that creature enters with X additional +1/+1
|
||||
// counters on it, where X is the number of ingredient counters on Communal Brewing.
|
||||
this.addAbility(new SpellCastControllerTriggeredAbility(new CommunalBrewingCountersEffect(), filter, false, SetTargetPointer.SPELL));
|
||||
this.addAbility(new SpellCastControllerTriggeredAbility(
|
||||
new CommunalBrewingCountersEffect(),
|
||||
StaticFilters.FILTER_SPELL_A_CREATURE,
|
||||
false, SetTargetPointer.SPELL
|
||||
));
|
||||
}
|
||||
|
||||
private CommunalBrewing(final CommunalBrewing card) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package mage.cards.d;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.CastFromGraveyardOnceEachTurnAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceDuringEachOfYourTurnAbility;
|
||||
import mage.abilities.keyword.LifelinkAbility;
|
||||
import mage.abilities.keyword.TrampleAbility;
|
||||
import mage.abilities.keyword.VigilanceAbility;
|
||||
|
|
@ -21,6 +21,7 @@ import java.util.UUID;
|
|||
public final class DanithaNewBenaliasLight extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("an Aura or Equipment spell");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.or(
|
||||
SubType.AURA.getPredicate(), SubType.EQUIPMENT.getPredicate()
|
||||
|
|
@ -46,7 +47,7 @@ public final class DanithaNewBenaliasLight extends CardImpl {
|
|||
this.addAbility(LifelinkAbility.getInstance());
|
||||
|
||||
// Once during each of your turns, you may cast an Aura or Equipment spell from your graveyard.
|
||||
this.addAbility(new CastFromGraveyardOnceEachTurnAbility(filter));
|
||||
this.addAbility(new CastFromGraveyardOnceDuringEachOfYourTurnAbility(filter));
|
||||
}
|
||||
|
||||
private DanithaNewBenaliasLight(final DanithaNewBenaliasLight card) {
|
||||
|
|
|
|||
55
Mage.Sets/src/mage/cards/e/EdgarMasterMachinist.java
Normal file
55
Mage.Sets/src/mage/cards/e/EdgarMasterMachinist.java
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
package mage.cards.e;
|
||||
|
||||
import mage.MageIdentifier;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.AttacksTriggeredAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceDuringEachOfYourTurnAbility;
|
||||
import mage.abilities.dynamicvalue.common.GreatestAmongPermanentsValue;
|
||||
import mage.abilities.dynamicvalue.common.StaticValue;
|
||||
import mage.abilities.effects.common.continuous.BoostSourceEffect;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterArtifactCard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public final class EdgarMasterMachinist extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterArtifactCard("an artifact spell");
|
||||
|
||||
public EdgarMasterMachinist(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{W}");
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.HUMAN);
|
||||
this.subtype.add(SubType.ARTIFICER);
|
||||
this.subtype.add(SubType.NOBLE);
|
||||
this.power = new MageInt(2);
|
||||
this.toughness = new MageInt(4);
|
||||
|
||||
// Once during each of your turns, you may cast an artifact spell from your graveyard. If you cast a spell this way, that artifact enters tapped.
|
||||
this.addAbility(new CastFromGraveyardOnceDuringEachOfYourTurnAbility(filter, MageIdentifier.OnceOnYourTurnCastFromGraveyardEntersTapped));
|
||||
|
||||
// Tools -- Whenever Edgar attacks, it gets +X/+0 until end of turn, where X is the greatest mana value among artifacts you control.
|
||||
this.addAbility(new AttacksTriggeredAbility(
|
||||
new BoostSourceEffect(GreatestAmongPermanentsValue.MANAVALUE_CONTROLLED_ARTIFACTS, StaticValue.get(0), Duration.EndOfTurn, "it")
|
||||
).withFlavorWord("Tools").addHint(GreatestAmongPermanentsValue.MANAVALUE_CONTROLLED_ARTIFACTS.getHint()));
|
||||
}
|
||||
|
||||
private EdgarMasterMachinist(final EdgarMasterMachinist card) {
|
||||
super(card);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EdgarMasterMachinist copy() {
|
||||
return new EdgarMasterMachinist(this);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
package mage.cards.g;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.CastFromGraveyardOnceEachTurnAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceDuringEachOfYourTurnAbility;
|
||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||
import mage.abilities.effects.common.MillCardsControllerEffect;
|
||||
import mage.cards.CardImpl;
|
||||
|
|
@ -9,17 +9,18 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
*/
|
||||
public final class GisaAndGeralf extends CardImpl {
|
||||
|
||||
private static final FilterCreatureCard filter = new FilterCreatureCard("a Zombie creature spell");
|
||||
private static final FilterCard filter = new FilterCreatureCard("a Zombie creature spell");
|
||||
|
||||
static {
|
||||
filter.add(SubType.ZOMBIE.getPredicate());
|
||||
}
|
||||
|
|
@ -36,7 +37,7 @@ public final class GisaAndGeralf extends CardImpl {
|
|||
this.addAbility(new EntersBattlefieldTriggeredAbility(new MillCardsControllerEffect(4)));
|
||||
|
||||
// Once during each of your turns, you may cast a Zombie creature spell from your graveyard
|
||||
this.addAbility(new CastFromGraveyardOnceEachTurnAbility(filter));
|
||||
this.addAbility(new CastFromGraveyardOnceDuringEachOfYourTurnAbility(filter));
|
||||
}
|
||||
|
||||
private GisaAndGeralf(final GisaAndGeralf card) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
package mage.cards.h;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||
|
|
@ -13,27 +12,23 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
*/
|
||||
public final class HazoretsMonument extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("Red creature spells");
|
||||
private static final FilterSpell filter2 = new FilterSpell("a creature spell");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.and(new ColorPredicate(ObjectColor.RED), CardType.CREATURE.getPredicate()));
|
||||
}
|
||||
static {
|
||||
filter2.add(CardType.CREATURE.getPredicate());
|
||||
}
|
||||
|
||||
public HazoretsMonument(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
|
||||
|
|
@ -44,7 +39,10 @@ public final class HazoretsMonument extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1)));
|
||||
|
||||
// Whenever you cast a creature spell, you may discard a card. If you do, draw a card.
|
||||
this.addAbility(new SpellCastControllerTriggeredAbility(new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()), filter2, false));
|
||||
this.addAbility(new SpellCastControllerTriggeredAbility(
|
||||
new DoIfCostPaid(new DrawCardSourceControllerEffect(1), new DiscardCardCost()),
|
||||
StaticFilters.FILTER_SPELL_A_CREATURE, false
|
||||
));
|
||||
}
|
||||
|
||||
private HazoretsMonument(final HazoretsMonument card) {
|
||||
|
|
|
|||
|
|
@ -3,14 +3,13 @@ package mage.cards.k;
|
|||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceEachTurnAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceDuringEachOfYourTurnAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.effects.common.cost.CostModificationEffectImpl;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.*;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.game.Game;
|
||||
import mage.players.Player;
|
||||
import mage.util.CardUtil;
|
||||
|
|
@ -18,13 +17,10 @@ import mage.util.CardUtil;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author emerald000
|
||||
*/
|
||||
public final class KaradorGhostChieftain extends CardImpl {
|
||||
|
||||
private static final FilterCreatureCard filter = new FilterCreatureCard("a creature spell");
|
||||
|
||||
public KaradorGhostChieftain(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{W}{B}{G}");
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
|
|
@ -39,7 +35,7 @@ public final class KaradorGhostChieftain extends CardImpl {
|
|||
new KaradorGhostChieftainCostReductionEffect()));
|
||||
|
||||
// Once during each of your turns, you may cast a creature spell from your graveyard.
|
||||
this.addAbility(new CastFromGraveyardOnceEachTurnAbility(filter));
|
||||
this.addAbility(new CastFromGraveyardOnceDuringEachOfYourTurnAbility(StaticFilters.FILTER_CARD_A_CREATURE_SPELL));
|
||||
}
|
||||
|
||||
private KaradorGhostChieftain(final KaradorGhostChieftain card) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
package mage.cards.k;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
|
|
@ -12,26 +11,23 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.target.common.TargetCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
*/
|
||||
public final class KefnetsMonument extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("Blue creature spells");
|
||||
private static final FilterSpell filter2 = new FilterSpell("a creature spell");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.and(new ColorPredicate(ObjectColor.BLUE), CardType.CREATURE.getPredicate()));
|
||||
filter2.add(CardType.CREATURE.getPredicate());
|
||||
}
|
||||
|
||||
public KefnetsMonument(UUID ownerId, CardSetInfo setInfo) {
|
||||
|
|
@ -43,7 +39,10 @@ public final class KefnetsMonument extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1)));
|
||||
|
||||
// Whenever you cast a creature spell, target creature an opponent controls doesn't untap during its controller's next untap step.
|
||||
Ability ability = new SpellCastControllerTriggeredAbility(new DontUntapInControllersNextUntapStepTargetEffect(), filter2, false);
|
||||
Ability ability = new SpellCastControllerTriggeredAbility(
|
||||
new DontUntapInControllersNextUntapStepTargetEffect(),
|
||||
StaticFilters.FILTER_SPELL_A_CREATURE, false
|
||||
);
|
||||
ability.addTarget(new TargetCreaturePermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_CREATURE));
|
||||
this.addAbility(ability);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package mage.cards.k;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.CastFromGraveyardOnceEachTurnAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceDuringEachOfYourTurnAbility;
|
||||
import mage.abilities.common.EntersBattlefieldOneOrMoreTriggeredAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.common.ExileFromGraveCost;
|
||||
|
|
@ -12,7 +12,6 @@ import mage.constants.*;
|
|||
import mage.counters.CounterType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterCreatureCard;
|
||||
import mage.filter.predicate.mageobject.AnotherPredicate;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.ZoneChangeEvent;
|
||||
|
|
@ -23,21 +22,19 @@ import mage.target.common.TargetCardInYourGraveyard;
|
|||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jmlundeen
|
||||
*/
|
||||
public final class KotisSibsigChampion extends CardImpl {
|
||||
|
||||
private static final FilterCreatureCard filter = new FilterCreatureCard("a creature spell");
|
||||
private static final FilterCard filter2 = new FilterCard("other cards");
|
||||
private static final FilterCard filter = new FilterCard("other cards");
|
||||
|
||||
static {
|
||||
filter2.add(AnotherPredicate.instance);
|
||||
filter.add(AnotherPredicate.instance);
|
||||
}
|
||||
|
||||
public KotisSibsigChampion(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{B}{G}{U}");
|
||||
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.ZOMBIE);
|
||||
this.subtype.add(SubType.WARRIOR);
|
||||
|
|
@ -45,9 +42,9 @@ public final class KotisSibsigChampion extends CardImpl {
|
|||
this.toughness = new MageInt(3);
|
||||
|
||||
// Once during each of your turns, you may cast a creature spell from your graveyard by exiling three other cards from your graveyard in addition to paying its other costs.
|
||||
Cost cost = new ExileFromGraveCost(new TargetCardInYourGraveyard(3, filter2));
|
||||
Cost cost = new ExileFromGraveCost(new TargetCardInYourGraveyard(3, filter));
|
||||
cost.setText(cost.getText().replace("exile", "exiling"));
|
||||
this.addAbility(new CastFromGraveyardOnceEachTurnAbility(filter, cost));
|
||||
this.addAbility(new CastFromGraveyardOnceDuringEachOfYourTurnAbility(StaticFilters.FILTER_CARD_A_CREATURE_SPELL, cost));
|
||||
|
||||
// Whenever one or more creatures you control enter, if one or more of them entered from a graveyard or was cast from a graveyard, put two +1/+1 counters on Kotis.
|
||||
this.addAbility(new KotisSibsigTriggeredAbility());
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ package mage.cards.l;
|
|||
|
||||
import mage.MageInt;
|
||||
import mage.MageObject;
|
||||
import mage.abilities.common.CastFromGraveyardOnceEachTurnAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceDuringEachOfYourTurnAbility;
|
||||
import mage.abilities.keyword.CompanionAbility;
|
||||
import mage.abilities.keyword.CompanionCondition;
|
||||
import mage.abilities.keyword.LifelinkAbility;
|
||||
|
|
@ -13,8 +13,10 @@ import mage.constants.CardType;
|
|||
import mage.constants.ComparisonType;
|
||||
import mage.constants.SubType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.common.FilterPermanentCard;
|
||||
import mage.filter.predicate.mageobject.ManaValuePredicate;
|
||||
import mage.filter.predicate.mageobject.PermanentPredicate;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
|
@ -24,9 +26,10 @@ import java.util.UUID;
|
|||
*/
|
||||
public final class LurrusOfTheDreamDen extends CardImpl {
|
||||
|
||||
private static final FilterPermanentCard filter = new FilterPermanentCard("a permanent spell with mana value 2 or less");
|
||||
private static final FilterCard filter = new FilterPermanentCard("a permanent spell with mana value 2 or less");
|
||||
|
||||
static {
|
||||
filter.add(PermanentPredicate.instance);
|
||||
filter.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3));
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +49,7 @@ public final class LurrusOfTheDreamDen extends CardImpl {
|
|||
this.addAbility(LifelinkAbility.getInstance());
|
||||
|
||||
// During each of your turns, you may cast one permanent spell with converted mana cost 2 or less from your graveyard.
|
||||
this.addAbility(new CastFromGraveyardOnceEachTurnAbility(filter));
|
||||
this.addAbility(new CastFromGraveyardOnceDuringEachOfYourTurnAbility(filter));
|
||||
}
|
||||
|
||||
private LurrusOfTheDreamDen(final LurrusOfTheDreamDen card) {
|
||||
|
|
|
|||
|
|
@ -1,45 +1,38 @@
|
|||
package mage.cards.m;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.MageInt;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.MaxSpeedAbility;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||
import mage.abilities.common.delayed.CopyNextSpellDelayedTriggeredAbility;
|
||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||
import mage.abilities.dynamicvalue.DynamicValue;
|
||||
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
|
||||
import mage.abilities.effects.Effect;
|
||||
import mage.abilities.effects.common.CopyStackObjectEffect;
|
||||
import mage.abilities.effects.common.CopyTargetStackObjectEffect;
|
||||
import mage.abilities.effects.common.DoIfCostPaid;
|
||||
import mage.abilities.effects.common.continuous.SetBasePowerSourceEffect;
|
||||
import mage.constants.*;
|
||||
import mage.abilities.keyword.StartYourEnginesAbility;
|
||||
import mage.cards.CardImpl;
|
||||
import mage.cards.CardSetInfo;
|
||||
import mage.filter.FilterPermanent;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.common.FilterControlledPermanent;
|
||||
import mage.filter.common.FilterArtifactSpell;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Jmlundeen
|
||||
*/
|
||||
public final class MendicantCoreGuidelight extends CardImpl {
|
||||
|
||||
private static final FilterSpell filter = new FilterSpell("an artifact spell");
|
||||
private static final FilterSpell filter = new FilterArtifactSpell("an artifact spell");
|
||||
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACTS);
|
||||
|
||||
static {
|
||||
filter.add(CardType.ARTIFACT.getPredicate());
|
||||
}
|
||||
|
||||
public MendicantCoreGuidelight(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{W}{U}");
|
||||
|
||||
|
||||
this.supertype.add(SuperType.LEGENDARY);
|
||||
this.subtype.add(SubType.ROBOT);
|
||||
this.power = new MageInt(0);
|
||||
|
|
@ -53,7 +46,7 @@ public final class MendicantCoreGuidelight extends CardImpl {
|
|||
// Max speed -- Whenever you cast an artifact spell, you may pay {1}. If you do, copy it.
|
||||
Effect copyEffect = new CopyTargetStackObjectEffect(true)
|
||||
.setText("copy it. <i>(The copy becomes a token.)</i>");
|
||||
Effect doIfEffect = new DoIfCostPaid(copyEffect,new ManaCostsImpl<>("{1}"));
|
||||
Effect doIfEffect = new DoIfCostPaid(copyEffect, new ManaCostsImpl<>("{1}"));
|
||||
Ability ability = new SpellCastControllerTriggeredAbility(doIfEffect, filter, false, SetTargetPointer.SPELL);
|
||||
this.addAbility(new MaxSpeedAbility(ability));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
package mage.cards.o;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||
|
|
@ -11,28 +10,24 @@ import mage.cards.CardImpl;
|
|||
import mage.cards.CardSetInfo;
|
||||
import mage.constants.CardType;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.game.permanent.token.WarriorVigilantToken;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
*/
|
||||
public final class OketrasMonument extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("White creature spells");
|
||||
private static final FilterSpell filter2 = new FilterSpell("a creature spell");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.and(new ColorPredicate(ObjectColor.WHITE), CardType.CREATURE.getPredicate()));
|
||||
}
|
||||
static {
|
||||
filter2.add(CardType.CREATURE.getPredicate());
|
||||
}
|
||||
|
||||
public OketrasMonument(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
|
||||
|
|
@ -43,7 +38,10 @@ public final class OketrasMonument extends CardImpl {
|
|||
this.addAbility(new SimpleStaticAbility(new SpellsCostReductionControllerEffect(filter, 1)));
|
||||
|
||||
// Whenever you cast a creature spell, create a 1/1 white Warrior creature token with vigilance.
|
||||
this.addAbility(new SpellCastControllerTriggeredAbility(new CreateTokenEffect(new WarriorVigilantToken()), filter2, false));
|
||||
this.addAbility(new SpellCastControllerTriggeredAbility(
|
||||
new CreateTokenEffect(new WarriorVigilantToken()),
|
||||
StaticFilters.FILTER_SPELL_A_CREATURE, false
|
||||
));
|
||||
}
|
||||
|
||||
private OketrasMonument(final OketrasMonument card) {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package mage.cards.r;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.CastFromGraveyardOnceEachTurnAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceDuringEachOfYourTurnAbility;
|
||||
import mage.abilities.common.SimpleActivatedAbility;
|
||||
import mage.abilities.costs.common.TapSourceCost;
|
||||
import mage.abilities.effects.common.MillCardsEachPlayerEffect;
|
||||
|
|
@ -39,7 +39,7 @@ public final class RaulTroubleShooter extends CardImpl {
|
|||
this.toughness = new MageInt(4);
|
||||
|
||||
// Once during each of your turns, you may cast a spell from among cards in your graveyard that were milled this turn.
|
||||
this.addAbility(new CastFromGraveyardOnceEachTurnAbility(filter), new CardsMilledWatcher());
|
||||
this.addAbility(new CastFromGraveyardOnceDuringEachOfYourTurnAbility(filter), new CardsMilledWatcher());
|
||||
|
||||
// {T}: Each player mills a card.
|
||||
this.addAbility(new SimpleActivatedAbility(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
package mage.cards.r;
|
||||
|
||||
import java.util.UUID;
|
||||
import mage.ObjectColor;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.common.SimpleStaticAbility;
|
||||
|
|
@ -15,30 +14,25 @@ import mage.cards.CardSetInfo;
|
|||
import mage.constants.CardType;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.SuperType;
|
||||
import mage.constants.Zone;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.filter.FilterSpell;
|
||||
import mage.filter.StaticFilters;
|
||||
import mage.filter.predicate.Predicates;
|
||||
import mage.filter.predicate.mageobject.ColorPredicate;
|
||||
import mage.target.common.TargetControlledCreaturePermanent;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author fireshoes
|
||||
*/
|
||||
public final class RhonassMonument extends CardImpl {
|
||||
|
||||
private static final FilterCard filter = new FilterCard("Green creature spells");
|
||||
private static final FilterSpell filter2 = new FilterSpell("a creature spell");
|
||||
|
||||
static {
|
||||
filter.add(Predicates.and(new ColorPredicate(ObjectColor.GREEN), CardType.CREATURE.getPredicate()));
|
||||
}
|
||||
|
||||
static {
|
||||
filter2.add(CardType.CREATURE.getPredicate());
|
||||
}
|
||||
|
||||
public RhonassMonument(UUID ownerId, CardSetInfo setInfo) {
|
||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
|
||||
|
||||
|
|
@ -49,7 +43,7 @@ public final class RhonassMonument extends CardImpl {
|
|||
|
||||
// Whenever you cast a creature spell, target creature you control gets +2/+2 and gains trample until end of turn.
|
||||
Ability ability = new SpellCastControllerTriggeredAbility(new BoostTargetEffect(2, 2, Duration.EndOfTurn)
|
||||
.setText("target creature you control gets +2/+2"), filter2, false);
|
||||
.setText("target creature you control gets +2/+2"), StaticFilters.FILTER_SPELL_A_CREATURE, false);
|
||||
Effect effect = new GainAbilityTargetEffect(TrampleAbility.getInstance(), Duration.EndOfTurn);
|
||||
effect.setText("and gains trample until end of turn");
|
||||
ability.addEffect(effect);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package mage.cards.r;
|
||||
|
||||
import mage.MageInt;
|
||||
import mage.abilities.common.CastFromGraveyardOnceEachTurnAbility;
|
||||
import mage.abilities.common.CastFromGraveyardOnceDuringEachOfYourTurnAbility;
|
||||
import mage.abilities.common.DiesSourceTriggeredAbility;
|
||||
import mage.abilities.common.SpellCastControllerTriggeredAbility;
|
||||
import mage.abilities.effects.common.ExileSourceEffect;
|
||||
|
|
@ -50,7 +50,7 @@ public final class RivazOfTheClaw extends CardImpl {
|
|||
this.addAbility(new ConditionalAnyColorManaAbility(2, new ConditionalSpellManaBuilder(manaAbilityFilter)));
|
||||
|
||||
// Once during each of your turns, you may cast a Dragon creature spell from your graveyard.
|
||||
this.addAbility(new CastFromGraveyardOnceEachTurnAbility(staticAbilityFilter));
|
||||
this.addAbility(new CastFromGraveyardOnceDuringEachOfYourTurnAbility(staticAbilityFilter));
|
||||
|
||||
// Whenever you cast a Dragon creature spell from your graveyard, it gains "When this creature dies, exile it."
|
||||
this.addAbility(new SpellCastControllerTriggeredAbility(
|
||||
|
|
|
|||
|
|
@ -129,6 +129,8 @@ public final class FinalFantasyCommander extends ExpansionSet {
|
|||
cards.add(new SetCardInfo("Dragonskull Summit", 387, Rarity.RARE, mage.cards.d.DragonskullSummit.class));
|
||||
cards.add(new SetCardInfo("Drowned Catacomb", 388, Rarity.RARE, mage.cards.d.DrownedCatacomb.class));
|
||||
cards.add(new SetCardInfo("Duskshell Crawler", 301, Rarity.COMMON, mage.cards.d.DuskshellCrawler.class));
|
||||
cards.add(new SetCardInfo("Edgar, Master Machinist", 169, Rarity.RARE, mage.cards.e.EdgarMasterMachinist.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Edgar, Master Machinist", 80, Rarity.RARE, mage.cards.e.EdgarMasterMachinist.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Elena, Turk Recruit", 133, Rarity.RARE, mage.cards.e.ElenaTurkRecruit.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Elena, Turk Recruit", 18, Rarity.RARE, mage.cards.e.ElenaTurkRecruit.class, NON_FULL_USE_VARIOUS));
|
||||
cards.add(new SetCardInfo("Endless Detour", 324, Rarity.RARE, mage.cards.e.EndlessDetour.class));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,180 @@
|
|||
package org.mage.test.cards.single.fic;
|
||||
|
||||
import mage.constants.PhaseStep;
|
||||
import mage.constants.Zone;
|
||||
import org.junit.Test;
|
||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||
|
||||
/**
|
||||
* @author Susucr
|
||||
*/
|
||||
public class EdgarMasterMachinistTest extends CardTestPlayerBase {
|
||||
|
||||
/**
|
||||
* {@link mage.cards.e.EdgarMasterMachinist Edgar, Master Machinist} {2}{R}{W}
|
||||
* Legendary Creature — Human Artificer Noble
|
||||
* Once during each of your turns, you may cast an artifact spell from your graveyard. If you cast a spell this way, that artifact enters tapped.
|
||||
* Tools — Whenever Edgar attacks, it gets +X/+0 until end of turn, where X is the greatest mana value among artifacts you control.
|
||||
* 2/4
|
||||
*/
|
||||
private static final String edgar = "Edgar, Master Machinist";
|
||||
|
||||
@Test
|
||||
public void test_cast_from_yard() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, edgar);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 2);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Golgari Signet");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Elite Vanguard");
|
||||
|
||||
checkPlayableAbility("can not cast Elite Vanguard", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Elite Vanguard", false);
|
||||
checkPlayableAbility("can cast Golgari Signet", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Golgari Signet", true);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Golgari Signet");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Golgari Signet", 1);
|
||||
assertTappedCount("Plains", true, 2);
|
||||
assertTappedCount("Golgari Signet", true, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_tapped_effect_wait_for_cleanup() {
|
||||
// test to make sure the discarding of the "enters tapped effect" only happens when the spell leave the stack
|
||||
addCard(Zone.BATTLEFIELD, playerA, edgar);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 3);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Golgari Signet");
|
||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Golgari Signet");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", playerB);
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Golgari Signet", 1);
|
||||
assertTappedCount("Mountain", true, 3);
|
||||
assertTappedCount("Golgari Signet", true, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_cast_limits() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, edgar);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Golgari Signet");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Bear Trap"); // has flash
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerB, "Orzhov Signet");
|
||||
|
||||
checkPlayableAbility("can not cast opponent Orzhov Signet", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Orzhov Signet", false);
|
||||
checkPlayableAbility("can cast Golgari Signet", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Golgari Signet", true);
|
||||
checkPlayableAbility("can cast Bear Trap", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Bear Trap", true);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Golgari Signet");
|
||||
|
||||
checkPlayableAbility("can not cast 2 per turn", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Cast Bear Trap", false);
|
||||
|
||||
checkPlayableAbility("can not cast opponent Orzhov Signet", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Orzhov Signet", false);
|
||||
checkPlayableAbility("opp can not cast Orzhov Signet", 2, PhaseStep.PRECOMBAT_MAIN, playerB, "Cast Orzhov Signet", false);
|
||||
checkPlayableAbility("can not cast Bear Trap on opp turn", 2, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Bear Trap", false);
|
||||
|
||||
castSpell(3, PhaseStep.UPKEEP, playerA, "Bear Trap");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Golgari Signet", 1);
|
||||
assertPermanentCount(playerA, "Bear Trap", 1);
|
||||
assertTappedCount("Bear Trap", true, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_mdfc() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, edgar);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Halvar, God of Battle");
|
||||
|
||||
checkPlayableAbility("can not cast Halvar, God of Battle", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Halvar, God of Battle", false);
|
||||
checkPlayableAbility("can cast Sword of the Realms", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Sword of the Realms", true);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Sword of the Realms");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Sword of the Realms", 1);
|
||||
assertTappedCount("Plains", true, 2);
|
||||
assertTappedCount("Sword of the Realms", true, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_adventure() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, edgar);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Horn of Valhalla");
|
||||
|
||||
checkPlayableAbility("can not cast Ysgard's Call", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Ysgard's Call", false);
|
||||
checkPlayableAbility("can cast Horn of Valhalla", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Horn of Valhalla", true);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Horn of Valhalla");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Horn of Valhalla", 1);
|
||||
assertTappedCount("Plains", true, 2);
|
||||
assertTappedCount("Horn of Valhalla", true, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_remand_recast() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, edgar);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
|
||||
addCard(Zone.HAND, playerB, "Remand");
|
||||
|
||||
addCard(Zone.GRAVEYARD, playerA, "Golgari Signet");
|
||||
addCard(Zone.GRAVEYARD, playerA, "Elite Vanguard");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Golgari Signet");
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Remand", "Golgari Signet", "Golgari Signet");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Golgari Signet");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertPermanentCount(playerA, "Golgari Signet", 1);
|
||||
assertGraveyardCount(playerB, "Remand", 1);
|
||||
assertTappedCount("Plains", true, 4);
|
||||
assertTappedCount("Golgari Signet", false, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_blink() {
|
||||
addCard(Zone.BATTLEFIELD, playerA, edgar);
|
||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||
addCard(Zone.HAND, playerA, "Cloudshift", 1);
|
||||
addCard(Zone.GRAVEYARD, playerA, "Memnite");
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Memnite");
|
||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
||||
checkPermanentTapped("Memnite entered tapped", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Memnite", true, 1);
|
||||
|
||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cloudshift", "Memnite");
|
||||
|
||||
setStrictChooseMode(true);
|
||||
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||
execute();
|
||||
|
||||
assertGraveyardCount(playerA, "Cloudshift", 1);
|
||||
assertTappedCount("Memnite", false, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,8 @@ public enum MageIdentifier {
|
|||
// e.g. [[Johann, Apprentice Sorcerer]]
|
||||
// "Once each turn, you may cast an instant or sorcery spell from the top of your library."
|
||||
//
|
||||
CastFromGraveyardOnceWatcher,
|
||||
OnceOnYourTurnCastFromGraveyard,
|
||||
OnceOnYourTurnCastFromGraveyardEntersTapped,
|
||||
OnceEachTurnCastWatcher,
|
||||
HaukensInsightWatcher,
|
||||
IntrepidPaleontologistWatcher,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,190 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.MageIdentifier;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.Costs;
|
||||
import mage.abilities.costs.CostsImpl;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.abilities.effects.common.replacement.MorEnteringTappedEffect;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Once during each of your turns, you may cast... from your graveyard
|
||||
* <p>
|
||||
* See Lurrus of the Dream Den and Rivaz of the Claw
|
||||
*
|
||||
* @author weirddan455, Susucr
|
||||
*/
|
||||
public class CastFromGraveyardOnceDuringEachOfYourTurnAbility extends SimpleStaticAbility {
|
||||
|
||||
public CastFromGraveyardOnceDuringEachOfYourTurnAbility(FilterCard filter) {
|
||||
this(filter, (Cost) null);
|
||||
}
|
||||
|
||||
public CastFromGraveyardOnceDuringEachOfYourTurnAbility(FilterCard filter, Cost additionalCost) {
|
||||
this(filter, additionalCost, MageIdentifier.OnceOnYourTurnCastFromGraveyard);
|
||||
}
|
||||
|
||||
public CastFromGraveyardOnceDuringEachOfYourTurnAbility(FilterCard filter, MageIdentifier mageIdentifier) {
|
||||
this(filter, null, mageIdentifier);
|
||||
}
|
||||
|
||||
public CastFromGraveyardOnceDuringEachOfYourTurnAbility(FilterCard filter, Cost additionalCost, MageIdentifier mageIdentifier) {
|
||||
super(new CastFromGraveyardOnceEffect(filter, additionalCost, mageIdentifier));
|
||||
this.addWatcher(new CastFromGraveyardOnceWatcher());
|
||||
switch (mageIdentifier) {
|
||||
case OnceOnYourTurnCastFromGraveyard:
|
||||
case OnceOnYourTurnCastFromGraveyardEntersTapped:
|
||||
this.setIdentifier(mageIdentifier);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Wrong code usage: only specific MageIdentifier are currently supported");
|
||||
}
|
||||
}
|
||||
|
||||
private CastFromGraveyardOnceDuringEachOfYourTurnAbility(final CastFromGraveyardOnceDuringEachOfYourTurnAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastFromGraveyardOnceDuringEachOfYourTurnAbility copy() {
|
||||
return new CastFromGraveyardOnceDuringEachOfYourTurnAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
class CastFromGraveyardOnceEffect extends AsThoughEffectImpl {
|
||||
|
||||
private final FilterCard filter;
|
||||
private final Cost additionalCost;
|
||||
private final MageIdentifier mageIdentifier;
|
||||
|
||||
CastFromGraveyardOnceEffect(FilterCard filter, Cost additionalCost, MageIdentifier mageIdentifier) {
|
||||
super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||
this.filter = filter;
|
||||
this.staticText = "Once during each of your turns, you may cast " + filter.getMessage()
|
||||
+ (filter.getMessage().contains("your graveyard") ? "" : " from your graveyard")
|
||||
+ (additionalCost == null ? "" : " by " + additionalCost.getText() + " in addition to paying its other costs.");
|
||||
this.additionalCost = additionalCost;
|
||||
this.mageIdentifier = mageIdentifier;
|
||||
}
|
||||
|
||||
private CastFromGraveyardOnceEffect(final CastFromGraveyardOnceEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
this.additionalCost = effect.additionalCost;
|
||||
this.mageIdentifier = effect.mageIdentifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastFromGraveyardOnceEffect copy() {
|
||||
return new CastFromGraveyardOnceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
throw new IllegalArgumentException("Wrong code usage: can't call applies method on empty affectedAbility");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
|
||||
CastFromGraveyardOnceWatcher watcher = game.getState().getWatcher(CastFromGraveyardOnceWatcher.class);
|
||||
Card cardToCast = game.getCard(objectId);
|
||||
if (controller == null || sourcePermanent == null || watcher == null || cardToCast == null
|
||||
|| !game.isActivePlayer(playerId) // only during your turn
|
||||
|| !source.isControlledBy(playerId) // only you may cast
|
||||
|| !Zone.GRAVEYARD.equals(game.getState().getZone(objectId)) // from graveyard
|
||||
|| !cardToCast.getOwnerId().equals(playerId) // only your graveyard
|
||||
|| !(affectedAbility instanceof SpellAbility) // characteristics to check
|
||||
|| watcher.abilityUsed(new MageObjectReference(sourcePermanent, game)) // once per turn
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
SpellAbility spellAbility = (SpellAbility) affectedAbility;
|
||||
Card cardToCheck = spellAbility.getCharacteristics(game);
|
||||
if (spellAbility.getManaCosts().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Set<MageIdentifier> allowedToBeCastNow = spellAbility.spellCanBeActivatedNow(playerId, game);
|
||||
if (!allowedToBeCastNow.contains(MageIdentifier.Default)
|
||||
|| !filter.match(cardToCheck, playerId, source, game)) {
|
||||
return false;
|
||||
}
|
||||
if (additionalCost != null) {
|
||||
Costs<Cost> costs = new CostsImpl<>();
|
||||
costs.add(additionalCost);
|
||||
controller.setCastSourceIdWithAlternateMana(
|
||||
objectId, spellAbility.getManaCosts(),
|
||||
costs, mageIdentifier);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
class CastFromGraveyardOnceWatcher extends Watcher {
|
||||
|
||||
// TODO: we might want to store (approver, approving ability) instead on the odd chance there
|
||||
// is more than one such ability on a given approver. (event.getApprovingObject() has
|
||||
// the exact ability, but not sure its id is stable enough.)
|
||||
// Set of each approver that approved casting a spell this turn (and is thus done for the turn)
|
||||
private final Set<MageObjectReference> usedFrom = new HashSet<>();
|
||||
|
||||
CastFromGraveyardOnceWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (!GameEvent.EventType.SPELL_CAST.equals(event.getType())) {
|
||||
return;
|
||||
}
|
||||
if (event.hasApprovingIdentifier(MageIdentifier.OnceOnYourTurnCastFromGraveyard)) {
|
||||
usedFrom.add(event.getApprovingObject().getApprovingMageObjectReference());
|
||||
return;
|
||||
}
|
||||
if (event.hasApprovingIdentifier(MageIdentifier.OnceOnYourTurnCastFromGraveyardEntersTapped)) {
|
||||
usedFrom.add(event.getApprovingObject().getApprovingMageObjectReference());
|
||||
// The cast (most likely permanent) spell enters the battlefield tapped.
|
||||
Spell target = game.getSpell(event.getTargetId());
|
||||
if (target != null) {
|
||||
MageObjectReference mor = new MageObjectReference(target, game);
|
||||
game.getState().addEffect(
|
||||
new MorEnteringTappedEffect(mor),
|
||||
event.getApprovingObject().getApprovingAbility() // ability that approved the cast is the source of the tapping.
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
usedFrom.clear();
|
||||
}
|
||||
|
||||
boolean abilityUsed(MageObjectReference mor) {
|
||||
return usedFrom.contains(mor);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,150 +0,0 @@
|
|||
package mage.abilities.common;
|
||||
|
||||
import mage.MageIdentifier;
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.SpellAbility;
|
||||
import mage.abilities.costs.Cost;
|
||||
import mage.abilities.costs.Costs;
|
||||
import mage.abilities.costs.CostsImpl;
|
||||
import mage.abilities.effects.AsThoughEffectImpl;
|
||||
import mage.cards.Card;
|
||||
import mage.constants.*;
|
||||
import mage.filter.FilterCard;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.players.Player;
|
||||
import mage.watchers.Watcher;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Once during each of your turns, you may cast... from your graveyard
|
||||
* <p>
|
||||
* See Lurrus of the Dream Den and Rivaz of the Claw
|
||||
*
|
||||
* @author weirddan455
|
||||
*/
|
||||
public class CastFromGraveyardOnceEachTurnAbility extends SimpleStaticAbility {
|
||||
|
||||
public CastFromGraveyardOnceEachTurnAbility(FilterCard filter) {
|
||||
this(filter, null);
|
||||
}
|
||||
|
||||
public CastFromGraveyardOnceEachTurnAbility(FilterCard filter, Cost additionalCost) {
|
||||
super(new CastFromGraveyardOnceEffect(filter, additionalCost));
|
||||
this.addWatcher(new CastFromGraveyardOnceWatcher());
|
||||
this.setIdentifier(MageIdentifier.CastFromGraveyardOnceWatcher);
|
||||
}
|
||||
|
||||
private CastFromGraveyardOnceEachTurnAbility(final CastFromGraveyardOnceEachTurnAbility ability) {
|
||||
super(ability);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastFromGraveyardOnceEachTurnAbility copy() {
|
||||
return new CastFromGraveyardOnceEachTurnAbility(this);
|
||||
}
|
||||
}
|
||||
|
||||
class CastFromGraveyardOnceEffect extends AsThoughEffectImpl {
|
||||
|
||||
private final FilterCard filter;
|
||||
private final Cost additionalCost;
|
||||
|
||||
CastFromGraveyardOnceEffect(FilterCard filter, Cost additionalCost) {
|
||||
super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit);
|
||||
this.filter = filter;
|
||||
this.staticText = "Once during each of your turns, you may cast " + filter.getMessage()
|
||||
+ (filter.getMessage().contains("your graveyard") ? "" : " from your graveyard")
|
||||
+ (additionalCost == null ? "" : " by " + additionalCost.getText() + " in addition to paying its other costs.");
|
||||
this.additionalCost = additionalCost;
|
||||
}
|
||||
|
||||
private CastFromGraveyardOnceEffect(final CastFromGraveyardOnceEffect effect) {
|
||||
super(effect);
|
||||
this.filter = effect.filter;
|
||||
this.additionalCost = effect.additionalCost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CastFromGraveyardOnceEffect copy() {
|
||||
return new CastFromGraveyardOnceEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean apply(Game game, Ability source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||
throw new IllegalArgumentException("Wrong code usage: can't call applies method on empty affectedAbility");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) {
|
||||
Player controller = game.getPlayer(source.getControllerId());
|
||||
Permanent sourcePermanent = source.getSourcePermanentIfItStillExists(game);
|
||||
CastFromGraveyardOnceWatcher watcher = game.getState().getWatcher(CastFromGraveyardOnceWatcher.class);
|
||||
Card cardToCast = game.getCard(objectId);
|
||||
if (controller == null || sourcePermanent == null || watcher == null || cardToCast == null) {
|
||||
return false;
|
||||
}
|
||||
if (game.isActivePlayer(playerId) // only during your turn
|
||||
&& source.isControlledBy(playerId) // only you may cast
|
||||
&& Zone.GRAVEYARD.equals(game.getState().getZone(objectId)) // from graveyard
|
||||
&& cardToCast.getOwnerId().equals(playerId) // only your graveyard
|
||||
&& affectedAbility instanceof SpellAbility // characteristics to check
|
||||
&& watcher.abilityNotUsed(new MageObjectReference(sourcePermanent, game)) // once per turn
|
||||
) {
|
||||
SpellAbility spellAbility = (SpellAbility) affectedAbility;
|
||||
Card cardToCheck = spellAbility.getCharacteristics(game);
|
||||
if (spellAbility.getManaCosts().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
Set<MageIdentifier> allowedToBeCastNow = spellAbility.spellCanBeActivatedNow(playerId, game);
|
||||
if (allowedToBeCastNow.contains(MageIdentifier.Default)) {
|
||||
boolean matched = filter.match(cardToCheck, playerId, source, game);
|
||||
if (matched && additionalCost != null) {
|
||||
Costs<Cost> costs = new CostsImpl<>();
|
||||
costs.add(additionalCost);
|
||||
controller.setCastSourceIdWithAlternateMana(objectId, spellAbility.getManaCosts(),
|
||||
costs, MageIdentifier.CastFromGraveyardOnceWatcher);
|
||||
}
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class CastFromGraveyardOnceWatcher extends Watcher {
|
||||
|
||||
private final Set<MageObjectReference> usedFrom = new HashSet<>();
|
||||
|
||||
CastFromGraveyardOnceWatcher() {
|
||||
super(WatcherScope.GAME);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void watch(GameEvent event, Game game) {
|
||||
if (GameEvent.EventType.SPELL_CAST.equals(event.getType())
|
||||
&& event.hasApprovingIdentifier(MageIdentifier.CastFromGraveyardOnceWatcher)) {
|
||||
usedFrom.add(event.getApprovingObject().getApprovingMageObjectReference());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
usedFrom.clear();
|
||||
}
|
||||
|
||||
boolean abilityNotUsed(MageObjectReference mor) {
|
||||
return !usedFrom.contains(mor);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package mage.abilities.effects.common.replacement;
|
||||
|
||||
import mage.MageObjectReference;
|
||||
import mage.abilities.Ability;
|
||||
import mage.abilities.effects.ReplacementEffectImpl;
|
||||
import mage.constants.Duration;
|
||||
import mage.constants.Outcome;
|
||||
import mage.game.Game;
|
||||
import mage.game.events.EntersTheBattlefieldEvent;
|
||||
import mage.game.events.GameEvent;
|
||||
import mage.game.permanent.Permanent;
|
||||
import mage.game.stack.Spell;
|
||||
|
||||
/**
|
||||
* Used to affect a spell on the stack.
|
||||
* The permanent it may become enters tapped.
|
||||
* <p>
|
||||
* Short-lived replacement effect, auto-cleanup if the mor is no longer a spell.
|
||||
*
|
||||
* @author Susucr
|
||||
*/
|
||||
public class MorEnteringTappedEffect extends ReplacementEffectImpl {
|
||||
|
||||
private final MageObjectReference mor;
|
||||
|
||||
public MorEnteringTappedEffect(MageObjectReference mor) {
|
||||
super(Duration.OneUse, Outcome.Tap);
|
||||
this.staticText = "That permanent enters the battlefield tapped";
|
||||
this.mor = mor;
|
||||
}
|
||||
|
||||
private MorEnteringTappedEffect(final MorEnteringTappedEffect effect) {
|
||||
super(effect);
|
||||
this.mor = effect.mor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MorEnteringTappedEffect copy() {
|
||||
return new MorEnteringTappedEffect(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checksEventType(GameEvent event, Game game) {
|
||||
return event.getType() == GameEvent.EventType.ENTERS_THE_BATTLEFIELD;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||
Spell spell = game.getSpell(event.getSourceId());
|
||||
Spell morSpell = mor.getSpell(game);
|
||||
if (morSpell == null) {
|
||||
// cleanup if something other than resolving happens to the spell.
|
||||
discard();
|
||||
return false;
|
||||
}
|
||||
return spell != null
|
||||
&& morSpell.getSourceId() == spell.getSourceId()
|
||||
&& morSpell.getZoneChangeCounter(game) == spell.getZoneChangeCounter(game);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
|
||||
Permanent permanent = ((EntersTheBattlefieldEvent) event).getTarget();
|
||||
if (permanent != null) {
|
||||
permanent.setTapped(true);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -97,6 +97,13 @@ public final class StaticFilters {
|
|||
FILTER_CARD_CREATURE_A.setLockedFilter(true);
|
||||
}
|
||||
|
||||
// for checks on cards to be cast as "a creature spell", this is a FilterCard, but the text is about spell
|
||||
public static final FilterCreatureCard FILTER_CARD_A_CREATURE_SPELL = new FilterCreatureCard("a creature spell");
|
||||
|
||||
static {
|
||||
FILTER_CARD_A_CREATURE_SPELL.setLockedFilter(true);
|
||||
}
|
||||
|
||||
public static final FilterCreatureCard FILTER_CARD_CREATURE_YOUR_HAND = new FilterCreatureCard("a creature card from your hand");
|
||||
|
||||
static {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue