Merge pull request 'master' (#32) from External/mage:master into master
All checks were successful
/ build_release (push) Successful in 18m46s

Reviewed-on: #32
This commit is contained in:
Failure 2025-07-29 09:22:26 -07:00
commit 4dc034f98c
108 changed files with 2152 additions and 1460 deletions

View file

@ -1,10 +1,10 @@
package org.mage.plugins.card.dl.sources; package org.mage.plugins.card.dl.sources;
import mage.cards.repository.TokenRepository;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import mage.cards.repository.TokenRepository;
/** /**
* @author JayDi85 * @author JayDi85
*/ */
@ -2787,6 +2787,7 @@ public class ScryfallImageSupportTokens {
// EOE // EOE
put("EOE/Drone", "https://api.scryfall.com/cards/teoe/3?format=image"); put("EOE/Drone", "https://api.scryfall.com/cards/teoe/3?format=image");
put("EOE/Emblem Tezzeret", "https://api.scryfall.com/cards/teoe/11?format=image");
put("EOE/Human Soldier", "https://api.scryfall.com/cards/teoe/2?format=image"); put("EOE/Human Soldier", "https://api.scryfall.com/cards/teoe/2?format=image");
put("EOE/Lander/1", "https://api.scryfall.com/cards/teoe/4?format=image"); put("EOE/Lander/1", "https://api.scryfall.com/cards/teoe/4?format=image");
put("EOE/Lander/2", "https://api.scryfall.com/cards/teoe/5?format=image"); put("EOE/Lander/2", "https://api.scryfall.com/cards/teoe/5?format=image");

View file

@ -13,10 +13,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard;
import mage.filter.common.FilterLandPermanent; import mage.filter.common.FilterLandPermanent;
import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate; import mage.filter.predicate.permanent.DefendingPlayerControlsSourceAttackingPredicate;
import mage.game.Controllable; import mage.game.Controllable;
@ -32,8 +30,6 @@ import java.util.stream.Collectors;
*/ */
public final class AerialSurveyor extends CardImpl { public final class AerialSurveyor extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard(SubType.PLAINS);
public AerialSurveyor(UUID ownerId, CardSetInfo setInfo) { public AerialSurveyor(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{W}");
@ -45,7 +41,7 @@ public final class AerialSurveyor extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Whenever Aerial Surveyor attacks, if defending player controls more lands than you, search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle. // Whenever Aerial Surveyor attacks, if defending player controls more lands than you, search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle.
this.addAbility(new AttacksTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true)) this.addAbility(new AttacksTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true))
.withInterveningIf(AerialSurveyorCondition.instance) .withInterveningIf(AerialSurveyorCondition.instance)
.addHint(LandsYouControlHint.instance) .addHint(LandsYouControlHint.instance)
.addHint(AerialSurveyorHint.instance)); .addHint(AerialSurveyorHint.instance));

View file

@ -13,7 +13,6 @@ import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterBySubtypeCard;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -24,7 +23,7 @@ import java.util.UUID;
*/ */
public final class AlpineGuide extends CardImpl { public final class AlpineGuide extends CardImpl {
private static final FilterCard filter = new FilterBySubtypeCard(SubType.MOUNTAIN); private static final FilterCard filter = new FilterCard(SubType.MOUNTAIN);
private static final FilterPermanent filter2 = new FilterControlledPermanent(SubType.MOUNTAIN, "Mountain"); private static final FilterPermanent filter2 = new FilterControlledPermanent(SubType.MOUNTAIN, "Mountain");
public AlpineGuide(UUID ownerId, CardSetInfo setInfo) { public AlpineGuide(UUID ownerId, CardSetInfo setInfo) {

View file

@ -14,8 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.AbilityWord; import mage.constants.AbilityWord;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.filter.StaticFilters;
import mage.filter.FilterCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -25,13 +24,6 @@ import java.util.UUID;
*/ */
public final class AmbitiousFarmhand extends CardImpl { public final class AmbitiousFarmhand extends CardImpl {
private static final FilterCard filter = new FilterCard("basic Plains card");
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.PLAINS.getPredicate());
}
public AmbitiousFarmhand(UUID ownerId, CardSetInfo setInfo) { public AmbitiousFarmhand(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
@ -43,7 +35,7 @@ public final class AmbitiousFarmhand extends CardImpl {
// When Ambitious Farmhand enters the battlefield, you may search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. // When Ambitious Farmhand enters the battlefield, you may search your library for a basic Plains card, reveal it, put it into your hand, then shuffle.
this.addAbility(new EntersBattlefieldTriggeredAbility( this.addAbility(new EntersBattlefieldTriggeredAbility(
new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), true new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true), true
)); ));
// Coven{1}{W}{W}: Transform Ambitious Farmhand. Activate only if you control three or more creatures with different powers. // Coven{1}{W}{W}: Transform Ambitious Farmhand. Activate only if you control three or more creatures with different powers.

View file

@ -0,0 +1,89 @@
package mage.cards.a;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.common.CastFromEverywhereSourceCondition;
import mage.abilities.effects.PreventionEffectImpl;
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
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.counters.CounterType;
import mage.filter.StaticFilters;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.permanent.Permanent;
import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class AntiVenomHorrifyingHealer extends CardImpl {
public AntiVenomHorrifyingHealer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}{W}{W}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SYMBIOTE);
this.subtype.add(SubType.HERO);
this.power = new MageInt(5);
this.toughness = new MageInt(5);
// When Anti-Venom enters, if he was cast, return target creature card from your graveyard to the battlefield.
Ability ability = new EntersBattlefieldTriggeredAbility(new ReturnFromGraveyardToBattlefieldTargetEffect())
.withInterveningIf(CastFromEverywhereSourceCondition.instance);
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
this.addAbility(ability);
// If damage would be dealt to Anti-Venom, prevent that damage and put that many +1/+1 counters on him.
this.addAbility(new SimpleStaticAbility(new AntiVenomHorrifyingHealerEffect()));
}
private AntiVenomHorrifyingHealer(final AntiVenomHorrifyingHealer card) {
super(card);
}
@Override
public AntiVenomHorrifyingHealer copy() {
return new AntiVenomHorrifyingHealer(this);
}
}
class AntiVenomHorrifyingHealerEffect extends PreventionEffectImpl {
AntiVenomHorrifyingHealerEffect() {
super(Duration.WhileOnBattlefield, Integer.MAX_VALUE, false, false);
staticText = "if damage would be dealt to {this}, prevent that damage and put that many +1/+1 counters on him";
}
private AntiVenomHorrifyingHealerEffect(final AntiVenomHorrifyingHealerEffect effect) {
super(effect);
}
@Override
public AntiVenomHorrifyingHealerEffect copy() {
return new AntiVenomHorrifyingHealerEffect(this);
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
return super.applies(event, source, game)
&& event.getTargetId().equals(source.getSourceId());
}
@Override
public boolean replaceEvent(GameEvent event, Ability source, Game game) {
Permanent permanent = game.getPermanent(source.getSourceId());
if (permanent != null) {
permanent.addCounters(CounterType.P1P1.createInstance(event.getAmount()), source.getControllerId(), source, game);
}
return super.replaceEvent(event, source, game);
}
}

View file

@ -9,10 +9,7 @@ import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterLandPermanent; import mage.filter.common.FilterLandPermanent;
@ -26,13 +23,10 @@ import java.util.UUID;
*/ */
public final class ArchaeomancersMap extends CardImpl { public final class ArchaeomancersMap extends CardImpl {
private static final FilterCard filter = new FilterCard("basic Plains cards"); private static final FilterPermanent filter = new FilterLandPermanent("a land an opponent controls");
private static final FilterPermanent filter2 = new FilterLandPermanent("a land an opponent controls");
static { static {
filter.add(SubType.PLAINS.getPredicate()); filter.add(TargetController.OPPONENT.getControllerPredicate());
filter.add(SuperType.BASIC.getPredicate());
filter2.add(TargetController.OPPONENT.getControllerPredicate());
} }
public ArchaeomancersMap(UUID ownerId, CardSetInfo setInfo) { public ArchaeomancersMap(UUID ownerId, CardSetInfo setInfo) {
@ -40,12 +34,12 @@ public final class ArchaeomancersMap extends CardImpl {
// When Archaeomancer's Map enters the battlefield, search your library for up to two basic Plains cards, reveal them, put them into your hand, then shuffle. // When Archaeomancer's Map enters the battlefield, search your library for up to two basic Plains cards, reveal them, put them into your hand, then shuffle.
this.addAbility(new EntersBattlefieldTriggeredAbility( this.addAbility(new EntersBattlefieldTriggeredAbility(
new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 2, filter), true) new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_PLAINS), true)
)); ));
// Whenever a land enters the battlefield under an opponent's control, if that player controls more lands than you, you may put a land card from your hand onto the battlefield. // Whenever a land enters the battlefield under an opponent's control, if that player controls more lands than you, you may put a land card from your hand onto the battlefield.
this.addAbility(new EntersBattlefieldAllTriggeredAbility( this.addAbility(new EntersBattlefieldAllTriggeredAbility(
new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A), filter2 new PutCardFromHandOntoBattlefieldEffect(StaticFilters.FILTER_CARD_LAND_A), filter
).withInterveningIf(ArchaeomancersMapCondition.instance)); ).withInterveningIf(ArchaeomancersMapCondition.instance));
} }

View file

@ -18,7 +18,7 @@ import mage.cards.CardSetInfo;
import mage.constants.AttachmentType; import mage.constants.AttachmentType;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.common.FilterBySubtypeCard; import mage.filter.FilterCard;
import mage.game.Game; import mage.game.Game;
import mage.util.CardUtil; import mage.util.CardUtil;
@ -30,6 +30,8 @@ import java.util.UUID;
*/ */
public final class ArmMountedAnchor extends CardImpl { public final class ArmMountedAnchor extends CardImpl {
private static final FilterCard filter = new FilterCard(SubType.PIRATE);
public ArmMountedAnchor(UUID ownerId, CardSetInfo setInfo) { public ArmMountedAnchor(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}");
this.subtype.add(SubType.EQUIPMENT); this.subtype.add(SubType.EQUIPMENT);
@ -42,11 +44,12 @@ public final class ArmMountedAnchor extends CardImpl {
this.addAbility(firstAbility); this.addAbility(firstAbility);
// Whenever equipped creature deals combat damage to a player, draw two cards. Then discard two cards unless you discard a Pirate card. // Whenever equipped creature deals combat damage to a player, draw two cards. Then discard two cards unless you discard a Pirate card.
Ability drawAbility = new DealsDamageToAPlayerAttachedTriggeredAbility(new DrawCardSourceControllerEffect(2), "equipped creature", false); Ability drawAbility = new DealsDamageToAPlayerAttachedTriggeredAbility(
DiscardCardCost cost = new DiscardCardCost(new FilterBySubtypeCard(SubType.PIRATE)); new DrawCardSourceControllerEffect(2), "equipped creature", false
cost.setText("Discard a Pirate card instead of discarding two cards"); );
drawAbility.addEffect(new DoIfCostPaid( drawAbility.addEffect(new DoIfCostPaid(
null, new DiscardControllerEffect(2), cost null, new DiscardControllerEffect(2),
new DiscardCardCost(filter).setText("Discard a Pirate card instead of discarding two cards")
).setText("Then discard two cards unless you discard a Pirate card")); ).setText("Then discard two cards unless you discard a Pirate card"));
this.addAbility(drawAbility); this.addAbility(drawAbility);

View file

@ -1,7 +1,6 @@
package mage.cards.a; package mage.cards.a;
import java.util.UUID;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.common.AttachEffect; import mage.abilities.effects.common.AttachEffect;
import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect; import mage.abilities.effects.common.continuous.GainAbilityAttachedEffect;
@ -9,11 +8,16 @@ import mage.abilities.keyword.EnchantAbility;
import mage.abilities.keyword.ProtectionAbility; import mage.abilities.keyword.ProtectionAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.AttachmentType;
import mage.constants.CardType;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.filter.common.FilterArtifactCard; import mage.filter.common.FilterArtifactCard;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/** /**
* *
* @author MarcoMarin * @author MarcoMarin
@ -33,7 +37,7 @@ public final class ArtifactWard extends CardImpl {
// Enchanted creature can't be blocked by artifact creatures. // Enchanted creature can't be blocked by artifact creatures.
// Prevent all damage that would be dealt to enchanted creature by artifact sources. // Prevent all damage that would be dealt to enchanted creature by artifact sources.
// Enchanted creature can't be the target of abilities from artifact sources. // Enchanted creature can't be the target of abilities from artifact sources.
this.addAbility(new SimpleStaticAbility( this.addAbility(new SimpleStaticAbility( // TODO: Implement as separate abilities, this isn't quite the same as "Enchanted creature gains protection from artifacts"
new GainAbilityAttachedEffect(new ProtectionAbility(new FilterArtifactCard("artifacts")), AttachmentType.AURA))); new GainAbilityAttachedEffect(new ProtectionAbility(new FilterArtifactCard("artifacts")), AttachmentType.AURA)));
} }

View file

@ -1,7 +1,5 @@
package mage.cards.b; package mage.cards.b;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
@ -11,11 +9,15 @@ import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
* @author North * @author North
*/ */
@ -24,7 +26,6 @@ public final class BantPanorama extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Forest, Plains, or Island card"); private static final FilterCard filter = new FilterCard("a basic Forest, Plains, or Island card");
static { static {
filter.add(CardType.LAND.getPredicate());
filter.add(SuperType.BASIC.getPredicate()); filter.add(SuperType.BASIC.getPredicate());
filter.add(Predicates.or( filter.add(Predicates.or(
SubType.FOREST.getPredicate(), SubType.FOREST.getPredicate(),

View file

@ -13,7 +13,6 @@ import mage.constants.SagaChapter;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBySubtypeCard;
import mage.target.TargetPermanent; import mage.target.TargetPermanent;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -24,7 +23,7 @@ import java.util.UUID;
*/ */
public final class BindingTheOldGods extends CardImpl { public final class BindingTheOldGods extends CardImpl {
private static final FilterCard filter = new FilterBySubtypeCard(SubType.FOREST); private static final FilterCard filter = new FilterCard(SubType.FOREST);
public BindingTheOldGods(UUID ownerId, CardSetInfo setInfo) { public BindingTheOldGods(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{G}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{B}{G}");
@ -33,15 +32,18 @@ public final class BindingTheOldGods extends CardImpl {
// (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.) // (As this Saga enters and after your draw step, add a lore counter. Sacrifice after III.)
SagaAbility sagaAbility = new SagaAbility(this); SagaAbility sagaAbility = new SagaAbility(this);
// I Destroy target nonland permanent an opponent controls. // I Destroy target nonland permanent an opponent controls.
sagaAbility.addChapterEffect( sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I, this, SagaChapter.CHAPTER_I, SagaChapter.CHAPTER_I,
new DestroyTargetEffect(), new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_NON_LAND) new DestroyTargetEffect(), new TargetPermanent(StaticFilters.FILTER_OPPONENTS_PERMANENT_NON_LAND)
); );
// II Search your library for a Forest card, put it onto the battlefield tapped, then shuffle your library. // II Search your library for a Forest card, put it onto the battlefield tapped, then shuffle your library.
sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II,
new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true) new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true)
); );
// III Creatures you control gain deathtouch until end of turn. // III Creatures you control gain deathtouch until end of turn.
sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III,
new GainAbilityControlledEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn, new GainAbilityControlledEffect(DeathtouchAbility.getInstance(), Duration.EndOfTurn,

View file

@ -51,7 +51,7 @@ public final class Blink extends CardImpl {
this, SagaChapter.CHAPTER_IV, this, SagaChapter.CHAPTER_IV,
new CreateTokenEffect(new AlienAngelToken()) new CreateTokenEffect(new AlienAngelToken())
); );
this.addAbility(sagaAbility); this.addAbility(sagaAbility); //TODO: These should be a single AddChapterEffect, but currently XMage does not support noncontiguous Saga chapters
} }
private Blink(final Blink card) { private Blink(final Blink card) {

View file

@ -2,7 +2,6 @@ package mage.cards.b;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.condition.common.YouGainedLifeCondition; import mage.abilities.condition.common.YouGainedLifeCondition;
@ -12,10 +11,14 @@ import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect;
import mage.abilities.hint.ConditionHint; import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.Hint; import mage.abilities.hint.Hint;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TargetController;
import mage.game.permanent.token.BloodToken; import mage.game.permanent.token.BloodToken;
import mage.watchers.common.PlayerGainedLifeWatcher;
import java.util.UUID; import java.util.UUID;
@ -40,7 +43,7 @@ public final class BloodsoakedReveler extends CardImpl {
this.addAbility(new BeginningOfEndStepTriggeredAbility( this.addAbility(new BeginningOfEndStepTriggeredAbility(
TargetController.YOU, new CreateTokenEffect(new BloodToken()), TargetController.YOU, new CreateTokenEffect(new BloodToken()),
false, condition false, condition
).addHint(hint)); ).addHint(hint), new PlayerGainedLifeWatcher());
// {4}{B}: Each opponent loses 2 life and you gain 2 life. // {4}{B}: Each opponent loses 2 life and you gain 2 life.
Ability ability = new SimpleActivatedAbility( Ability ability = new SimpleActivatedAbility(

View file

@ -1,36 +1,27 @@
package mage.cards.b; package mage.cards.b;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility; import mage.abilities.common.EntersBattlefieldThisOrAnotherTriggeredAbility;
import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.search.SearchLibraryPutOntoBattlefieldTappedRestInHandEffect; import mage.abilities.effects.common.search.SearchLibraryPutOntoBattlefieldTappedRestInHandEffect;
import mage.cards.OmenCard;
import mage.constants.SubType;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.OmenCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SuperType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.common.FilterControlledCreaturePermanent;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterCreaturePermanent;
import mage.target.Target;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
*
* @author Jmlundeen * @author Jmlundeen
*/ */
public final class BloomvineRegent extends OmenCard { public final class BloomvineRegent extends OmenCard {
private static final FilterCard filter = new FilterCard("basic Forest cards"); private static final FilterCard filter = new FilterBasicCard(SubType.FOREST, "basic Forest cards");
static {
filter.add(SubType.FOREST.getPredicate());
filter.add(SuperType.BASIC.getPredicate());
}
public BloomvineRegent(UUID ownerId, CardSetInfo setInfo) { public BloomvineRegent(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{3}{G}{G}", "Claim Territory", "{2}{G}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, new CardType[]{CardType.SORCERY}, "{3}{G}{G}", "Claim Territory", "{2}{G}");

View file

@ -4,18 +4,14 @@ import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.CastSecondSpellTriggeredAbility; import mage.abilities.common.CastSecondSpellTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.combat.GoadTargetEffect; import mage.abilities.effects.common.combat.GoadTargetEffect;
import mage.abilities.keyword.ForetellAbility; import mage.abilities.keyword.ForetellAbility;
import mage.cards.*; import mage.cards.CardImpl;
import mage.constants.*; import mage.cards.CardSetInfo;
import mage.filter.common.FilterNonlandCard; import mage.constants.CardType;
import mage.filter.predicate.Predicates; import mage.constants.SubType;
import mage.filter.predicate.mageobject.AbilityPredicate; import mage.constants.SuperType;
import mage.game.Game;
import mage.players.Player;
import mage.target.common.TargetOpponentsCreaturePermanent; import mage.target.common.TargetOpponentsCreaturePermanent;
import mage.util.CardUtil;
import java.util.UUID; import java.util.UUID;
@ -34,7 +30,7 @@ public final class BohnBeguilingBalladeer extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Each nonland card in your hand without foretell has foretell. Its foretell cost is equal to its mana cost reduced by {2}. // Each nonland card in your hand without foretell has foretell. Its foretell cost is equal to its mana cost reduced by {2}.
this.addAbility(new SimpleStaticAbility(new EdginLarcenousLutenistEffect())); this.addAbility(new SimpleStaticAbility(ForetellAbility.makeAddForetellEffect()));
// Whenever you cast your second spell each turn, goad target creature an opponent controls. // Whenever you cast your second spell each turn, goad target creature an opponent controls.
Ability ability = new CastSecondSpellTriggeredAbility(new GoadTargetEffect()); Ability ability = new CastSecondSpellTriggeredAbility(new GoadTargetEffect());
@ -51,69 +47,3 @@ public final class BohnBeguilingBalladeer extends CardImpl {
return new BohnBeguilingBalladeer(this); return new BohnBeguilingBalladeer(this);
} }
} }
class EdginLarcenousLutenistEffect extends ContinuousEffectImpl {
private static final FilterNonlandCard filter = new FilterNonlandCard();
static {
filter.add(Predicates.not(new AbilityPredicate(ForetellAbility.class)));
}
EdginLarcenousLutenistEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
this.staticText = "Each nonland card in your hand without foretell has foretell. Its foretell cost is equal to its mana cost reduced by {2}";
}
private EdginLarcenousLutenistEffect(final EdginLarcenousLutenistEffect effect) {
super(effect);
}
@Override
public EdginLarcenousLutenistEffect copy() {
return new EdginLarcenousLutenistEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
for (Card card : controller.getHand().getCards(filter, game)) {
ForetellAbility foretellAbility = null;
if (card instanceof SplitCard) {
String leftHalfCost = CardUtil.reduceCost(((SplitCard) card).getLeftHalfCard().getManaCost(), 2).getText();
String rightHalfCost = CardUtil.reduceCost(((SplitCard) card).getRightHalfCard().getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, leftHalfCost, rightHalfCost);
} else if (card instanceof ModalDoubleFacedCard) {
ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard();
// If front side of MDFC is land, do nothing as Dream Devourer does not apply to lands
// MDFC cards in hand are considered lands if front side is land
if (!leftHalfCard.isLand(game)) {
String leftHalfCost = CardUtil.reduceCost(leftHalfCard.getManaCost(), 2).getText();
ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard();
if (rightHalfCard.isLand(game)) {
foretellAbility = new ForetellAbility(card, leftHalfCost);
} else {
String rightHalfCost = CardUtil.reduceCost(rightHalfCard.getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, leftHalfCost, rightHalfCost);
}
}
} else if (card instanceof CardWithSpellOption) {
String creatureCost = CardUtil.reduceCost(card.getMainCard().getManaCost(), 2).getText();
String spellCost = CardUtil.reduceCost(((CardWithSpellOption) card).getSpellCard().getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, creatureCost, spellCost);
} else {
String costText = CardUtil.reduceCost(card.getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, costText);
}
if (foretellAbility != null) {
foretellAbility.setSourceId(card.getId());
foretellAbility.setControllerId(card.getOwnerId());
game.getState().addOtherAbility(card, foretellAbility);
}
}
return true;
}
}

View file

@ -10,9 +10,9 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SagaChapter; import mage.constants.SagaChapter;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterLandCard; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
@ -23,13 +23,7 @@ import java.util.UUID;
*/ */
public final class BoseijuReachesSkyward extends CardImpl { public final class BoseijuReachesSkyward extends CardImpl {
private static final FilterCard filter = new FilterCard("basic Forest cards"); private static final FilterCard filter = new FilterBasicCard(SubType.FOREST, "basic Forest cards");
private static final FilterCard filter2 = new FilterLandCard("land card from your graveyard");
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.FOREST.getPredicate());
}
public BoseijuReachesSkyward(UUID ownerId, CardSetInfo setInfo) { public BoseijuReachesSkyward(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{3}{G}");
@ -52,7 +46,7 @@ public final class BoseijuReachesSkyward extends CardImpl {
sagaAbility.addChapterEffect( sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II, this, SagaChapter.CHAPTER_II, SagaChapter.CHAPTER_II,
new PutOnLibraryTargetEffect(true), new PutOnLibraryTargetEffect(true),
new TargetCardInYourGraveyard(0, 1, filter2) new TargetCardInYourGraveyard(0, 1, StaticFilters.FILTER_CARD_LAND_FROM_YOUR_GRAVEYARD)
); );
// III Exile this Saga, then return it to the battlefield transformed under your control. // III Exile this Saga, then return it to the battlefield transformed under your control.

View file

@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -25,7 +25,7 @@ import java.util.UUID;
*/ */
public final class BountifulLandscape extends CardImpl { public final class BountifulLandscape extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("a basic Forest, Island, or Mountain card"); private static final FilterCard filter = new FilterBasicCard("a basic Forest, Island, or Mountain card");
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(

View file

@ -1,13 +1,12 @@
package mage.cards.c; package mage.cards.c;
import java.util.UUID;
import mage.Mana; import mage.Mana;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint; import mage.abilities.hint.ValueHint;
import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ColorlessManaAbility;
import mage.abilities.mana.DynamicManaAbility; import mage.abilities.mana.DynamicManaAbility;
@ -16,7 +15,10 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.filter.common.FilterControlledLandPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterControlledPermanent;
import java.util.UUID;
/** /**
* @author JRHerlehy * @author JRHerlehy
@ -24,13 +26,15 @@ import mage.filter.common.FilterControlledLandPermanent;
*/ */
public final class CabalStronghold extends CardImpl { public final class CabalStronghold extends CardImpl {
private static final FilterControlledLandPermanent filter = new FilterControlledLandPermanent("basic Swamp you control"); private static final FilterPermanent filter = new FilterControlledPermanent(SubType.SWAMP, "basic Swamp you control");
static { static {
filter.add(SuperType.BASIC.getPredicate()); filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.SWAMP.getPredicate());
} }
private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(filter);
private static final Hint hint = new ValueHint("Basic Swamps you control", xValue);
public CabalStronghold(UUID ownerId, CardSetInfo setInfo) { public CabalStronghold(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.LAND}, ""); super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
@ -38,9 +42,9 @@ public final class CabalStronghold extends CardImpl {
this.addAbility(new ColorlessManaAbility()); this.addAbility(new ColorlessManaAbility());
// {3}, {T}: Add {B} for each basic Swamp you control. // {3}, {T}: Add {B} for each basic Swamp you control.
Ability ability = new DynamicManaAbility(Mana.BlackMana(1), new PermanentsOnBattlefieldCount(filter), new GenericManaCost(3)); Ability ability = new DynamicManaAbility(Mana.BlackMana(1), xValue, new GenericManaCost(3));
ability.addCost(new TapSourceCost()); ability.addCost(new TapSourceCost());
this.addAbility(ability.addHint(new ValueHint("Basic Swamps you control", new PermanentsOnBattlefieldCount(filter)))); this.addAbility(ability.addHint(hint));
} }
private CabalStronghold(final CabalStronghold card) { private CabalStronghold(final CabalStronghold card) {

View file

@ -12,13 +12,10 @@ import mage.abilities.keyword.CantBeBlockedSourceAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.*;
import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterLandCard;
import mage.filter.predicate.Predicate; import mage.filter.predicate.Predicate;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
@ -101,7 +98,8 @@ class CanoptekWraithEffect extends OneShotEffect {
if (permanent == null) { if (permanent == null) {
return false; return false;
} }
FilterCard filter = new FilterBasicLandCard("basic land cards with the same name as the chosen land"); FilterCard filter = new FilterLandCard("basic land cards with the same name as the chosen land");
filter.add(SuperType.BASIC.getPredicate());
filter.add(new CanoptekWraithPredicate(permanent)); filter.add(new CanoptekWraithPredicate(permanent));
TargetCardInLibrary targetCard = new TargetCardInLibrary(0, 2, filter); TargetCardInLibrary targetCard = new TargetCardInLibrary(0, 2, filter);
player.searchLibrary(targetCard, source, game); player.searchLibrary(targetCard, source, game);

View file

@ -20,7 +20,6 @@ import mage.constants.TargetController;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBySubtypeCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -39,7 +38,7 @@ public final class CharitableLevy extends CardImpl {
private static final Condition condition = new SourceHasCounterCondition(CounterType.COLLECTION, 3); private static final Condition condition = new SourceHasCounterCondition(CounterType.COLLECTION, 3);
private static final FilterCard filterPlains = new FilterBySubtypeCard(SubType.PLAINS); private static final FilterCard filterPlains = new FilterCard(SubType.PLAINS);
public CharitableLevy(UUID ownerId, CardSetInfo setInfo) { public CharitableLevy(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}");

View file

@ -8,9 +8,7 @@ import mage.abilities.keyword.CraftAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.filter.StaticFilters;
import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -20,15 +18,13 @@ import java.util.UUID;
*/ */
public final class ClayFiredBricks extends CardImpl { public final class ClayFiredBricks extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard(SubType.PLAINS);
public ClayFiredBricks(UUID ownerId, CardSetInfo setInfo) { public ClayFiredBricks(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}");
this.secondSideCardClazz = mage.cards.c.CosmiumKiln.class; this.secondSideCardClazz = mage.cards.c.CosmiumKiln.class;
// When Clay-Fired Bricks enters the battlefield, search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. You gain 2 life. // When Clay-Fired Bricks enters the battlefield, search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. You gain 2 life.
Ability ability = new EntersBattlefieldTriggeredAbility( Ability ability = new EntersBattlefieldTriggeredAbility(
new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true) new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true)
); );
ability.addEffect(new GainLifeEffect(2)); ability.addEffect(new GainLifeEffect(2));
this.addAbility(ability); this.addAbility(ability);

View file

@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -25,7 +25,7 @@ import java.util.UUID;
*/ */
public final class ContaminatedLandscape extends CardImpl { public final class ContaminatedLandscape extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("a basic Plains, Island, or Swamp card"); private static final FilterCard filter = new FilterBasicCard("a basic Plains, Island, or Swamp card");
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(

View file

@ -1,31 +1,29 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.dynamicvalue.IntPlusDynamicValue; import mage.abilities.condition.Condition;
import mage.abilities.dynamicvalue.MultipliedValue; import mage.abilities.condition.common.CardsInHandCondition;
import mage.abilities.dynamicvalue.common.CardsInControllerHandCount; import mage.abilities.effects.common.DrawCardsEqualToDifferenceEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.SkipDrawStepEffect; import mage.abilities.effects.common.SkipDrawStepEffect;
import mage.abilities.keyword.DeathtouchAbility; import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.constants.TargetController;
import mage.game.Game; import java.util.UUID;
import mage.players.Player;
/** /**
*
* @author emerald000 * @author emerald000
*/ */
public final class DamiaSageOfStone extends CardImpl { public final class DamiaSageOfStone extends CardImpl {
private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 7);
public DamiaSageOfStone(UUID ownerId, CardSetInfo setInfo) { public DamiaSageOfStone(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{G}{U}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{B}{G}{U}");
this.supertype.add(SuperType.LEGENDARY); this.supertype.add(SuperType.LEGENDARY);
@ -42,7 +40,7 @@ public final class DamiaSageOfStone extends CardImpl {
this.addAbility(new SimpleStaticAbility(new SkipDrawStepEffect())); this.addAbility(new SimpleStaticAbility(new SkipDrawStepEffect()));
// At the beginning of your upkeep, if you have fewer than seven cards in hand, draw cards equal to the difference. // At the beginning of your upkeep, if you have fewer than seven cards in hand, draw cards equal to the difference.
this.addAbility(new DamiaSageOfStoneTriggeredAbility()); this.addAbility(new BeginningOfUpkeepTriggeredAbility(new DrawCardsEqualToDifferenceEffect(7)).withInterveningIf(condition));
} }
private DamiaSageOfStone(final DamiaSageOfStone card) { private DamiaSageOfStone(final DamiaSageOfStone card) {
@ -54,33 +52,3 @@ public final class DamiaSageOfStone extends CardImpl {
return new DamiaSageOfStone(this); return new DamiaSageOfStone(this);
} }
} }
class DamiaSageOfStoneTriggeredAbility extends BeginningOfUpkeepTriggeredAbility {
DamiaSageOfStoneTriggeredAbility() {
super(TargetController.YOU, new DrawCardSourceControllerEffect(new IntPlusDynamicValue(7, new MultipliedValue(CardsInControllerHandCount.ANY, -1))), false);
}
private DamiaSageOfStoneTriggeredAbility(final DamiaSageOfStoneTriggeredAbility ability) {
super(ability);
}
@Override
public DamiaSageOfStoneTriggeredAbility copy() {
return new DamiaSageOfStoneTriggeredAbility(this);
}
@Override
public boolean checkInterveningIfClause(Game game) {
Player player = game.getPlayer(this.getControllerId());
if (player != null) {
return player.getHand().size() < 7;
}
return false;
}
@Override
public String getRule() {
return "At the beginning of your upkeep, if you have fewer than seven cards in hand, draw cards equal to the difference.";
}
}

View file

@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -25,7 +25,7 @@ import java.util.UUID;
*/ */
public final class DeceptiveLandscape extends CardImpl { public final class DeceptiveLandscape extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("a basic Plains, Swamp, or Forest card"); private static final FilterCard filter = new FilterBasicCard("a basic Plains, Swamp, or Forest card");
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(

View file

@ -0,0 +1,58 @@
package mage.cards.d;
import mage.MageInt;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.condition.common.CardsInHandCondition;
import mage.abilities.effects.common.DrawCardsEqualToDifferenceEffect;
import mage.abilities.effects.common.continuous.BoostControlledEffect;
import mage.abilities.effects.common.continuous.MaximumHandSizeControllerEffect;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.filter.common.FilterCreaturePermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class DoctorOctopusMasterPlanner extends CardImpl {
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent(SubType.VILLAIN, "Villains");
private static final Condition condition = new CardsInHandCondition(ComparisonType.FEWER_THAN, 8);
public DoctorOctopusMasterPlanner(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{U}{B}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.SCIENTIST);
this.subtype.add(SubType.VILLAIN);
this.power = new MageInt(4);
this.toughness = new MageInt(8);
// Other Villains you control get +2/+2.
this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(
2, 2, Duration.WhileOnBattlefield, filter, true
)));
// Your maximum hand size is eight.
this.addAbility(new SimpleStaticAbility(new MaximumHandSizeControllerEffect(
8, Duration.WhileOnBattlefield, MaximumHandSizeControllerEffect.HandSizeModification.SET
)));
// At the beginning of your end step, if you have fewer than eight cards in hand, draw cards equal to the difference.
this.addAbility(new BeginningOfEndStepTriggeredAbility(new DrawCardsEqualToDifferenceEffect(8)).withInterveningIf(condition));
}
private DoctorOctopusMasterPlanner(final DoctorOctopusMasterPlanner card) {
super(card);
}
@Override
public DoctorOctopusMasterPlanner copy() {
return new DoctorOctopusMasterPlanner(this);
}
}

View file

@ -1,27 +1,17 @@
package mage.cards.d; package mage.cards.d;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.ForetellSourceControllerTriggeredAbility; import mage.abilities.common.ForetellSourceControllerTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.common.continuous.BoostSourceEffect; import mage.abilities.effects.common.continuous.BoostSourceEffect;
import mage.abilities.keyword.ForetellAbility; import mage.abilities.keyword.ForetellAbility;
import mage.cards.*; import mage.cards.CardImpl;
import mage.constants.SubType; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Duration; import mage.constants.Duration;
import mage.constants.Layer; import mage.constants.SubType;
import mage.constants.Outcome;
import mage.constants.SubLayer; import java.util.UUID;
import mage.constants.Zone;
import mage.filter.common.FilterNonlandCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.Game;
import mage.players.Player;
import mage.util.CardUtil;
/** /**
* *
@ -38,7 +28,7 @@ public final class DreamDevourer extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// Each nonland card in your hand without foretell has foretell. Its foretell cost is equal to its mana cost reduced by 2. // Each nonland card in your hand without foretell has foretell. Its foretell cost is equal to its mana cost reduced by 2.
this.addAbility(new SimpleStaticAbility(new DreamDevourerAddAbilityEffect())); this.addAbility(new SimpleStaticAbility(ForetellAbility.makeAddForetellEffect()));
// Whenever you foretell a card, Dream Devourer gets +2/+0 until end of turn. // Whenever you foretell a card, Dream Devourer gets +2/+0 until end of turn.
this.addAbility(new ForetellSourceControllerTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn))); this.addAbility(new ForetellSourceControllerTriggeredAbility(new BoostSourceEffect(2, 0, Duration.EndOfTurn)));
@ -54,69 +44,3 @@ public final class DreamDevourer extends CardImpl {
return new DreamDevourer(this); return new DreamDevourer(this);
} }
} }
class DreamDevourerAddAbilityEffect extends ContinuousEffectImpl {
private static final FilterNonlandCard filter = new FilterNonlandCard();
static {
filter.add(Predicates.not(new AbilityPredicate(ForetellAbility.class)));
}
DreamDevourerAddAbilityEffect() {
super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
this.staticText = "Each nonland card in your hand without foretell has foretell. Its foretell cost is equal to its mana cost reduced by {2}";
}
private DreamDevourerAddAbilityEffect(final DreamDevourerAddAbilityEffect effect) {
super(effect);
}
@Override
public DreamDevourerAddAbilityEffect copy() {
return new DreamDevourerAddAbilityEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
for (Card card : controller.getHand().getCards(filter, game)) {
ForetellAbility foretellAbility = null;
if (card instanceof SplitCard) {
String leftHalfCost = CardUtil.reduceCost(((SplitCard) card).getLeftHalfCard().getManaCost(), 2).getText();
String rightHalfCost = CardUtil.reduceCost(((SplitCard) card).getRightHalfCard().getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, leftHalfCost, rightHalfCost);
} else if (card instanceof ModalDoubleFacedCard) {
ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard();
// If front side of MDFC is land, do nothing as Dream Devourer does not apply to lands
// MDFC cards in hand are considered lands if front side is land
if (!leftHalfCard.isLand(game)) {
String leftHalfCost = CardUtil.reduceCost(leftHalfCard.getManaCost(), 2).getText();
ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard();
if (rightHalfCard.isLand(game)) {
foretellAbility = new ForetellAbility(card, leftHalfCost);
} else {
String rightHalfCost = CardUtil.reduceCost(rightHalfCard.getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, leftHalfCost, rightHalfCost);
}
}
} else if (card instanceof CardWithSpellOption) {
String creatureCost = CardUtil.reduceCost(card.getMainCard().getManaCost(), 2).getText();
String spellCost = CardUtil.reduceCost(((CardWithSpellOption) card).getSpellCard().getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, creatureCost, spellCost);
} else {
String costText = CardUtil.reduceCost(card.getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, costText);
}
if (foretellAbility != null) {
foretellAbility.setSourceId(card.getId());
foretellAbility.setControllerId(card.getOwnerId());
game.getState().addOtherAbility(card, foretellAbility);
}
}
return true;
}
}

View file

@ -1,29 +1,28 @@
package mage.cards.e; package mage.cards.e;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.DiesSourceTriggeredAbility; import mage.abilities.common.DiesSourceTriggeredAbility;
import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect; import mage.abilities.effects.common.ReturnFromGraveyardToHandTargetEffect;
import mage.constants.SubType;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBySubtypeCard;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/** /**
*
* @author weirddan455 * @author weirddan455
*/ */
public final class ElderfangRitualist extends CardImpl { public final class ElderfangRitualist extends CardImpl {
private static final FilterCard filter = new FilterBySubtypeCard(SubType.ELF); private static final FilterCard filter = new FilterCard(SubType.ELF, "another target Elf card from your graveyard");
static { static {
filter.add(AnotherPredicate.instance); filter.add(AnotherPredicate.instance);
filter.setMessage("another target Elf card from your graveyard");
} }
public ElderfangRitualist(UUID ownerId, CardSetInfo setInfo) { public ElderfangRitualist(UUID ownerId, CardSetInfo setInfo) {

View file

@ -1,7 +1,5 @@
package mage.cards.e; package mage.cards.e;
import java.util.UUID;
import mage.abilities.condition.common.FerociousCondition; import mage.abilities.condition.common.FerociousCondition;
import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.SacrificeControllerEffect; import mage.abilities.effects.common.SacrificeControllerEffect;
@ -9,22 +7,19 @@ import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
*
* @author Susucr * @author Susucr
*/ */
public final class EntishRestoration extends CardImpl { public final class EntishRestoration extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("basic land cards");
private static final String rule = "Search your library for up to two basic land cards, " + private static final String rule = "Search your library for up to two basic land cards, " +
"put them onto the battlefield tapped, then shuffle. " + "put them onto the battlefield tapped, then shuffle. " +
"If " + FerociousCondition.instance.toString() + ", instead search your library for up " + "If " + FerociousCondition.instance + ", instead search your library for up " +
"to three basic land cards, put them onto the battlefield tapped, then shuffle."; "to three basic land cards, put them onto the battlefield tapped, then shuffle.";
public EntishRestoration(UUID ownerId, CardSetInfo setInfo) { public EntishRestoration(UUID ownerId, CardSetInfo setInfo) {
@ -39,8 +34,8 @@ public final class EntishRestoration extends CardImpl {
).setText("Sacrifice a land.")); ).setText("Sacrifice a land."));
this.getSpellAbility().addEffect( this.getSpellAbility().addEffect(
new ConditionalOneShotEffect( new ConditionalOneShotEffect(
new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 3, filter), true), new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 3, StaticFilters.FILTER_CARD_BASIC_LANDS), true),
new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 2, filter), true), new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LANDS), true),
FerociousCondition.instance, rule FerociousCondition.instance, rule
) )
); );

View file

@ -1,23 +1,22 @@
package mage.cards.e; package mage.cards.e;
import mage.MageInt; import mage.MageInt;
import mage.MageObjectReference;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility; import mage.abilities.common.EntersBattlefieldOrAttacksSourceTriggeredAbility;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.ForetellAbility; import mage.abilities.keyword.ForetellAbility;
import mage.cards.*; import mage.cards.Card;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetCardInHand; import mage.target.common.TargetCardInHand;
import mage.util.CardUtil; import mage.watchers.common.ForetoldWatcher;
import java.util.UUID; import java.util.UUID;
@ -38,7 +37,7 @@ public final class EtherealValkyrie extends CardImpl {
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Whenever Ethereal Valkyrie enters the battlefield or attacks, draw a card, then exile a card from your hand face down. It becomes foretold. Its foretell cost is its mana cost reduced by {2}. // Whenever Ethereal Valkyrie enters the battlefield or attacks, draw a card, then exile a card from your hand face down. It becomes foretold. Its foretell cost is its mana cost reduced by {2}.
this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new EtherealValkyrieEffect())); this.addAbility(new EntersBattlefieldOrAttacksSourceTriggeredAbility(new EtherealValkyrieEffect()), new ForetoldWatcher());
} }
private EtherealValkyrie(final EtherealValkyrie card) { private EtherealValkyrie(final EtherealValkyrie card) {
@ -75,77 +74,15 @@ class EtherealValkyrieEffect extends OneShotEffect {
if (controller == null) { if (controller == null) {
return false; return false;
} }
controller.drawCards(1, source, game); controller.drawCards(1, source, game);
TargetCardInHand targetCard = new TargetCardInHand(new FilterCard("card to exile face down. It becomes foretold.")); TargetCardInHand targetCard = new TargetCardInHand(StaticFilters.FILTER_CARD).withChooseHint("to exile face down; it becomes foretold");
if (!controller.chooseTarget(Outcome.Benefit, targetCard, source, game)) { if (!controller.chooseTarget(Outcome.Benefit, targetCard, source, game)) {
return false; return false;
} }
Card card = game.getCard(targetCard.getFirstTarget());
Card exileCard = game.getCard(targetCard.getFirstTarget()); if (card == null) {
if (exileCard == null) {
return false; return false;
} }
return ForetellAbility.doExileBecomesForetold(card, game, source, 2);
// process Split, MDFC, and Adventure cards first
// note that 'Foretell Cost' refers to the main card (left) and 'Foretell Split Cost' refers to the (right) card if it exists
ForetellAbility foretellAbility = null;
if (exileCard instanceof SplitCard) {
String leftHalfCost = CardUtil.reduceCost(((SplitCard) exileCard).getLeftHalfCard().getManaCost(), 2).getText();
String rightHalfCost = CardUtil.reduceCost(((SplitCard) exileCard).getRightHalfCard().getManaCost(), 2).getText();
game.getState().setValue(exileCard.getMainCard().getId().toString() + "Foretell Cost", leftHalfCost);
game.getState().setValue(exileCard.getMainCard().getId().toString() + "Foretell Split Cost", rightHalfCost);
foretellAbility = new ForetellAbility(exileCard, leftHalfCost, rightHalfCost);
} else if (exileCard instanceof ModalDoubleFacedCard) {
ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) exileCard).getLeftHalfCard();
if (!leftHalfCard.isLand(game)) { // Only MDFC cards with a left side a land have a land on the right side too
String leftHalfCost = CardUtil.reduceCost(leftHalfCard.getManaCost(), 2).getText();
game.getState().setValue(exileCard.getMainCard().getId().toString() + "Foretell Cost", leftHalfCost);
ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) exileCard).getRightHalfCard();
if (rightHalfCard.isLand(game)) {
foretellAbility = new ForetellAbility(exileCard, leftHalfCost);
} else {
String rightHalfCost = CardUtil.reduceCost(rightHalfCard.getManaCost(), 2).getText();
game.getState().setValue(exileCard.getMainCard().getId().toString() + "Foretell Split Cost", rightHalfCost);
foretellAbility = new ForetellAbility(exileCard, leftHalfCost, rightHalfCost);
}
}
} else if (exileCard instanceof CardWithSpellOption) {
String creatureCost = CardUtil.reduceCost(exileCard.getMainCard().getManaCost(), 2).getText();
String spellCost = CardUtil.reduceCost(((CardWithSpellOption) exileCard).getSpellCard().getManaCost(), 2).getText();
game.getState().setValue(exileCard.getMainCard().getId().toString() + "Foretell Cost", creatureCost);
game.getState().setValue(exileCard.getMainCard().getId().toString() + "Foretell Split Cost", spellCost);
foretellAbility = new ForetellAbility(exileCard, creatureCost, spellCost);
} else if (!exileCard.isLand(game)) {
// normal card
String costText = CardUtil.reduceCost(exileCard.getManaCost(), 2).getText();
game.getState().setValue(exileCard.getId().toString() + "Foretell Cost", costText);
foretellAbility = new ForetellAbility(exileCard, costText);
}
// All card types (including lands) must be exiled
UUID exileId = CardUtil.getExileZoneId(exileCard.getMainCard().getId().toString() + "foretellAbility", game);
controller.moveCardsToExile(exileCard, source, game, true, exileId, " Foretell Turn Number: " + game.getTurnNum());
exileCard.setFaceDown(true, game);
// all done pre-processing so stick the foretell cost effect onto the main card
// note that the card is not foretell'd into exile, it is put into exile and made foretold
// If the card is a non-land, it will not be exiled.
if (foretellAbility != null) {
// copy source and use it for the foretold effect on the exiled card
// bug #8673
Ability copiedSource = source.copy();
copiedSource.newId();
copiedSource.setSourceId(exileCard.getId());
game.getState().setValue(exileCard.getMainCard().getId().toString() + "Foretell Turn Number", game.getTurnNum());
foretellAbility.setSourceId(exileCard.getId());
foretellAbility.setControllerId(exileCard.getOwnerId());
game.getState().addOtherAbility(exileCard, foretellAbility);
foretellAbility.activate(game, true);
ContinuousEffect effect = new ForetellAbility.ForetellAddCostEffect(new MageObjectReference(exileCard, game));
game.addEffect(effect, copiedSource);
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.FORETOLD, exileCard.getId(), null, null));
}
return true;
} }
} }

View file

@ -7,8 +7,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -18,12 +18,7 @@ import java.util.UUID;
*/ */
public final class FieldTrip extends CardImpl { public final class FieldTrip extends CardImpl {
private static final FilterCard filter = new FilterCard("basic Forest card"); private static final FilterCard filter = new FilterBasicCard(SubType.FOREST);
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.FOREST.getPredicate());
}
public FieldTrip(UUID ownerId, CardSetInfo setInfo) { public FieldTrip(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}");

View file

@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -25,7 +25,7 @@ import java.util.UUID;
*/ */
public final class ForebodingLandscape extends CardImpl { public final class ForebodingLandscape extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("a basic Swamp, Forest, or Island card"); private static final FilterCard filter = new FilterBasicCard("a basic Swamp, Forest, or Island card");
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(

View file

@ -1,32 +1,33 @@
package mage.cards.f; package mage.cards.f;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect;
import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterBySubtypeCard; import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
*
* @author JayDi85 * @author JayDi85
*/ */
public final class ForerunnerOfTheCoalition extends CardImpl { public final class ForerunnerOfTheCoalition extends CardImpl {
private static final FilterPermanent filterAnotherPirate = new FilterPermanent(SubType.PIRATE, "another " + SubType.PIRATE.toString()); private static final FilterCard filter = new FilterCard(SubType.PIRATE);
private static final FilterPermanent filter2
= new FilterControlledPermanent(SubType.PIRATE, "another Pirate you control");
static { static {
filterAnotherPirate.add(AnotherPredicate.instance); filter2.add(AnotherPredicate.instance);
filterAnotherPirate.add(TargetController.YOU.getControllerPredicate());
} }
public ForerunnerOfTheCoalition(UUID ownerId, CardSetInfo setInfo) { public ForerunnerOfTheCoalition(UUID ownerId, CardSetInfo setInfo) {
@ -39,15 +40,13 @@ public final class ForerunnerOfTheCoalition extends CardImpl {
// When Forerunner of the Coalition enters the battlefield, you may search your library for a Pirate card, reveal it, then shuffle your library and put that card on top of it. // When Forerunner of the Coalition enters the battlefield, you may search your library for a Pirate card, reveal it, then shuffle your library and put that card on top of it.
this.addAbility(new EntersBattlefieldTriggeredAbility( this.addAbility(new EntersBattlefieldTriggeredAbility(
new SearchLibraryPutOnLibraryEffect( new SearchLibraryPutOnLibraryEffect(new TargetCardInLibrary(filter), true), true
new TargetCardInLibrary(new FilterBySubtypeCard(SubType.PIRATE)), ));
true), true));
// Whenever another Pirate you control enters, each opponent loses 1 life. // Whenever another Pirate you control enters, each opponent loses 1 life.
Ability ability = new EntersBattlefieldControlledTriggeredAbility( this.addAbility(new EntersBattlefieldAllTriggeredAbility(
Zone.BATTLEFIELD, new LoseLifeOpponentsEffect(1), new LoseLifeOpponentsEffect(1), filter2
filterAnotherPirate, false); ));
this.addAbility(ability);
} }
private ForerunnerOfTheCoalition(final ForerunnerOfTheCoalition card) { private ForerunnerOfTheCoalition(final ForerunnerOfTheCoalition card) {

View file

@ -1,9 +1,7 @@
package mage.cards.f; package mage.cards.f;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.DamageAllEffect; import mage.abilities.effects.common.DamageAllEffect;
import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect;
@ -11,10 +9,10 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.TargetController; import mage.filter.FilterCard;
import mage.constants.Zone; import mage.filter.FilterPermanent;
import mage.filter.common.FilterBySubtypeCard; import mage.filter.StaticFilters;
import mage.filter.common.FilterCreaturePermanent; import mage.filter.common.FilterControlledPermanent;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -24,11 +22,9 @@ import java.util.UUID;
*/ */
public final class ForerunnerOfTheEmpire extends CardImpl { public final class ForerunnerOfTheEmpire extends CardImpl {
private static final FilterCreaturePermanent filterAnyDinosaur = new FilterCreaturePermanent(SubType.DINOSAUR, "a " + SubType.DINOSAUR.toString()); private static final FilterCard filter = new FilterCard(SubType.DINOSAUR);
private static final FilterPermanent filter2
static { = new FilterControlledPermanent(SubType.DINOSAUR, "Dinosaur you control");
filterAnyDinosaur.add(TargetController.YOU.getControllerPredicate());
}
public ForerunnerOfTheEmpire(UUID ownerId, CardSetInfo setInfo) { public ForerunnerOfTheEmpire(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{R}");
@ -39,23 +35,16 @@ public final class ForerunnerOfTheEmpire extends CardImpl {
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// When Forerunner of the Empire enters the battlefield, you may search your library for a Dinosaur card, reveal it, then shuffle your library and put that card on top of it. // When Forerunner of the Empire enters the battlefield, you may search your library for a Dinosaur card, reveal it, then shuffle your library and put that card on top of it.
this.addAbility( this.addAbility(new EntersBattlefieldTriggeredAbility(
new EntersBattlefieldTriggeredAbility( new SearchLibraryPutOnLibraryEffect(new TargetCardInLibrary(filter), true), true
new SearchLibraryPutOnLibraryEffect( ));
new TargetCardInLibrary(new FilterBySubtypeCard(SubType.DINOSAUR)),
true
),
true
)
);
// Whenever a Dinosaur you control enters, you may have Forerunner of the Empire deal 1 damage to each creature. // Whenever a Dinosaur you control enters, you may have Forerunner of the Empire deal 1 damage to each creature.
Ability ability = new EntersBattlefieldControlledTriggeredAbility( this.addAbility(new EntersBattlefieldAllTriggeredAbility(
Zone.BATTLEFIELD, new DamageAllEffect(1, StaticFilters.FILTER_PERMANENT_CREATURE)
new DamageAllEffect(1, new FilterCreaturePermanent()).setText("have {this} deal 1 damage to each creature"), .setText("have {this} deal 1 damage to each creature"),
filterAnyDinosaur, filter2, true
true); ));
this.addAbility(ability);
} }
private ForerunnerOfTheEmpire(final ForerunnerOfTheEmpire card) { private ForerunnerOfTheEmpire(final ForerunnerOfTheEmpire card) {

View file

@ -1,34 +1,35 @@
package mage.cards.f; package mage.cards.f;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.counter.AddCountersSourceEffect; import mage.abilities.effects.common.counter.AddCountersSourceEffect;
import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect;
import mage.constants.SubType;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.TargetController; import mage.constants.SubType;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterBySubtypeCard; import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
*
* @author JayDi85 * @author JayDi85
*/ */
public final class ForerunnerOfTheHeralds extends CardImpl { public final class ForerunnerOfTheHeralds extends CardImpl {
private static final FilterPermanent filterAnotherMerfolk = new FilterPermanent(SubType.MERFOLK, "another " + SubType.MERFOLK.toString()); private static final FilterCard filter = new FilterCard(SubType.MERFOLK);
private static final FilterPermanent filter2
= new FilterControlledPermanent(SubType.MERFOLK, "another Merfolk you control");
static { static {
filterAnotherMerfolk.add(AnotherPredicate.instance); filter2.add(AnotherPredicate.instance);
filterAnotherMerfolk.add(TargetController.YOU.getControllerPredicate());
} }
public ForerunnerOfTheHeralds(UUID ownerId, CardSetInfo setInfo) { public ForerunnerOfTheHeralds(UUID ownerId, CardSetInfo setInfo) {
@ -39,21 +40,15 @@ public final class ForerunnerOfTheHeralds extends CardImpl {
this.power = new MageInt(3); this.power = new MageInt(3);
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// When Forerunner of the Heralds enters the battlefield, you may search your library for a Merfolk card, reveal it, then shuffle your library and put that card on top of it. // When Forerunner of the Heralds enters the battlefield, you may search your library for a Merfolk card, reveal it, then shuffle your library and put that card on top of it.
this.addAbility( this.addAbility(new EntersBattlefieldTriggeredAbility(
new EntersBattlefieldTriggeredAbility( new SearchLibraryPutOnLibraryEffect(new TargetCardInLibrary(filter), true), true
new SearchLibraryPutOnLibraryEffect( ));
new TargetCardInLibrary(new FilterBySubtypeCard(SubType.MERFOLK)),
true
),
true
)
);
// Whenever another Merfolk you control enters, put a +1/+1 counter on Forerunner of the Heralds. // Whenever another Merfolk you control enters, put a +1/+1 counter on Forerunner of the Heralds.
Ability ability = new EntersBattlefieldControlledTriggeredAbility(new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filterAnotherMerfolk); this.addAbility(new EntersBattlefieldAllTriggeredAbility(
this.addAbility(ability); new AddCountersSourceEffect(CounterType.P1P1.createInstance()), filter2
));
} }
private ForerunnerOfTheHeralds(final ForerunnerOfTheHeralds card) { private ForerunnerOfTheHeralds(final ForerunnerOfTheHeralds card) {

View file

@ -1,32 +1,35 @@
package mage.cards.f; package mage.cards.f;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.EntersBattlefieldAllTriggeredAbility;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect;
import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect; import mage.abilities.effects.common.search.SearchLibraryPutOnLibraryEffect;
import mage.constants.*;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.common.FilterBySubtypeCard; import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.mageobject.AnotherPredicate; import mage.filter.predicate.mageobject.AnotherPredicate;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetCreaturePermanent; import mage.target.common.TargetCreaturePermanent;
import java.util.UUID;
/** /**
*
* @author JayDi85 * @author JayDi85
*/ */
public final class ForerunnerOfTheLegion extends CardImpl { public final class ForerunnerOfTheLegion extends CardImpl {
private static final FilterPermanent filterAnotherVampire = new FilterPermanent(SubType.VAMPIRE, "another " + SubType.VAMPIRE.toString()); private static final FilterCard filter = new FilterCard(SubType.VAMPIRE);
private static final FilterPermanent filter2
= new FilterControlledPermanent(SubType.VAMPIRE, "another Vampire you control");
static { static {
filterAnotherVampire.add(AnotherPredicate.instance); filter2.add(AnotherPredicate.instance);
filterAnotherVampire.add(TargetController.YOU.getControllerPredicate());
} }
public ForerunnerOfTheLegion(UUID ownerId, CardSetInfo setInfo) { public ForerunnerOfTheLegion(UUID ownerId, CardSetInfo setInfo) {
@ -38,18 +41,12 @@ public final class ForerunnerOfTheLegion extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// When Forerunner of the Legion enters the battlefield, you may search your library for a Vampire card, reveal it, then shuffle your library and put that card on top of it. // When Forerunner of the Legion enters the battlefield, you may search your library for a Vampire card, reveal it, then shuffle your library and put that card on top of it.
this.addAbility( this.addAbility(new EntersBattlefieldTriggeredAbility(
new EntersBattlefieldTriggeredAbility( new SearchLibraryPutOnLibraryEffect(new TargetCardInLibrary(filter), true), true
new SearchLibraryPutOnLibraryEffect( ));
new TargetCardInLibrary(new FilterBySubtypeCard(SubType.VAMPIRE)),
true
),
true
)
);
// Whenever another Vampire you control enters, target creature gets +1/+1 until end of turn. // Whenever another Vampire you control enters, target creature gets +1/+1 until end of turn.
Ability ability = new EntersBattlefieldControlledTriggeredAbility(new BoostTargetEffect(1,1, Duration.EndOfTurn), filterAnotherVampire); Ability ability = new EntersBattlefieldAllTriggeredAbility(new BoostTargetEffect(1, 1), filter2);
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -9,8 +9,12 @@ import mage.abilities.effects.common.PutCardFromHandOntoBattlefieldEffect;
import mage.abilities.mana.SimpleManaAbility; import mage.abilities.mana.SimpleManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.TimingRule;
import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicCard;
import java.util.UUID; import java.util.UUID;
@ -19,12 +23,7 @@ import java.util.UUID;
*/ */
public final class GaeasTouch extends CardImpl { public final class GaeasTouch extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Forest card"); private static final FilterCard filter = new FilterBasicCard(SubType.FOREST);
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.FOREST.getPredicate());
}
public GaeasTouch(UUID ownerId, CardSetInfo setInfo) { public GaeasTouch(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}{G}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{G}{G}");

View file

@ -8,7 +8,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
@ -19,7 +19,7 @@ import java.util.UUID;
*/ */
public final class GlimpseTheCore extends CardImpl { public final class GlimpseTheCore extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard(SubType.FOREST); private static final FilterCard filter = new FilterBasicCard(SubType.FOREST);
private static final FilterCard filter2 = new FilterCard("Cave card from your graveyard"); private static final FilterCard filter2 = new FilterCard("Cave card from your graveyard");
static { static {

View file

@ -9,8 +9,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.filter.StaticFilters;
import mage.filter.FilterCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -20,13 +19,6 @@ import java.util.UUID;
*/ */
public final class GloryheathLynx extends CardImpl { public final class GloryheathLynx extends CardImpl {
private static final FilterCard filter = new FilterCard("basic Plains card");
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.PLAINS.getPredicate());
}
public GloryheathLynx(UUID ownerId, CardSetInfo setInfo) { public GloryheathLynx(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
@ -40,7 +32,7 @@ public final class GloryheathLynx extends CardImpl {
// Whenever this creature attacks while saddled, search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. // Whenever this creature attacks while saddled, search your library for a basic Plains card, reveal it, put it into your hand, then shuffle.
this.addAbility(new AttacksWhileSaddledTriggeredAbility( this.addAbility(new AttacksWhileSaddledTriggeredAbility(
new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true) new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true)
)); ));
// Saddle 2 // Saddle 2

View file

@ -0,0 +1,88 @@
package mage.cards.g;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.AttacksTriggeredAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.discard.DiscardControllerEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.abilities.keyword.DeathtouchAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.game.Game;
import mage.watchers.common.DiscardedCardWatcher;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class GreenGoblinRevenant extends CardImpl {
public GreenGoblinRevenant(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}{R}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.GOBLIN);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.VILLAIN);
this.power = new MageInt(3);
this.toughness = new MageInt(3);
// Flying
this.addAbility(FlyingAbility.getInstance());
// Deathtouch
this.addAbility(DeathtouchAbility.getInstance());
// Whenever Green Goblin attacks, discard a card. Then draw a card for each card you've discarded this turn.
Ability ability = new AttacksTriggeredAbility(new DiscardControllerEffect(1));
ability.addEffect(new DrawCardSourceControllerEffect(GreenGoblinRevenantValue.instance).concatBy("Then"));
this.addAbility(ability.addHint(GreenGoblinRevenantValue.getHint()), new DiscardedCardWatcher());
}
private GreenGoblinRevenant(final GreenGoblinRevenant card) {
super(card);
}
@Override
public GreenGoblinRevenant copy() {
return new GreenGoblinRevenant(this);
}
}
enum GreenGoblinRevenantValue implements DynamicValue {
instance;
private static final Hint hint = new ValueHint("Cards you've discarded this turn", instance);
public static Hint getHint() {
return hint;
}
@Override
public int calculate(Game game, Ability sourceAbility, Effect effect) {
return DiscardedCardWatcher.getDiscarded(sourceAbility.getControllerId(), game);
}
@Override
public GreenGoblinRevenantValue copy() {
return instance;
}
@Override
public String toString() {
return "1";
}
@Override
public String getMessage() {
return "card you've discarded this turn";
}
}

View file

@ -1,7 +1,5 @@
package mage.cards.g; package mage.cards.g;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
@ -11,13 +9,16 @@ import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
*
* @author North * @author North
*/ */
public final class GrixisPanorama extends CardImpl { public final class GrixisPanorama extends CardImpl {
@ -25,7 +26,6 @@ public final class GrixisPanorama extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Island, Swamp, or Mountain card"); private static final FilterCard filter = new FilterCard("a basic Island, Swamp, or Mountain card");
static { static {
filter.add(CardType.LAND.getPredicate());
filter.add(SuperType.BASIC.getPredicate()); filter.add(SuperType.BASIC.getPredicate());
filter.add(Predicates.or( filter.add(Predicates.or(
SubType.ISLAND.getPredicate(), SubType.ISLAND.getPredicate(),
@ -34,7 +34,7 @@ public final class GrixisPanorama extends CardImpl {
} }
public GrixisPanorama(UUID ownerId, CardSetInfo setInfo) { public GrixisPanorama(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},""); super(ownerId, setInfo, new CardType[]{CardType.LAND}, "");
this.addAbility(new ColorlessManaAbility()); this.addAbility(new ColorlessManaAbility());
TargetCardInLibrary target = new TargetCardInLibrary(filter); TargetCardInLibrary target = new TargetCardInLibrary(filter);

View file

@ -9,8 +9,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID; import java.util.UUID;
@ -20,8 +19,6 @@ import java.util.UUID;
*/ */
public final class Groundskeeper extends CardImpl { public final class Groundskeeper extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("basic land card from your graveyard");
public Groundskeeper(UUID ownerId, CardSetInfo setInfo) { public Groundskeeper(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}");
this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.HUMAN);
@ -31,7 +28,7 @@ public final class Groundskeeper extends CardImpl {
// {1}{G}: Return target basic land card from your graveyard to your hand. // {1}{G}: Return target basic land card from your graveyard to your hand.
Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{1}{G}")); Ability ability = new SimpleActivatedAbility(new ReturnFromGraveyardToHandTargetEffect(), new ManaCostsImpl<>("{1}{G}"));
ability.addTarget(new TargetCardInYourGraveyard(filter)); ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_BASIC_LAND));
this.addAbility(ability); this.addAbility(ability);
} }

View file

@ -1,28 +1,26 @@
package mage.cards.h; package mage.cards.h;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.condition.common.ForetoldCondition; import mage.abilities.condition.common.ForetoldCondition;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ChooseCreatureTypeEffect; import mage.abilities.effects.common.ChooseCreatureTypeEffect;
import mage.abilities.keyword.ForetellAbility; import mage.abilities.keyword.ForetellAbility;
import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.CardsImpl;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.common.FilterBySubtypeCard; import mage.filter.FilterCard;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetCard;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID;
/** /**
*
* @author weirddan455 * @author weirddan455
*/ */
public final class HauntingVoyage extends CardImpl { public final class HauntingVoyage extends CardImpl {
@ -70,30 +68,15 @@ class HauntingVoyageEffect extends OneShotEffect {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId()); Player controller = game.getPlayer(source.getControllerId());
SubType chosenSubType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game); SubType chosenSubType = ChooseCreatureTypeEffect.getChosenCreatureType(source.getSourceId(), game);
if (controller != null && chosenSubType != null) { if (controller == null || chosenSubType == null) {
Set<Card> cardsToBattlefield = new LinkedHashSet<>();
if (!ForetoldCondition.instance.apply(game, source)) {
TargetCardInYourGraveyard target = new TargetCardInYourGraveyard(0, 2, new FilterBySubtypeCard(chosenSubType), true);
controller.chooseTarget(outcome, target, source, game);
for (UUID cardId : target.getTargets()) {
Card card = game.getCard(cardId);
if (card != null) {
cardsToBattlefield.add(card);
}
}
} else {
for (UUID cardId : controller.getGraveyard()) {
Card card = game.getCard(cardId);
if (card != null && card.hasSubtype(chosenSubType, game)) {
cardsToBattlefield.add(card);
}
}
}
if (!cardsToBattlefield.isEmpty()) {
controller.moveCards(cardsToBattlefield, Zone.BATTLEFIELD, source, game);
return true;
}
}
return false; return false;
} }
FilterCard filter = new FilterCard(chosenSubType);
if (ForetoldCondition.instance.apply(game, source)) {
return controller.moveCards(controller.getGraveyard().getCards(filter, game), Zone.BATTLEFIELD, source, game);
}
TargetCard target = new TargetCardInYourGraveyard(0, 2, filter, true);
controller.chooseTarget(outcome, target, source, game);
return controller.moveCards(new CardsImpl(target.getTargets()), Zone.BATTLEFIELD, source, game);
}
} }

View file

@ -13,7 +13,6 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBySubtypeCard;
import mage.game.permanent.token.HumanSoldierToken; import mage.game.permanent.token.HumanSoldierToken;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -24,7 +23,7 @@ import java.util.UUID;
*/ */
public final class HonoredKnightCaptain extends CardImpl { public final class HonoredKnightCaptain extends CardImpl {
private static final FilterCard filter = new FilterBySubtypeCard(SubType.EQUIPMENT); private static final FilterCard filter = new FilterCard(SubType.EQUIPMENT);
public HonoredKnightCaptain(UUID ownerId, CardSetInfo setInfo) { public HonoredKnightCaptain(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");

View file

@ -1,11 +1,8 @@
package mage.cards.i; package mage.cards.i;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.MorphAbility; import mage.abilities.keyword.MorphAbility;
@ -13,17 +10,20 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.common.FilterBySubtypeCard; import mage.filter.FilterCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
*
* @author fireshoes * @author fireshoes
*/ */
public final class ImperialHellkite extends CardImpl { public final class ImperialHellkite extends CardImpl {
private static final FilterCard filter = new FilterCard(SubType.DRAGON);
public ImperialHellkite(UUID ownerId, CardSetInfo setInfo) { public ImperialHellkite(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{5}{R}{R}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{5}{R}{R}");
this.subtype.add(SubType.DRAGON); this.subtype.add(SubType.DRAGON);
this.power = new MageInt(6); this.power = new MageInt(6);
this.toughness = new MageInt(6); this.toughness = new MageInt(6);
@ -35,9 +35,9 @@ public final class ImperialHellkite extends CardImpl {
this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{6}{R}{R}"))); this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{6}{R}{R}")));
// When Imperial Hellkite is turned face up, you may search your library for a Dragon card, reveal it, and put it into your hand. If you do, shuffle your library. // When Imperial Hellkite is turned face up, you may search your library for a Dragon card, reveal it, and put it into your hand. If you do, shuffle your library.
Effect effect = new SearchLibraryPutInHandEffect(new TargetCardInLibrary(0, 1, new FilterBySubtypeCard(SubType.DRAGON)), true); this.addAbility(new TurnedFaceUpSourceTriggeredAbility(
effect.setText("you may search your library for a Dragon card, reveal it, put it into your hand, then shuffle"); new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), false, true
this.addAbility(new TurnedFaceUpSourceTriggeredAbility(effect)); ));
} }
private ImperialHellkite(final ImperialHellkite card) { private ImperialHellkite(final ImperialHellkite card) {

View file

@ -1,11 +1,8 @@
package mage.cards.i; package mage.cards.i;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility; import mage.abilities.common.TurnedFaceUpSourceTriggeredAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.Effect;
import mage.abilities.effects.common.ReturnToHandFromGraveyardAllEffect; import mage.abilities.effects.common.ReturnToHandFromGraveyardAllEffect;
import mage.abilities.keyword.MorphAbility; import mage.abilities.keyword.MorphAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -13,18 +10,18 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBySubtypeCard;
import java.util.UUID;
/** /**
*
* @author cg5 * @author cg5
*/ */
public final class InfernalCaretaker extends CardImpl { public final class InfernalCaretaker extends CardImpl {
private static FilterCard zombieCard = new FilterBySubtypeCard(SubType.ZOMBIE); private static FilterCard zombieCard = new FilterCard(SubType.ZOMBIE);
public InfernalCaretaker(UUID ownerId, CardSetInfo setInfo) { public InfernalCaretaker(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{B}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{B}");
this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.CLERIC); this.subtype.add(SubType.CLERIC);
this.power = new MageInt(2); this.power = new MageInt(2);
@ -34,9 +31,8 @@ public final class InfernalCaretaker extends CardImpl {
this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{3}{B}"))); this.addAbility(new MorphAbility(this, new ManaCostsImpl<>("{3}{B}")));
// When Infernal Caretaker is turned face up, return all Zombie cards from all graveyards to their owners' hands. // When Infernal Caretaker is turned face up, return all Zombie cards from all graveyards to their owners' hands.
Effect effect = new ReturnToHandFromGraveyardAllEffect(zombieCard); this.addAbility(new TurnedFaceUpSourceTriggeredAbility(new ReturnToHandFromGraveyardAllEffect(zombieCard)
effect.setText("return all Zombie cards from all graveyards to their owners' hands"); .setText("return all Zombie cards from all graveyards to their owners' hands")));
this.addAbility(new TurnedFaceUpSourceTriggeredAbility(effect));
} }
private InfernalCaretaker(final InfernalCaretaker card) { private InfernalCaretaker(final InfernalCaretaker card) {

View file

@ -0,0 +1,74 @@
package mage.cards.i;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.RemoveCounterCost;
import mage.abilities.costs.common.TapSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.counter.AddCountersAllEffect;
import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType;
import mage.filter.FilterPermanent;
import mage.filter.StaticFilters;
import mage.filter.common.FilterControlledPermanent;
import mage.filter.predicate.Predicates;
import mage.target.TargetPermanent;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class IronSpiderStarkUpgrade extends CardImpl {
private static final FilterPermanent filter
= new FilterControlledPermanent("creature and/or Vehicle you control");
static {
filter.add(Predicates.or(
CardType.CREATURE.getPredicate(),
SubType.VEHICLE.getPredicate()
));
}
public IronSpiderStarkUpgrade(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SPIDER);
this.subtype.add(SubType.HERO);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// Vigilance
this.addAbility(VigilanceAbility.getInstance());
// {T}: Put a +1/+1 counter on each artifact creature and/or Vehicle you control.
this.addAbility(new SimpleActivatedAbility(
new AddCountersAllEffect(CounterType.P1P1.createInstance(), filter), new TapSourceCost()
));
// {2}, Remove two +1/+1 counters from among artifacts you control: Draw a card.
Ability ability = new SimpleActivatedAbility(new DrawCardSourceControllerEffect(1), new GenericManaCost(2));
ability.addCost(new RemoveCounterCost(new TargetPermanent(
1, 2, StaticFilters.FILTER_CONTROLLED_PERMANENT_ARTIFACT
), CounterType.P1P1, 2).setText("remove two +1/+1 counters from among creatures you control"));
this.addAbility(ability);
}
private IronSpiderStarkUpgrade(final IronSpiderStarkUpgrade card) {
super(card);
}
@Override
public IronSpiderStarkUpgrade copy() {
return new IronSpiderStarkUpgrade(this);
}
}

View file

@ -1,27 +1,27 @@
package mage.cards.i; package mage.cards.i;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility; import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.InvertCondition;
import mage.abilities.condition.common.SourceTappedCondition; import mage.abilities.condition.common.SourceTappedCondition;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.decorator.ConditionalContinuousEffect; import mage.abilities.decorator.ConditionalContinuousEffect;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardSourceControllerEffect; import mage.abilities.effects.common.DrawCardSourceControllerEffect;
import mage.abilities.effects.common.DrawCardsEqualToDifferenceEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect; import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.WardAbility;
import mage.constants.*;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.WardAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.game.Game; import mage.constants.CardType;
import mage.players.Player; import mage.constants.Duration;
import mage.constants.SubType;
import mage.constants.SuperType;
import java.util.UUID;
/** /**
*
* @author weirddan455 * @author weirddan455
*/ */
public final class IymrithDesertDoom extends CardImpl { public final class IymrithDesertDoom extends CardImpl {
@ -40,13 +40,13 @@ public final class IymrithDesertDoom extends CardImpl {
// Iymrith, Desert Doom has ward {4} as long as it's untapped. // Iymrith, Desert Doom has ward {4} as long as it's untapped.
this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect( this.addAbility(new SimpleStaticAbility(new ConditionalContinuousEffect(
new GainAbilitySourceEffect(new WardAbility(new GenericManaCost(4)), Duration.WhileOnBattlefield), new GainAbilitySourceEffect(new WardAbility(new GenericManaCost(4)), Duration.WhileOnBattlefield),
SourceTappedCondition.UNTAPPED, SourceTappedCondition.UNTAPPED, "{this} has ward {4} as long as it's untapped"
"{this} has ward {4} as long as it's untapped"
))); )));
// Whenever Iymrith deals combat damage to a player, draw a card. Then if you have fewer than three cards in hand, draw cards equal to the difference. // Whenever Iymrith deals combat damage to a player, draw a card. Then if you have fewer than three cards in hand, draw cards equal to the difference.
Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1), false); Ability ability = new DealsCombatDamageToAPlayerTriggeredAbility(new DrawCardSourceControllerEffect(1));
ability.addEffect(new IymrithDesertDoomEffect()); ability.addEffect(new DrawCardsEqualToDifferenceEffect(3)
.concatBy("Then if you have fewer than three cards in hand,"));
this.addAbility(ability); this.addAbility(ability);
} }
@ -59,33 +59,3 @@ public final class IymrithDesertDoom extends CardImpl {
return new IymrithDesertDoom(this); return new IymrithDesertDoom(this);
} }
} }
class IymrithDesertDoomEffect extends OneShotEffect {
IymrithDesertDoomEffect() {
super(Outcome.DrawCard);
this.staticText = "Then if you have fewer than three cards in hand, draw cards equal to the difference";
}
private IymrithDesertDoomEffect(final IymrithDesertDoomEffect effect) {
super(effect);
}
@Override
public IymrithDesertDoomEffect copy() {
return new IymrithDesertDoomEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
int handSize = controller.getHand().size();
if (handSize < 3) {
controller.drawCards(3 - handSize, source, game);
return true;
}
}
return false;
}
}

View file

@ -1,14 +1,13 @@
package mage.cards.j; package mage.cards.j;
import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility; import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.LoyaltyAbility; import mage.abilities.LoyaltyAbility;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.abilities.effects.common.CopyTargetStackObjectEffect; import mage.abilities.effects.common.CopyTargetStackObjectEffect;
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect; import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
import mage.abilities.effects.common.DrawDiscardControllerEffect; import mage.abilities.effects.common.DrawDiscardControllerEffect;
import mage.abilities.effects.common.MayExileCardFromHandPlottedEffect; import mage.abilities.effects.common.MayExileCardFromHandPlottedEffect;
import mage.abilities.effects.common.ruleModifying.CantCastDuringFirstThreeTurnsEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
@ -18,7 +17,6 @@ import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.game.stack.Spell; import mage.game.stack.Spell;
import mage.players.Player;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.UUID; import java.util.UUID;
@ -43,7 +41,7 @@ public final class JaceReawakened extends CardImpl {
this.setStartingLoyalty(3); this.setStartingLoyalty(3);
// You can't cast this spell during your first, second, or third turns of the game. // You can't cast this spell during your first, second, or third turns of the game.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new CantCastJaceReawakenedEffect())); this.addAbility(new SimpleStaticAbility(Zone.ALL, new CantCastDuringFirstThreeTurnsEffect()));
// +1: Draw a card, then discard a card. // +1: Draw a card, then discard a card.
this.addAbility(new LoyaltyAbility(new DrawDiscardControllerEffect(1, 1), 1)); this.addAbility(new LoyaltyAbility(new DrawDiscardControllerEffect(1, 1), 1));
@ -69,43 +67,6 @@ public final class JaceReawakened extends CardImpl {
} }
} }
/**
* Same as {@link mage.cards.s.SerraAvenger Serra Avenger}
*/
class CantCastJaceReawakenedEffect extends ContinuousRuleModifyingEffectImpl {
CantCastJaceReawakenedEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
staticText = "You can't cast this spell during your first, second, or third turns of the game";
}
private CantCastJaceReawakenedEffect(final CantCastJaceReawakenedEffect effect) {
super(effect);
}
@Override
public CantCastJaceReawakenedEffect copy() {
return new CantCastJaceReawakenedEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getSourceId().equals(source.getSourceId())) {
Player controller = game.getPlayer(source.getControllerId());
// it can be cast on other players turn 1 - 3 if some effect let allow you to do this
if (controller != null && controller.getTurns() <= 3 && game.isActivePlayer(source.getControllerId())) {
return true;
}
}
return false;
}
}
class JaceReawakenedDelayedTriggeredAbility extends DelayedTriggeredAbility { class JaceReawakenedDelayedTriggeredAbility extends DelayedTriggeredAbility {
JaceReawakenedDelayedTriggeredAbility() { JaceReawakenedDelayedTriggeredAbility() {

View file

@ -2,7 +2,6 @@
package mage.cards.j; package mage.cards.j;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost; import mage.abilities.costs.common.SacrificeSourceCost;
@ -12,13 +11,16 @@ import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
import mage.abilities.mana.ColorlessManaAbility; import mage.abilities.mana.ColorlessManaAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
*
* @author BetaSteward_at_googlemail.com * @author BetaSteward_at_googlemail.com
*/ */
public final class JundPanorama extends CardImpl { public final class JundPanorama extends CardImpl {
@ -26,7 +28,6 @@ public final class JundPanorama extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Swamp, Mountain, or Forest card"); private static final FilterCard filter = new FilterCard("a basic Swamp, Mountain, or Forest card");
static { static {
filter.add(CardType.LAND.getPredicate());
filter.add(SuperType.BASIC.getPredicate()); filter.add(SuperType.BASIC.getPredicate());
filter.add(Predicates.or( filter.add(Predicates.or(
SubType.SWAMP.getPredicate(), SubType.SWAMP.getPredicate(),
@ -35,7 +36,7 @@ public final class JundPanorama extends CardImpl {
} }
public JundPanorama(UUID ownerId, CardSetInfo setInfo) { public JundPanorama(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.LAND},null); super(ownerId, setInfo, new CardType[]{CardType.LAND}, null);
this.addAbility(new ColorlessManaAbility()); this.addAbility(new ColorlessManaAbility());
TargetCardInLibrary target = new TargetCardInLibrary(filter); TargetCardInLibrary target = new TargetCardInLibrary(filter);
Ability ability = new SimpleActivatedAbility(new SearchLibraryPutInPlayEffect(target, true), new GenericManaCost(1)); Ability ability = new SimpleActivatedAbility(new SearchLibraryPutInPlayEffect(target, true), new GenericManaCost(1));

View file

@ -1,7 +1,5 @@
package mage.cards.k; package mage.cards.k;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.Mode; import mage.abilities.Mode;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
@ -15,10 +13,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType;
import mage.constants.SuperType;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterCard; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.game.permanent.token.Construct2Token; import mage.game.permanent.token.Construct2Token;
@ -27,20 +23,13 @@ import mage.target.common.TargetCardInLibrary;
import mage.target.common.TargetControlledCreaturePermanent; import mage.target.common.TargetControlledCreaturePermanent;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.UUID;
/** /**
*
* @author weirddan455 * @author weirddan455
*/ */
public final class KaylasCommand extends CardImpl { public final class KaylasCommand extends CardImpl {
private static final FilterCard filter
= new FilterCard("a basic Plains card");
static {
filter.add(SubType.PLAINS.getPredicate());
filter.add(SuperType.BASIC.getPredicate());
}
public KaylasCommand(UUID ownerId, CardSetInfo setInfo) { public KaylasCommand(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}{W}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{1}{W}{W}");
@ -55,7 +44,7 @@ public final class KaylasCommand extends CardImpl {
this.getSpellAbility().addMode(new Mode(new KaylasCommandCounterEffect())); this.getSpellAbility().addMode(new Mode(new KaylasCommandCounterEffect()));
// * Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. // * Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle.
this.getSpellAbility().addMode(new Mode(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true))); this.getSpellAbility().addMode(new Mode(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true)));
// * You gain 2 life and scry 2. // * You gain 2 life and scry 2.
Mode mode = new Mode(new GainLifeEffect(2)); Mode mode = new Mode(new GainLifeEffect(2));

View file

@ -10,9 +10,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.TargetController; import mage.constants.TargetController;
import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
@ -26,13 +24,6 @@ import java.util.UUID;
*/ */
public final class KeeperOfTheAccord extends CardImpl { public final class KeeperOfTheAccord extends CardImpl {
private static final FilterCard filter = new FilterCard("basic Plains card");
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.PLAINS.getPredicate());
}
public KeeperOfTheAccord(UUID ownerId, CardSetInfo setInfo) { public KeeperOfTheAccord(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
@ -48,7 +39,7 @@ public final class KeeperOfTheAccord extends CardImpl {
// At the beginning of each opponent's end step, if that player controls more lands than you, you may search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle your library. // At the beginning of each opponent's end step, if that player controls more lands than you, you may search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle your library.
this.addAbility(new BeginningOfEndStepTriggeredAbility( this.addAbility(new BeginningOfEndStepTriggeredAbility(
TargetController.OPPONENT, new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true), true TargetController.OPPONENT, new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true), true
).withInterveningIf(KeeperOfTheAccordCondition.LANDS)); ).withInterveningIf(KeeperOfTheAccordCondition.LANDS));
} }

View file

@ -12,7 +12,6 @@ import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBySubtypeCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -22,7 +21,7 @@ import java.util.UUID;
*/ */
public final class KnightOfTheWhiteOrchid extends CardImpl { public final class KnightOfTheWhiteOrchid extends CardImpl {
private static final FilterCard filter = new FilterBySubtypeCard(SubType.PLAINS); private static final FilterCard filter = new FilterCard(SubType.PLAINS);
private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS);
public KnightOfTheWhiteOrchid(UUID ownerId, CardSetInfo setInfo) { public KnightOfTheWhiteOrchid(UUID ownerId, CardSetInfo setInfo) {

View file

@ -1,7 +1,5 @@
package mage.cards.k; package mage.cards.k;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect; import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
@ -9,17 +7,20 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.common.FilterBySubtypeCard; import mage.filter.FilterCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
*
* @author North * @author North
*/ */
public final class KorCartographer extends CardImpl { public final class KorCartographer extends CardImpl {
private static final FilterCard filter = new FilterCard(SubType.PLAINS);
public KorCartographer(UUID ownerId, CardSetInfo setInfo) { public KorCartographer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{3}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}");
this.subtype.add(SubType.KOR); this.subtype.add(SubType.KOR);
this.subtype.add(SubType.SCOUT); this.subtype.add(SubType.SCOUT);
@ -27,7 +28,9 @@ public final class KorCartographer extends CardImpl {
this.toughness = new MageInt(2); this.toughness = new MageInt(2);
// When Kor Cartographer enters the battlefield, you may search your library for a Plains card, put it onto the battlefield tapped, then shuffle your library. // When Kor Cartographer enters the battlefield, you may search your library for a Plains card, put it onto the battlefield tapped, then shuffle your library.
this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(new FilterBySubtypeCard(SubType.PLAINS)), true), true)); this.addAbility(new EntersBattlefieldTriggeredAbility(
new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true), true
));
} }
private KorCartographer(final KorCartographer card) { private KorCartographer(final KorCartographer card) {

View file

@ -2,16 +2,20 @@ package mage.cards.k;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.LoyaltyAbility; import mage.abilities.LoyaltyAbility;
import mage.abilities.dynamicvalue.DynamicValue;
import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount;
import mage.abilities.effects.common.DamageTargetEffect; import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.GetEmblemEffect; import mage.abilities.effects.common.GetEmblemEffect;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.abilities.hint.Hint;
import mage.abilities.hint.ValueHint;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicCard;
import mage.filter.common.FilterControlledPermanent; import mage.filter.common.FilterControlledPermanent;
import mage.game.command.emblems.KothFireOfResistanceEmblem; import mage.game.command.emblems.KothFireOfResistanceEmblem;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -24,14 +28,11 @@ import java.util.UUID;
*/ */
public final class KothFireOfResistance extends CardImpl { public final class KothFireOfResistance extends CardImpl {
private static final FilterCard filter = new FilterCard("basic Mountain card"); private static final FilterCard filter = new FilterBasicCard(SubType.MOUNTAIN);
private static final FilterControlledPermanent filter2 = new FilterControlledPermanent("Mountains you control"); private static final DynamicValue xValue = new PermanentsOnBattlefieldCount(
new FilterControlledPermanent(SubType.MOUNTAIN, "Mountains you control")
static { );
filter.add(SuperType.BASIC.getPredicate()); private static final Hint hint = new ValueHint(xValue.getMessage(), xValue);
filter.add(SubType.MOUNTAIN.getPredicate());
filter2.add(SubType.MOUNTAIN.getPredicate());
}
public KothFireOfResistance(UUID ownerId, CardSetInfo setInfo) { public KothFireOfResistance(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{R}"); super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{R}{R}");
@ -44,10 +45,10 @@ public final class KothFireOfResistance extends CardImpl {
this.addAbility(new LoyaltyAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), 2)); this.addAbility(new LoyaltyAbility(new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), 2));
// 3: Koth, Fire of Resistance deals damage to target creature equal to the number of Mountains you control. // 3: Koth, Fire of Resistance deals damage to target creature equal to the number of Mountains you control.
Ability ability = new LoyaltyAbility(new DamageTargetEffect(new PermanentsOnBattlefieldCount(filter2)) Ability ability = new LoyaltyAbility(new DamageTargetEffect(xValue)
.setText("{this} deals damage to target creature equal to the number of Mountains you control"), -3); .setText("{this} deals damage to target creature equal to the number of Mountains you control"), -3);
ability.addTarget(new TargetCreaturePermanent()); ability.addTarget(new TargetCreaturePermanent());
this.addAbility(ability); this.addAbility(ability.addHint(hint));
// 7: You get an emblem with "Whenever a Mountain you control enters, this emblem deals 4 damage to any target." // 7: You get an emblem with "Whenever a Mountain you control enters, this emblem deals 4 damage to any target."
this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new KothFireOfResistanceEmblem()), -7)); this.addAbility(new LoyaltyAbility(new GetEmblemEffect(new KothFireOfResistanceEmblem()), -7));

View file

@ -7,9 +7,9 @@ import mage.abilities.condition.Condition;
import mage.abilities.condition.common.CardsInHandCondition; import mage.abilities.condition.common.CardsInHandCondition;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
import mage.abilities.costs.CostImpl; import mage.abilities.costs.CostImpl;
import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.CastSourceTriggeredAbility; import mage.abilities.effects.common.CastSourceTriggeredAbility;
import mage.abilities.effects.common.CounterTargetEffect; import mage.abilities.effects.common.CounterTargetEffect;
import mage.abilities.effects.common.DrawCardsEqualToDifferenceEffect;
import mage.abilities.keyword.MenaceAbility; import mage.abilities.keyword.MenaceAbility;
import mage.cards.Card; import mage.cards.Card;
import mage.cards.CardImpl; import mage.cards.CardImpl;
@ -44,7 +44,7 @@ public final class KozilekTheGreatDistortion extends CardImpl {
this.toughness = new MageInt(12); this.toughness = new MageInt(12);
// When you cast Kozilek, the Great Distortion, if you have fewer than seven cards in hand, draw cards equal to the difference. // When you cast Kozilek, the Great Distortion, if you have fewer than seven cards in hand, draw cards equal to the difference.
this.addAbility(new CastSourceTriggeredAbility(new KozilekDrawEffect(), false).withInterveningIf(condition)); this.addAbility(new CastSourceTriggeredAbility(new DrawCardsEqualToDifferenceEffect(7)).withInterveningIf(condition));
// Menace // Menace
this.addAbility(new MenaceAbility(false)); this.addAbility(new MenaceAbility(false));
@ -65,33 +65,6 @@ public final class KozilekTheGreatDistortion extends CardImpl {
} }
} }
class KozilekDrawEffect extends OneShotEffect {
KozilekDrawEffect() {
super(Outcome.DrawCard);
this.staticText = "draw cards equal to the difference";
}
private KozilekDrawEffect(final KozilekDrawEffect effect) {
super(effect);
}
@Override
public KozilekDrawEffect copy() {
return new KozilekDrawEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller != null) {
controller.drawCards(7 - controller.getHand().size(), source, game);
return true;
}
return false;
}
}
class KozilekDiscardCost extends CostImpl { class KozilekDiscardCost extends CostImpl {
public KozilekDiscardCost() { public KozilekDiscardCost() {
@ -156,5 +129,4 @@ class KozilekDiscardCost extends CostImpl {
public KozilekDiscardCost copy() { public KozilekDiscardCost copy() {
return new KozilekDiscardCost(this); return new KozilekDiscardCost(this);
} }
} }

View file

@ -1,8 +1,6 @@
package mage.cards.l; package mage.cards.l;
import java.util.List;
import java.util.UUID;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.DelayedTriggeredAbility; import mage.abilities.DelayedTriggeredAbility;
import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.common.SimpleActivatedAbility;
@ -14,23 +12,21 @@ import mage.abilities.dynamicvalue.common.StaticValue;
import mage.abilities.effects.Effect; import mage.abilities.effects.Effect;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.DrawCardTargetEffect; import mage.abilities.effects.common.DrawCardTargetEffect;
import mage.cards.Card; import mage.cards.*;
import mage.cards.Cards;
import mage.cards.CardImpl;
import mage.cards.CardsImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.common.FilterBasicLandCard; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.TargetPlayer; import mage.target.TargetPlayer;
import mage.target.common.TargetCardInGraveyard; import mage.target.common.TargetCardInGraveyard;
import mage.target.targetpointer.FixedTarget; import mage.target.targetpointer.FixedTarget;
import java.util.List;
import java.util.UUID;
/** /**
*
* @author ThomasLerner, LevelX2 & L_J * @author ThomasLerner, LevelX2 & L_J
*/ */
public final class LodestoneBauble extends CardImpl { public final class LodestoneBauble extends CardImpl {
@ -61,7 +57,7 @@ public final class LodestoneBauble extends CardImpl {
class LodestoneBaubleTarget extends TargetCardInGraveyard { class LodestoneBaubleTarget extends TargetCardInGraveyard {
public LodestoneBaubleTarget() { public LodestoneBaubleTarget() {
super(0, 4, new FilterBasicLandCard("basic land cards from a player's graveyard")); super(0, 4, StaticFilters.FILTER_CARD_BASIC_LANDS);
} }
private LodestoneBaubleTarget(final LodestoneBaubleTarget target) { private LodestoneBaubleTarget(final LodestoneBaubleTarget target) {

View file

@ -10,9 +10,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -22,7 +20,6 @@ import java.util.UUID;
*/ */
public final class LoyalWarhound extends CardImpl { public final class LoyalWarhound extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard(SubType.PLAINS);
private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS);
public LoyalWarhound(UUID ownerId, CardSetInfo setInfo) { public LoyalWarhound(UUID ownerId, CardSetInfo setInfo) {
@ -38,7 +35,7 @@ public final class LoyalWarhound extends CardImpl {
// When Loyal Warhound enters the battlefield, if an opponent controls more lands than you, // When Loyal Warhound enters the battlefield, if an opponent controls more lands than you,
// search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle. // search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle.
this.addAbility(new EntersBattlefieldTriggeredAbility( this.addAbility(new EntersBattlefieldTriggeredAbility(
new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true) new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true)
).withInterveningIf(condition)); ).withInterveningIf(condition));
} }

View file

@ -6,8 +6,7 @@ import mage.abilities.keyword.CyclingAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.filter.FilterCard; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -17,14 +16,12 @@ import java.util.UUID;
*/ */
public final class MigrationPath extends CardImpl { public final class MigrationPath extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("basic land cards");
public MigrationPath(UUID ownerId, CardSetInfo setInfo) { public MigrationPath(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}");
// Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle your library. // Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle your library.
this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect( this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(
new TargetCardInLibrary(0, 2, filter), true new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LANDS), true
)); ));
// Cycling {2} // Cycling {2}

View file

@ -10,8 +10,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -21,12 +21,7 @@ import java.util.UUID;
*/ */
public final class NeverwinterDryad extends CardImpl { public final class NeverwinterDryad extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Forest card"); private static final FilterCard filter = new FilterBasicCard(SubType.FOREST);
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.FOREST.getPredicate());
}
public NeverwinterDryad(UUID ownerId, CardSetInfo setInfo) { public NeverwinterDryad(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{G}");

View file

@ -12,6 +12,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicCard;
import mage.filter.common.FilterLandPermanent; import mage.filter.common.FilterLandPermanent;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -22,12 +23,7 @@ import java.util.UUID;
*/ */
public final class NissaVastwoodSeer extends CardImpl { public final class NissaVastwoodSeer extends CardImpl {
private static final FilterCard filter = new FilterCard("basic Forest card"); private static final FilterCard filter = new FilterBasicCard(SubType.FOREST);
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.FOREST.getPredicate());
}
private static final Condition condition = new PermanentsOnTheBattlefieldCondition( private static final Condition condition = new PermanentsOnTheBattlefieldCondition(
new FilterLandPermanent("you control seven or more lands"), new FilterLandPermanent("you control seven or more lands"),

View file

@ -1,7 +1,6 @@
package mage.cards.n; package mage.cards.n;
import java.util.UUID;
import mage.abilities.condition.common.SpellMasteryCondition; import mage.abilities.condition.common.SpellMasteryCondition;
import mage.abilities.decorator.ConditionalOneShotEffect; import mage.abilities.decorator.ConditionalOneShotEffect;
import mage.abilities.effects.common.search.SearchLibraryPutOntoBattlefieldTappedRestInHandEffect; import mage.abilities.effects.common.search.SearchLibraryPutOntoBattlefieldTappedRestInHandEffect;
@ -9,22 +8,18 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
*
* @author LevelX2 * @author LevelX2
*/ */
public final class NissasPilgrimage extends CardImpl { public final class NissasPilgrimage extends CardImpl {
private static final FilterCard filter = new FilterCard("basic Forest cards"); private static final FilterCard filter = new FilterBasicCard(SubType.FOREST, "basic Forest cards");
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.FOREST.getPredicate());
}
public NissasPilgrimage(UUID ownerId, CardSetInfo setInfo) { public NissasPilgrimage(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{G}");

View file

@ -8,10 +8,10 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.FilterPermanent; import mage.filter.FilterPermanent;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicCard;
import mage.filter.common.FilterControlledPlaneswalkerPermanent; import mage.filter.common.FilterControlledPlaneswalkerPermanent;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -22,14 +22,9 @@ import java.util.UUID;
*/ */
public final class NissasTriumph extends CardImpl { public final class NissasTriumph extends CardImpl {
private static final FilterCard filter = new FilterCard("basic Forest cards"); private static final FilterCard filter = new FilterBasicCard(SubType.FOREST, "basic Forest cards");
private static final FilterPermanent filter2 = new FilterControlledPlaneswalkerPermanent(SubType.NISSA); private static final FilterPermanent filter2 = new FilterControlledPlaneswalkerPermanent(SubType.NISSA);
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.FOREST.getPredicate());
}
private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter2); private static final Condition condition = new PermanentsOnTheBattlefieldCondition(filter2);
public NissasTriumph(UUID ownerId, CardSetInfo setInfo) { public NissasTriumph(UUID ownerId, CardSetInfo setInfo) {

View file

@ -1,10 +1,6 @@
package mage.cards.o; package mage.cards.o;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability; import mage.abilities.Ability;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
@ -16,13 +12,16 @@ import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.common.FilterBasicLandCard; import mage.filter.StaticFilters;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.players.Player;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/** /**
*
* @author TheElk801 * @author TheElk801
*/ */
public final class OldGrowthDryads extends CardImpl { public final class OldGrowthDryads extends CardImpl {
@ -70,7 +69,7 @@ class OldGrowthDryadsEffect extends OneShotEffect {
for (UUID opponentId : game.getOpponents(source.getControllerId())) { for (UUID opponentId : game.getOpponents(source.getControllerId())) {
Player opponent = game.getPlayer(opponentId); Player opponent = game.getPlayer(opponentId);
if (opponent != null && opponent.chooseUse(Outcome.PutLandInPlay, "Search your library for a basic land card and put it onto the battlefield tapped?", source, game)) { if (opponent != null && opponent.chooseUse(Outcome.PutLandInPlay, "Search your library for a basic land card and put it onto the battlefield tapped?", source, game)) {
TargetCardInLibrary target = new TargetCardInLibrary(new FilterBasicLandCard()); TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND);
if (opponent.searchLibrary(target, source, game)) { if (opponent.searchLibrary(target, source, game)) {
Card targetCard = opponent.getLibrary().getCard(target.getFirstTarget(), game); Card targetCard = opponent.getLibrary().getCard(target.getFirstTarget(), game);
if (targetCard != null) { if (targetCard != null) {

View file

@ -8,7 +8,6 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
/** /**

View file

@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -25,7 +25,7 @@ import java.util.UUID;
*/ */
public final class PerilousLandscape extends CardImpl { public final class PerilousLandscape extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("a basic Island, Mountain, or Plains card"); private static final FilterCard filter = new FilterBasicCard("a basic Island, Mountain, or Plains card");
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(

View file

@ -10,9 +10,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.FilterCard; import mage.filter.StaticFilters;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -22,13 +21,6 @@ import java.util.UUID;
*/ */
public final class PilgrimOfTheAges extends CardImpl { public final class PilgrimOfTheAges extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Plains card");
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.PLAINS.getPredicate());
}
public PilgrimOfTheAges(UUID ownerId, CardSetInfo setInfo) { public PilgrimOfTheAges(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}");
@ -38,7 +30,7 @@ public final class PilgrimOfTheAges extends CardImpl {
// When Pilgrim of the Ages enters the battlefield, you may search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. // When Pilgrim of the Ages enters the battlefield, you may search your library for a basic Plains card, reveal it, put it into your hand, then shuffle.
this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect( this.addAbility(new EntersBattlefieldTriggeredAbility(new SearchLibraryPutInHandEffect(
new TargetCardInLibrary(filter), true new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true
), true)); ), true));
// {6}: Return Pilgrim of the Ages from your graveyard to your hand. // {6}: Return Pilgrim of the Ages from your graveyard to your hand.

View file

@ -8,8 +8,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -19,12 +19,7 @@ import java.util.UUID;
*/ */
public final class Plasmancer extends CardImpl { public final class Plasmancer extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Swamp card"); private static final FilterCard filter = new FilterBasicCard(SubType.SWAMP);
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.SWAMP.getPredicate());
}
public Plasmancer(UUID ownerId, CardSetInfo setInfo) { public Plasmancer(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{B}{B}"); super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{2}{B}{B}");

View file

@ -11,7 +11,6 @@ import mage.constants.PutCards;
import mage.constants.SubType; import mage.constants.SubType;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBySubtypeCard;
import java.util.UUID; import java.util.UUID;
@ -20,7 +19,7 @@ import java.util.UUID;
*/ */
public final class PulsarSquadronAce extends CardImpl { public final class PulsarSquadronAce extends CardImpl {
private static final FilterCard filter = new FilterBySubtypeCard(SubType.SPACECRAFT); private static final FilterCard filter = new FilterCard(SubType.SPACECRAFT);
public PulsarSquadronAce(UUID ownerId, CardSetInfo setInfo) { public PulsarSquadronAce(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");

View file

@ -14,12 +14,14 @@ import mage.abilities.effects.common.UntapSourceEffect;
import mage.abilities.effects.common.continuous.AddCardSubtypeAllEffect; import mage.abilities.effects.common.continuous.AddCardSubtypeAllEffect;
import mage.abilities.effects.common.continuous.GainAbilityAllEffect; import mage.abilities.effects.common.continuous.GainAbilityAllEffect;
import mage.abilities.hint.ConditionHint; import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.Hint;
import mage.abilities.token.FoodAbility; import mage.abilities.token.FoodAbility;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility; import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.*;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.watchers.common.PlayerGainedLifeWatcher;
import java.util.UUID; import java.util.UUID;
@ -29,6 +31,7 @@ import java.util.UUID;
public final class RagostDeftGastronaut extends CardImpl { public final class RagostDeftGastronaut extends CardImpl {
private static final Condition condition = new YouGainedLifeCondition(); private static final Condition condition = new YouGainedLifeCondition();
private static final Hint hint = new ConditionHint(condition);
public RagostDeftGastronaut(UUID ownerId, CardSetInfo setInfo) { public RagostDeftGastronaut(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{W}");
@ -60,7 +63,7 @@ public final class RagostDeftGastronaut extends CardImpl {
// At the beginning of each end step, if you gained life this turn, untap Ragost. // At the beginning of each end step, if you gained life this turn, untap Ragost.
this.addAbility(new BeginningOfEndStepTriggeredAbility( this.addAbility(new BeginningOfEndStepTriggeredAbility(
TargetController.ANY, new UntapSourceEffect(), false, condition TargetController.ANY, new UntapSourceEffect(), false, condition
).addHint(new ConditionHint(condition))); ).addHint(hint), new PlayerGainedLifeWatcher());
} }
private RagostDeftGastronaut(final RagostDeftGastronaut card) { private RagostDeftGastronaut(final RagostDeftGastronaut card) {

View file

@ -89,7 +89,7 @@ class RanarTheEverWatchfulCostReductionEffect extends CostModificationEffectImpl
public boolean applies(Ability abilityToModify, Ability source, Game game) { public boolean applies(Ability abilityToModify, Ability source, Game game) {
ForetoldWatcher watcher = game.getState().getWatcher(ForetoldWatcher.class); ForetoldWatcher watcher = game.getState().getWatcher(ForetoldWatcher.class);
return (watcher != null return (watcher != null
&& watcher.countNumberForetellThisTurn() == 0 && watcher.getPlayerForetellCountThisTurn(source.getControllerId()) == 0
&& abilityToModify.isControlledBy(source.getControllerId()) && abilityToModify.isControlledBy(source.getControllerId())
&& abilityToModify instanceof ForetellAbility); && abilityToModify instanceof ForetellAbility);
} }

View file

@ -5,9 +5,7 @@ import mage.abilities.effects.common.search.SearchLibraryPutInPlayEffect;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -17,8 +15,6 @@ import java.util.UUID;
*/ */
public final class RoilingRegrowth extends CardImpl { public final class RoilingRegrowth extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("basic land cards");
public RoilingRegrowth(UUID ownerId, CardSetInfo setInfo) { public RoilingRegrowth(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}"); super(ownerId, setInfo, new CardType[]{CardType.INSTANT}, "{2}{G}");
@ -27,7 +23,7 @@ public final class RoilingRegrowth extends CardImpl {
StaticFilters.FILTER_LAND, 1, null StaticFilters.FILTER_LAND, 1, null
).setText("Sacrifice a land.")); ).setText("Sacrifice a land."));
this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect( this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(
new TargetCardInLibrary(0, 2, filter), true new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LANDS), true
)); ));
} }

View file

@ -1,20 +1,20 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility; import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.GainLifeEffect; import mage.abilities.effects.common.GainLifeEffect;
import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect; import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.cards.OmenCard;
import mage.constants.SubType;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.cards.OmenCard;
import mage.constants.CardType; import mage.constants.CardType;
import mage.filter.common.FilterBasicLandCard; import mage.constants.SubType;
import mage.filter.StaticFilters;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID;
/** /**
*
* @author Jmlundeen * @author Jmlundeen
*/ */
public final class SaguWildling extends OmenCard { public final class SaguWildling extends OmenCard {
@ -34,7 +34,7 @@ public final class SaguWildling extends OmenCard {
// Roost Seek // Roost Seek
// Search your library for a basic land card, reveal it, put it into your hand, then shuffle. // Search your library for a basic land card, reveal it, put it into your hand, then shuffle.
TargetCardInLibrary target = new TargetCardInLibrary(new FilterBasicLandCard()); TargetCardInLibrary target = new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND);
this.getSpellCard().getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(target, true)); this.getSpellCard().getSpellAbility().addEffect(new SearchLibraryPutInHandEffect(target, true));
this.finalizeOmen(); this.finalizeOmen();
} }

View file

@ -10,8 +10,6 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -22,13 +20,6 @@ import java.util.UUID;
*/ */
public final class ScoutingHawk extends CardImpl { public final class ScoutingHawk extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Plains card");
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.PLAINS.getPredicate());
}
private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS);
public ScoutingHawk(UUID ownerId, CardSetInfo setInfo) { public ScoutingHawk(UUID ownerId, CardSetInfo setInfo) {
@ -43,7 +34,7 @@ public final class ScoutingHawk extends CardImpl {
// Keen Sight When Scouting Hawk enters the battlefield, if an opponent controls more lands than you, search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle. // Keen Sight When Scouting Hawk enters the battlefield, if an opponent controls more lands than you, search your library for a basic Plains card, put it onto the battlefield tapped, then shuffle.
this.addAbility(new EntersBattlefieldTriggeredAbility( this.addAbility(new EntersBattlefieldTriggeredAbility(
new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true) new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true)
).withInterveningIf(condition).withFlavorWord("Keen Sight")); ).withInterveningIf(condition).withFlavorWord("Keen Sight"));
} }

View file

@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -25,7 +25,7 @@ import java.util.UUID;
*/ */
public final class SeethingLandscape extends CardImpl { public final class SeethingLandscape extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("a basic Island, Swamp, or Mountain card"); private static final FilterCard filter = new FilterBasicCard("a basic Island, Swamp, or Mountain card");
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(

View file

@ -1,24 +1,17 @@
package mage.cards.s; package mage.cards.s;
import java.util.UUID;
import mage.MageInt; import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility; import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.ruleModifying.CantCastDuringFirstThreeTurnsEffect;
import mage.abilities.keyword.FlyingAbility; import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.VigilanceAbility; import mage.abilities.keyword.VigilanceAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game;
import mage.game.events.GameEvent; import java.util.UUID;
import mage.game.events.GameEvent.EventType;
import mage.players.Player;
/** /**
@ -27,21 +20,20 @@ import mage.players.Player;
public final class SerraAvenger extends CardImpl { public final class SerraAvenger extends CardImpl {
public SerraAvenger(UUID ownerId, CardSetInfo setInfo) { public SerraAvenger(UUID ownerId, CardSetInfo setInfo) {
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{W}{W}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{W}{W}");
this.subtype.add(SubType.ANGEL); this.subtype.add(SubType.ANGEL);
this.power = new MageInt(3); this.power = new MageInt(3);
this.toughness = new MageInt(3); this.toughness = new MageInt(3);
// You can't cast Serra Avenger during your first, second, or third turns of the game. // You can't cast Serra Avenger during your first, second, or third turns of the game.
this.addAbility(new SimpleStaticAbility(Zone.ALL, new CantCastSerraAvengerEffect())); this.addAbility(new SimpleStaticAbility(Zone.ALL, new CantCastDuringFirstThreeTurnsEffect()));
// Flying // Flying
this.addAbility(FlyingAbility.getInstance()); this.addAbility(FlyingAbility.getInstance());
// Vigilance // Vigilance
this.addAbility(VigilanceAbility.getInstance()); this.addAbility(VigilanceAbility.getInstance());
} }
private SerraAvenger(final SerraAvenger card) { private SerraAvenger(final SerraAvenger card) {
@ -53,37 +45,3 @@ public final class SerraAvenger extends CardImpl {
return new SerraAvenger(this); return new SerraAvenger(this);
} }
} }
class CantCastSerraAvengerEffect extends ContinuousRuleModifyingEffectImpl {
CantCastSerraAvengerEffect() {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
staticText = "You can't cast this spell during your first, second, or third turns of the game";
}
private CantCastSerraAvengerEffect(final CantCastSerraAvengerEffect effect) {
super(effect);
}
@Override
public CantCastSerraAvengerEffect copy() {
return new CantCastSerraAvengerEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (event.getSourceId().equals(source.getSourceId())) {
Player controller = game.getPlayer(source.getControllerId());
// it can be cast on other players turn 1 - 3 if some effect let allow you to do this
if (controller != null && controller.getTurns() <= 3 && game.isActivePlayer(source.getControllerId())) {
return true;
}
}
return false;
}
}

View file

@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -25,7 +25,7 @@ import java.util.UUID;
*/ */
public final class ShatteredLandscape extends CardImpl { public final class ShatteredLandscape extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("a basic Mountain, Plains, or Swamp card"); private static final FilterCard filter = new FilterBasicCard("a basic Mountain, Plains, or Swamp card");
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(

View file

@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -25,7 +25,7 @@ import java.util.UUID;
*/ */
public final class ShelteringLandscape extends CardImpl { public final class ShelteringLandscape extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("a basic Mountain, Forest, or Plains card"); private static final FilterCard filter = new FilterBasicCard("a basic Mountain, Forest, or Plains card");
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(

View file

@ -0,0 +1,68 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleActivatedAbility;
import mage.abilities.costs.common.SacrificeSourceCost;
import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
import mage.abilities.effects.common.continuous.GainAbilitySourceEffect;
import mage.abilities.keyword.FlashAbility;
import mage.abilities.keyword.FlyingAbility;
import mage.abilities.keyword.HexproofAbility;
import mage.abilities.keyword.IndestructibleAbility;
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.StaticFilters;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class SpectacularSpiderMan extends CardImpl {
public SpectacularSpiderMan(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SPIDER);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.HERO);
this.power = new MageInt(3);
this.toughness = new MageInt(2);
// Flash
this.addAbility(FlashAbility.getInstance());
// {1}: Spectacular Spider-Man gains flying until end of turn.
this.addAbility(new SimpleActivatedAbility(
new GainAbilitySourceEffect(FlyingAbility.getInstance(), Duration.EndOfTurn), new GenericManaCost(1)
));
// {1}, Sacrifice Spectacular Spider-Man: Creatures you control gain hexproof and indestructible until end of turn.
Ability ability = new SimpleActivatedAbility(new GainAbilityControlledEffect(
HexproofAbility.getInstance(), Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURES
).setText("creatures you control gain hexproof"), new GenericManaCost(1));
ability.addCost(new SacrificeSourceCost());
ability.addEffect(new GainAbilityControlledEffect(
IndestructibleAbility.getInstance(), Duration.EndOfTurn,
StaticFilters.FILTER_PERMANENT_CREATURES
).setText("and indestructible until end of turn"));
this.addAbility(ability);
}
private SpectacularSpiderMan(final SpectacularSpiderMan card) {
super(card);
}
@Override
public SpectacularSpiderMan copy() {
return new SpectacularSpiderMan(this);
}
}

View file

@ -0,0 +1,129 @@
package mage.cards.s;
import mage.MageInt;
import mage.abilities.Ability;
import mage.abilities.common.SimpleStaticAbility;
import mage.abilities.condition.Condition;
import mage.abilities.dynamicvalue.common.SourcePermanentPowerValue;
import mage.abilities.effects.common.DamageTargetEffect;
import mage.abilities.effects.common.ruleModifying.CantCastDuringFirstThreeTurnsEffect;
import mage.abilities.hint.ConditionHint;
import mage.abilities.hint.Hint;
import mage.abilities.keyword.DoubleStrikeAbility;
import mage.abilities.keyword.VigilanceAbility;
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.*;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.game.stack.Spell;
import mage.target.common.TargetAnyTarget;
import mage.watchers.Watcher;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class SpiderMan2099 extends CardImpl {
public SpiderMan2099(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}{R}");
this.supertype.add(SuperType.LEGENDARY);
this.subtype.add(SubType.SPIDER);
this.subtype.add(SubType.HUMAN);
this.subtype.add(SubType.HERO);
this.power = new MageInt(2);
this.toughness = new MageInt(3);
// From the Future -- You can't cast Spider-Man 2099 during your first, second, or third turns of the game.
this.addAbility(new SimpleStaticAbility(
Zone.ALL, new CantCastDuringFirstThreeTurnsEffect("{this}")
).withFlavorWord("From the Future"));
// Double strike
this.addAbility(DoubleStrikeAbility.getInstance());
// Vigilance
this.addAbility(VigilanceAbility.getInstance());
// At the beginning of your end step, if you've played a land or cast a spell this turn from anywhere other than your hand, Spider-Man 2099 deals damage equal to his power to any target.
Ability ability = new BeginningOfEndStepTriggeredAbility(
new DamageTargetEffect(SourcePermanentPowerValue.NOT_NEGATIVE)
.setText("{this} deals damage equal to his power to any target")
).withInterveningIf(SpiderMan2099Condition.instance);
ability.addTarget(new TargetAnyTarget());
this.addAbility(ability.addHint(SpiderMan2099Condition.getHint()), new SpiderMan2099Watcher());
}
private SpiderMan2099(final SpiderMan2099 card) {
super(card);
}
@Override
public SpiderMan2099 copy() {
return new SpiderMan2099(this);
}
}
enum SpiderMan2099Condition implements Condition {
instance;
private static final Hint hint = new ConditionHint(instance);
public static Hint getHint() {
return hint;
}
@Override
public boolean apply(Game game, Ability source) {
return SpiderMan2099Watcher.checkPlayer(game, source);
}
@Override
public String toString() {
return "you've played a land or cast a spell this turn from anywhere other than your hand";
}
}
class SpiderMan2099Watcher extends Watcher {
private final Set<UUID> set = new HashSet<>();
SpiderMan2099Watcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
switch (event.getType()) {
case LAND_PLAYED:
if (!Zone.HAND.match(event.getZone())) {
set.add(event.getPlayerId());
}
break;
case SPELL_CAST:
Spell spell = game.getSpell(event.getTargetId());
if (spell != null && !Zone.HAND.match(spell.getFromZone())) {
set.add(spell.getControllerId());
}
}
}
@Override
public void reset() {
super.reset();
set.clear();
}
static boolean checkPlayer(Game game, Ability source) {
return game
.getState()
.getWatcher(SpiderMan2099Watcher.class)
.set
.contains(source.getControllerId());
}
}

View file

@ -12,8 +12,6 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -24,13 +22,6 @@ import java.util.UUID;
*/ */
public final class StoicFarmer extends CardImpl { public final class StoicFarmer extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Plains card");
static {
filter.add(SuperType.BASIC.getPredicate());
filter.add(SubType.PLAINS.getPredicate());
}
private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS); private static final Condition condition = new OpponentControlsMoreCondition(StaticFilters.FILTER_LANDS);
public StoicFarmer(UUID ownerId, CardSetInfo setInfo) { public StoicFarmer(UUID ownerId, CardSetInfo setInfo) {
@ -44,8 +35,8 @@ public final class StoicFarmer extends CardImpl {
// When Stoic Farmer enters the battlefield, search your library for a basic Plains card and reveal it. If an opponent controls more lands than you, put it onto the battlefield tapped. Otherwise, put it into your hand. Then shuffle your library. // When Stoic Farmer enters the battlefield, search your library for a basic Plains card and reveal it. If an opponent controls more lands than you, put it onto the battlefield tapped. Otherwise, put it into your hand. Then shuffle your library.
this.addAbility(new EntersBattlefieldTriggeredAbility( this.addAbility(new EntersBattlefieldTriggeredAbility(
new ConditionalOneShotEffect( new ConditionalOneShotEffect(
new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(filter), true), new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true),
new SearchLibraryPutInHandEffect(new TargetCardInLibrary(filter), true), new SearchLibraryPutInHandEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true),
condition, "search your library for a basic Plains card and reveal it. " + condition, "search your library for a basic Plains card and reveal it. " +
"If an opponent controls more lands than you, put it onto the battlefield tapped. " + "If an opponent controls more lands than you, put it onto the battlefield tapped. " +
"Otherwise put it into your hand. Then shuffle" "Otherwise put it into your hand. Then shuffle"

View file

@ -10,8 +10,8 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -21,12 +21,7 @@ import java.util.UUID;
*/ */
public final class SunbladeSamurai extends CardImpl { public final class SunbladeSamurai extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Plains card"); private static final FilterCard filter = new FilterBasicCard(SubType.PLAINS);
static {
filter.add(SubType.PLAINS.getPredicate());
filter.add(SuperType.BASIC.getPredicate());
}
public SunbladeSamurai(UUID ownerId, CardSetInfo setInfo) { public SunbladeSamurai(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{4}{W}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{4}{W}");

View file

@ -15,7 +15,7 @@ import mage.constants.CardType;
import mage.constants.Outcome; import mage.constants.Outcome;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.Zone; import mage.constants.Zone;
import mage.filter.common.FilterBySubtypeCard; import mage.filter.FilterCard;
import mage.game.Game; import mage.game.Game;
import mage.game.permanent.Permanent; import mage.game.permanent.Permanent;
import mage.players.Player; import mage.players.Player;
@ -54,7 +54,7 @@ public final class TempleOfTheDragonQueen extends CardImpl {
class TempleOfTheDragonQueenEffect extends OneShotEffect { class TempleOfTheDragonQueenEffect extends OneShotEffect {
private static final FilterBySubtypeCard filter = new FilterBySubtypeCard(SubType.DRAGON); private static final FilterCard filter = new FilterCard(SubType.DRAGON);
public TempleOfTheDragonQueenEffect() { public TempleOfTheDragonQueenEffect() {
super(Outcome.Tap); super(Outcome.Tap);

View file

@ -9,8 +9,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SagaChapter; import mage.constants.SagaChapter;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.filter.StaticFilters;
import mage.filter.FilterCard;
import mage.game.permanent.token.ArtifactWallToken; import mage.game.permanent.token.ArtifactWallToken;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -21,13 +20,6 @@ import java.util.UUID;
*/ */
public final class TheBirthOfMeletis extends CardImpl { public final class TheBirthOfMeletis extends CardImpl {
private static final FilterCard filter = new FilterCard("a basic Plains card");
static {
filter.add(SubType.PLAINS.getPredicate());
filter.add(SuperType.BASIC.getPredicate());
}
public TheBirthOfMeletis(UUID ownerId, CardSetInfo setInfo) { public TheBirthOfMeletis(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}"); super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{W}");
@ -39,7 +31,7 @@ public final class TheBirthOfMeletis extends CardImpl {
// I Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library. // I Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle your library.
sagaAbility.addChapterEffect( sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_I, new SearchLibraryPutInHandEffect( this, SagaChapter.CHAPTER_I, new SearchLibraryPutInHandEffect(
new TargetCardInLibrary(filter), true new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true
) )
); );

View file

@ -10,8 +10,12 @@ import mage.abilities.effects.common.search.SearchLibraryPutInHandEffect;
import mage.abilities.keyword.TransformAbility; import mage.abilities.keyword.TransformAbility;
import mage.cards.CardImpl; import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.*; import mage.constants.CardType;
import mage.constants.ComparisonType;
import mage.constants.SagaChapter;
import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.StaticFilters;
import mage.filter.common.FilterPermanentCard; import mage.filter.common.FilterPermanentCard;
import mage.filter.predicate.mageobject.ManaValuePredicate; import mage.filter.predicate.mageobject.ManaValuePredicate;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -24,14 +28,10 @@ import java.util.UUID;
*/ */
public final class TheRestorationOfEiganjo extends CardImpl { public final class TheRestorationOfEiganjo extends CardImpl {
private static final FilterCard filter
= new FilterCard("a basic Plains card");
private static final FilterCard filter2 private static final FilterCard filter2
= new FilterPermanentCard("permanent card with mana value 2 or less from your graveyard"); = new FilterPermanentCard("permanent card with mana value 2 or less from your graveyard");
static { static {
filter.add(SubType.PLAINS.getPredicate());
filter.add(SuperType.BASIC.getPredicate());
filter2.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3)); filter2.add(new ManaValuePredicate(ComparisonType.FEWER_THAN, 3));
} }
@ -47,7 +47,7 @@ public final class TheRestorationOfEiganjo extends CardImpl {
// I - Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle. // I - Search your library for a basic Plains card, reveal it, put it into your hand, then shuffle.
sagaAbility.addChapterEffect( sagaAbility.addChapterEffect(
this, SagaChapter.CHAPTER_I, new SearchLibraryPutInHandEffect( this, SagaChapter.CHAPTER_I, new SearchLibraryPutInHandEffect(
new TargetCardInLibrary(filter), true new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_PLAINS), true
) )
); );

View file

@ -12,7 +12,6 @@ import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.constants.SuperType; import mage.constants.SuperType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBySubtypeCard;
import mage.target.common.TargetCardInYourGraveyard; import mage.target.common.TargetCardInYourGraveyard;
import java.util.UUID; import java.util.UUID;
@ -22,8 +21,8 @@ import java.util.UUID;
*/ */
public final class TombstoneCareerCriminal extends CardImpl { public final class TombstoneCareerCriminal extends CardImpl {
private static final FilterCard filter = new FilterBySubtypeCard(SubType.VILLAIN); private static final FilterCard filter = new FilterCard(SubType.VILLAIN);
private static final FilterCard filter2 = new FilterBySubtypeCard(SubType.VILLAIN, "Villain spells"); private static final FilterCard filter2 = new FilterCard(SubType.VILLAIN, "Villain spells");
public TombstoneCareerCriminal(UUID ownerId, CardSetInfo setInfo) { public TombstoneCareerCriminal(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}"); super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{B}");

View file

@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -25,7 +25,7 @@ import java.util.UUID;
*/ */
public final class TranquilLandscape extends CardImpl { public final class TranquilLandscape extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("a basic Forest, Plains, or Island card"); private static final FilterCard filter = new FilterBasicCard("a basic Forest, Plains, or Island card");
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(

View file

@ -14,7 +14,7 @@ import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.constants.SubType; import mage.constants.SubType;
import mage.filter.FilterCard; import mage.filter.FilterCard;
import mage.filter.common.FilterBasicLandCard; import mage.filter.common.FilterBasicCard;
import mage.filter.predicate.Predicates; import mage.filter.predicate.Predicates;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
@ -25,7 +25,7 @@ import java.util.UUID;
*/ */
public final class TwistedLandscape extends CardImpl { public final class TwistedLandscape extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("a basic Swamp, Mountain, or Forest card"); private static final FilterCard filter = new FilterBasicCard("a basic Swamp, Mountain, or Forest card");
static { static {
filter.add(Predicates.or( filter.add(Predicates.or(

View file

@ -9,9 +9,7 @@ import mage.cards.CardImpl;
import mage.cards.CardSetInfo; import mage.cards.CardSetInfo;
import mage.constants.CardType; import mage.constants.CardType;
import mage.counters.CounterType; import mage.counters.CounterType;
import mage.filter.FilterCard;
import mage.filter.StaticFilters; import mage.filter.StaticFilters;
import mage.filter.common.FilterBasicLandCard;
import mage.target.common.TargetCardInLibrary; import mage.target.common.TargetCardInLibrary;
import java.util.UUID; import java.util.UUID;
@ -21,8 +19,6 @@ import java.util.UUID;
*/ */
public final class VastwoodSurge extends CardImpl { public final class VastwoodSurge extends CardImpl {
private static final FilterCard filter = new FilterBasicLandCard("basic land cards");
public VastwoodSurge(UUID ownerId, CardSetInfo setInfo) { public VastwoodSurge(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}"); super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{3}{G}");
@ -31,7 +27,7 @@ public final class VastwoodSurge extends CardImpl {
// Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle your library. If this spell was kicked, put two +1/+1 counters on each creature you control. // Search your library for up to two basic land cards, put them onto the battlefield tapped, then shuffle your library. If this spell was kicked, put two +1/+1 counters on each creature you control.
this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect( this.getSpellAbility().addEffect(new SearchLibraryPutInPlayEffect(
new TargetCardInLibrary(0, 2, filter), true new TargetCardInLibrary(0, 2, StaticFilters.FILTER_CARD_BASIC_LANDS), true
)); ));
this.getSpellAbility().addEffect(new ConditionalOneShotEffect( this.getSpellAbility().addEffect(new ConditionalOneShotEffect(
new AddCountersAllEffect( new AddCountersAllEffect(

View file

@ -24,7 +24,7 @@ public final class VenomBlast extends CardImpl {
this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2))); this.getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)));
this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect() this.getSpellAbility().addEffect(new DamageWithPowerFromOneToAnotherTargetEffect()
.setText("It deals damage equal to its power to up to one other target creature")); .setText("It deals damage equal to its power to up to one other target creature"));
this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent()); this.getSpellAbility().addTarget(new TargetControlledCreaturePermanent().setTargetTag(1));
this.getSpellAbility().addTarget(new TargetPermanent( this.getSpellAbility().addTarget(new TargetPermanent(
0, 1, StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2 0, 1, StaticFilters.FILTER_ANOTHER_CREATURE_TARGET_2
).setTargetTag(2)); ).setTargetTag(2));

View file

@ -0,0 +1,42 @@
package mage.cards.w;
import mage.MageInt;
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
import mage.abilities.effects.common.counter.AddCountersAllEffect;
import mage.cards.CardImpl;
import mage.cards.CardSetInfo;
import mage.constants.CardType;
import mage.constants.SubType;
import mage.counters.CounterType;
import mage.filter.StaticFilters;
import java.util.UUID;
/**
* @author TheElk801
*/
public final class WebWarriors extends CardImpl {
public WebWarriors(UUID ownerId, CardSetInfo setInfo) {
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{4}{G/W}");
this.subtype.add(SubType.SPIDER);
this.subtype.add(SubType.HERO);
this.power = new MageInt(4);
this.toughness = new MageInt(3);
// When this creature enters, put a +1/+1 counter on each other creature you control.
this.addAbility(new EntersBattlefieldTriggeredAbility(new AddCountersAllEffect(
CounterType.P1P1.createInstance(), StaticFilters.FILTER_OTHER_CONTROLLED_CREATURE
)));
}
private WebWarriors(final WebWarriors card) {
super(card);
}
@Override
public WebWarriors copy() {
return new WebWarriors(this);
}
}

View file

@ -4,15 +4,11 @@ import mage.cards.ExpansionSet;
import mage.constants.Rarity; import mage.constants.Rarity;
import mage.constants.SetType; import mage.constants.SetType;
import java.util.Arrays;
import java.util.List;
/** /**
* @author TheElk801 * @author TheElk801
*/ */
public final class MarvelsSpiderMan extends ExpansionSet { public final class MarvelsSpiderMan extends ExpansionSet {
private static final List<String> unfinished = Arrays.asList("Electro's Bolt", "Spider-Islanders");
private static final MarvelsSpiderMan instance = new MarvelsSpiderMan(); private static final MarvelsSpiderMan instance = new MarvelsSpiderMan();
public static MarvelsSpiderMan getInstance() { public static MarvelsSpiderMan getInstance() {
@ -25,17 +21,26 @@ public final class MarvelsSpiderMan extends ExpansionSet {
this.hasBasicLands = true; this.hasBasicLands = true;
cards.add(new SetCardInfo("Angry Rabble", 75, Rarity.COMMON, mage.cards.a.AngryRabble.class)); cards.add(new SetCardInfo("Angry Rabble", 75, Rarity.COMMON, mage.cards.a.AngryRabble.class));
cards.add(new SetCardInfo("Anti-Venom, Horrifying Healer", 1, Rarity.MYTHIC, mage.cards.a.AntiVenomHorrifyingHealer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Anti-Venom, Horrifying Healer", 244, Rarity.MYTHIC, mage.cards.a.AntiVenomHorrifyingHealer.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Aunt May", 3, Rarity.UNCOMMON, mage.cards.a.AuntMay.class)); cards.add(new SetCardInfo("Aunt May", 3, Rarity.UNCOMMON, mage.cards.a.AuntMay.class));
cards.add(new SetCardInfo("Beetle, Legacy Criminal", 26, Rarity.COMMON, mage.cards.b.BeetleLegacyCriminal.class)); cards.add(new SetCardInfo("Beetle, Legacy Criminal", 26, Rarity.COMMON, mage.cards.b.BeetleLegacyCriminal.class));
cards.add(new SetCardInfo("Daily Bugle Reporters", 6, Rarity.COMMON, mage.cards.d.DailyBugleReporters.class)); cards.add(new SetCardInfo("Daily Bugle Reporters", 6, Rarity.COMMON, mage.cards.d.DailyBugleReporters.class));
cards.add(new SetCardInfo("Doc Ock's Henchmen", 30, Rarity.COMMON, mage.cards.d.DocOcksHenchmen.class)); cards.add(new SetCardInfo("Doc Ock's Henchmen", 30, Rarity.COMMON, mage.cards.d.DocOcksHenchmen.class));
cards.add(new SetCardInfo("Doc Ock, Sinister Scientist", 29, Rarity.COMMON, mage.cards.d.DocOckSinisterScientist.class)); cards.add(new SetCardInfo("Doc Ock, Sinister Scientist", 29, Rarity.COMMON, mage.cards.d.DocOckSinisterScientist.class));
cards.add(new SetCardInfo("Doctor Octopus, Master Planner", 128, Rarity.MYTHIC, mage.cards.d.DoctorOctopusMasterPlanner.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Doctor Octopus, Master Planner", 228, Rarity.MYTHIC, mage.cards.d.DoctorOctopusMasterPlanner.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Eerie Gravestone", 163, Rarity.COMMON, mage.cards.e.EerieGravestone.class)); cards.add(new SetCardInfo("Eerie Gravestone", 163, Rarity.COMMON, mage.cards.e.EerieGravestone.class));
cards.add(new SetCardInfo("Electro's Bolt", 77, Rarity.COMMON, mage.cards.e.ElectrosBolt.class)); cards.add(new SetCardInfo("Electro's Bolt", 77, Rarity.COMMON, mage.cards.e.ElectrosBolt.class));
cards.add(new SetCardInfo("Flying Octobot", 31, Rarity.UNCOMMON, mage.cards.f.FlyingOctobot.class)); cards.add(new SetCardInfo("Flying Octobot", 31, Rarity.UNCOMMON, mage.cards.f.FlyingOctobot.class));
cards.add(new SetCardInfo("Forest", 193, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Forest", 198, Rarity.LAND, mage.cards.basiclands.Forest.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Green Goblin, Revenant", 130, Rarity.UNCOMMON, mage.cards.g.GreenGoblinRevenant.class));
cards.add(new SetCardInfo("Grow Extra Arms", 101, Rarity.COMMON, mage.cards.g.GrowExtraArms.class)); cards.add(new SetCardInfo("Grow Extra Arms", 101, Rarity.COMMON, mage.cards.g.GrowExtraArms.class));
cards.add(new SetCardInfo("Guy in the Chair", 102, Rarity.COMMON, mage.cards.g.GuyInTheChair.class)); cards.add(new SetCardInfo("Guy in the Chair", 102, Rarity.COMMON, mage.cards.g.GuyInTheChair.class));
cards.add(new SetCardInfo("Iron Spider, Stark Upgrade", 166, Rarity.RARE, mage.cards.i.IronSpiderStarkUpgrade.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Iron Spider, Stark Upgrade", 279, Rarity.RARE, mage.cards.i.IronSpiderStarkUpgrade.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", 190, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Island", 195, Rarity.LAND, mage.cards.basiclands.Island.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Kapow!", 103, Rarity.COMMON, mage.cards.k.Kapow.class)); cards.add(new SetCardInfo("Kapow!", 103, Rarity.COMMON, mage.cards.k.Kapow.class));
cards.add(new SetCardInfo("Kraven's Cats", 104, Rarity.COMMON, mage.cards.k.KravensCats.class)); cards.add(new SetCardInfo("Kraven's Cats", 104, Rarity.COMMON, mage.cards.k.KravensCats.class));
@ -43,9 +48,12 @@ public final class MarvelsSpiderMan extends ExpansionSet {
cards.add(new SetCardInfo("Masked Meower", 82, Rarity.COMMON, mage.cards.m.MaskedMeower.class)); cards.add(new SetCardInfo("Masked Meower", 82, Rarity.COMMON, mage.cards.m.MaskedMeower.class));
cards.add(new SetCardInfo("Mechanical Mobster", 168, Rarity.COMMON, mage.cards.m.MechanicalMobster.class)); cards.add(new SetCardInfo("Mechanical Mobster", 168, Rarity.COMMON, mage.cards.m.MechanicalMobster.class));
cards.add(new SetCardInfo("Merciless Enforcers", 58, Rarity.COMMON, mage.cards.m.MercilessEnforcers.class)); cards.add(new SetCardInfo("Merciless Enforcers", 58, Rarity.COMMON, mage.cards.m.MercilessEnforcers.class));
cards.add(new SetCardInfo("Mountain", 192, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mountain", 197, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mountain", 197, Rarity.LAND, mage.cards.basiclands.Mountain.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Origin of Spider-Man", 9, Rarity.RARE, mage.cards.o.OriginOfSpiderMan.class)); cards.add(new SetCardInfo("Origin of Spider-Man", 218, Rarity.RARE, mage.cards.o.OriginOfSpiderMan.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Origin of Spider-Man", 9, Rarity.RARE, mage.cards.o.OriginOfSpiderMan.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Oscorp Research Team", 40, Rarity.COMMON, mage.cards.o.OscorpResearchTeam.class)); cards.add(new SetCardInfo("Oscorp Research Team", 40, Rarity.COMMON, mage.cards.o.OscorpResearchTeam.class));
cards.add(new SetCardInfo("Plains", 189, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Plains", 194, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Risky Research", 62, Rarity.COMMON, mage.cards.r.RiskyResearch.class)); cards.add(new SetCardInfo("Risky Research", 62, Rarity.COMMON, mage.cards.r.RiskyResearch.class));
cards.add(new SetCardInfo("Romantic Rendezvous", 86, Rarity.COMMON, mage.cards.r.RomanticRendezvous.class)); cards.add(new SetCardInfo("Romantic Rendezvous", 86, Rarity.COMMON, mage.cards.r.RomanticRendezvous.class));
@ -55,18 +63,25 @@ public final class MarvelsSpiderMan extends ExpansionSet {
cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class)); cards.add(new SetCardInfo("Selfless Police Captain", 12, Rarity.COMMON, mage.cards.s.SelflessPoliceCaptain.class));
cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class)); cards.add(new SetCardInfo("Shock", 88, Rarity.COMMON, mage.cards.s.Shock.class));
cards.add(new SetCardInfo("Shocker, Unshakable", 89, Rarity.UNCOMMON, mage.cards.s.ShockerUnshakable.class)); cards.add(new SetCardInfo("Shocker, Unshakable", 89, Rarity.UNCOMMON, mage.cards.s.ShockerUnshakable.class));
cards.add(new SetCardInfo("Spectacular Spider-Man", 14, Rarity.RARE, mage.cards.s.SpectacularSpiderMan.class));
cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class)); cards.add(new SetCardInfo("Spectacular Tactics", 15, Rarity.COMMON, mage.cards.s.SpectacularTactics.class));
cards.add(new SetCardInfo("Spider-Bot", 173, Rarity.COMMON, mage.cards.s.SpiderBot.class)); cards.add(new SetCardInfo("Spider-Bot", 173, Rarity.COMMON, mage.cards.s.SpiderBot.class));
cards.add(new SetCardInfo("Spider-Byte, Web Warden", 44, Rarity.UNCOMMON, mage.cards.s.SpiderByteWebWarden.class)); cards.add(new SetCardInfo("Spider-Byte, Web Warden", 44, Rarity.UNCOMMON, mage.cards.s.SpiderByteWebWarden.class));
cards.add(new SetCardInfo("Spider-Gwen, Free Spirit", 90, Rarity.COMMON, mage.cards.s.SpiderGwenFreeSpirit.class)); cards.add(new SetCardInfo("Spider-Gwen, Free Spirit", 90, Rarity.COMMON, mage.cards.s.SpiderGwenFreeSpirit.class));
cards.add(new SetCardInfo("Spider-Ham, Peter Porker", 114, Rarity.RARE, mage.cards.s.SpiderHamPeterPorker.class)); cards.add(new SetCardInfo("Spider-Ham, Peter Porker", 114, Rarity.RARE, mage.cards.s.SpiderHamPeterPorker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider-Ham, Peter Porker", 201, Rarity.RARE, mage.cards.s.SpiderHamPeterPorker.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider-Islanders", 91, Rarity.COMMON, mage.cards.s.SpiderIslanders.class)); cards.add(new SetCardInfo("Spider-Islanders", 91, Rarity.COMMON, mage.cards.s.SpiderIslanders.class));
cards.add(new SetCardInfo("Spider-Man Noir", 67, Rarity.UNCOMMON, mage.cards.s.SpiderManNoir.class)); cards.add(new SetCardInfo("Spider-Man 2099", 150, Rarity.RARE, mage.cards.s.SpiderMan2099.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider-Man 2099", 205, Rarity.RARE, mage.cards.s.SpiderMan2099.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider-Man 2099", 216, Rarity.RARE, mage.cards.s.SpiderMan2099.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider-Man Noir", 204, Rarity.UNCOMMON, mage.cards.s.SpiderManNoir.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider-Man Noir", 67, Rarity.UNCOMMON, mage.cards.s.SpiderManNoir.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Spider-Man, Brooklyn Visionary", 115, Rarity.COMMON, mage.cards.s.SpiderManBrooklynVisionary.class)); cards.add(new SetCardInfo("Spider-Man, Brooklyn Visionary", 115, Rarity.COMMON, mage.cards.s.SpiderManBrooklynVisionary.class));
cards.add(new SetCardInfo("Spider-Man, Web-Slinger", 16, Rarity.COMMON, mage.cards.s.SpiderManWebSlinger.class)); cards.add(new SetCardInfo("Spider-Man, Web-Slinger", 16, Rarity.COMMON, mage.cards.s.SpiderManWebSlinger.class));
cards.add(new SetCardInfo("Spider-Rex, Daring Dino", 116, Rarity.COMMON, mage.cards.s.SpiderRexDaringDino.class)); cards.add(new SetCardInfo("Spider-Rex, Daring Dino", 116, Rarity.COMMON, mage.cards.s.SpiderRexDaringDino.class));
cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class)); cards.add(new SetCardInfo("Starling, Aerial Ally", 18, Rarity.COMMON, mage.cards.s.StarlingAerialAlly.class));
cards.add(new SetCardInfo("Stegron the Dinosaur Man", 95, Rarity.COMMON, mage.cards.s.StegronTheDinosaurMan.class)); cards.add(new SetCardInfo("Stegron the Dinosaur Man", 95, Rarity.COMMON, mage.cards.s.StegronTheDinosaurMan.class));
cards.add(new SetCardInfo("Swamp", 191, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Swamp", 196, Rarity.LAND, mage.cards.basiclands.Swamp.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Taxi Driver", 97, Rarity.COMMON, mage.cards.t.TaxiDriver.class)); cards.add(new SetCardInfo("Taxi Driver", 97, Rarity.COMMON, mage.cards.t.TaxiDriver.class));
cards.add(new SetCardInfo("Thwip!", 20, Rarity.COMMON, mage.cards.t.Thwip.class)); cards.add(new SetCardInfo("Thwip!", 20, Rarity.COMMON, mage.cards.t.Thwip.class));
@ -75,9 +90,9 @@ public final class MarvelsSpiderMan extends ExpansionSet {
cards.add(new SetCardInfo("Venom's Hunger", 73, Rarity.COMMON, mage.cards.v.VenomsHunger.class)); cards.add(new SetCardInfo("Venom's Hunger", 73, Rarity.COMMON, mage.cards.v.VenomsHunger.class));
cards.add(new SetCardInfo("Venom, Evil Unleashed", 71, Rarity.COMMON, mage.cards.v.VenomEvilUnleashed.class)); cards.add(new SetCardInfo("Venom, Evil Unleashed", 71, Rarity.COMMON, mage.cards.v.VenomEvilUnleashed.class));
cards.add(new SetCardInfo("Web Up", 21, Rarity.COMMON, mage.cards.w.WebUp.class)); cards.add(new SetCardInfo("Web Up", 21, Rarity.COMMON, mage.cards.w.WebUp.class));
cards.add(new SetCardInfo("Web-Warriors", 159, Rarity.UNCOMMON, mage.cards.w.WebWarriors.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Web-Warriors", 203, Rarity.UNCOMMON, mage.cards.w.WebWarriors.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Whoosh!", 48, Rarity.COMMON, mage.cards.w.Whoosh.class)); cards.add(new SetCardInfo("Whoosh!", 48, Rarity.COMMON, mage.cards.w.Whoosh.class));
cards.add(new SetCardInfo("Wild Pack Squad", 23, Rarity.COMMON, mage.cards.w.WildPackSquad.class)); cards.add(new SetCardInfo("Wild Pack Squad", 23, Rarity.COMMON, mage.cards.w.WildPackSquad.class));
cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName()));
} }
} }

View file

@ -83,7 +83,7 @@ public final class SpecialGuests extends ExpansionSet {
cards.add(new SetCardInfo("Lord of the Undead", 88, Rarity.MYTHIC, mage.cards.l.LordOfTheUndead.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lord of the Undead", 88, Rarity.MYTHIC, mage.cards.l.LordOfTheUndead.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Lord of the Undead", 98, Rarity.MYTHIC, mage.cards.l.LordOfTheUndead.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Lord of the Undead", 98, Rarity.MYTHIC, mage.cards.l.LordOfTheUndead.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Maddening Hex", 70, Rarity.MYTHIC, mage.cards.m.MaddeningHex.class)); cards.add(new SetCardInfo("Maddening Hex", 70, Rarity.MYTHIC, mage.cards.m.MaddeningHex.class));
cards.add(new SetCardInfo("Magus of the Moon", 125, Rarity.RARE, mage.cards.m.MagusOfTheMoon.class, FULL_ART)); cards.add(new SetCardInfo("Magus of the Moon", 125, Rarity.MYTHIC, mage.cards.m.MagusOfTheMoon.class, FULL_ART));
cards.add(new SetCardInfo("Malcolm, Keen-Eyed Navigator", 2, Rarity.UNCOMMON, mage.cards.m.MalcolmKeenEyedNavigator.class)); cards.add(new SetCardInfo("Malcolm, Keen-Eyed Navigator", 2, Rarity.UNCOMMON, mage.cards.m.MalcolmKeenEyedNavigator.class));
cards.add(new SetCardInfo("Mana Crypt", "17a", Rarity.MYTHIC, mage.cards.m.ManaCrypt.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mana Crypt", "17a", Rarity.MYTHIC, mage.cards.m.ManaCrypt.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Mana Crypt", "17b", Rarity.MYTHIC, mage.cards.m.ManaCrypt.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Mana Crypt", "17b", Rarity.MYTHIC, mage.cards.m.ManaCrypt.class, NON_FULL_USE_VARIOUS));
@ -127,7 +127,7 @@ public final class SpecialGuests extends ExpansionSet {
cards.add(new SetCardInfo("Show and Tell", 21, Rarity.MYTHIC, mage.cards.s.ShowAndTell.class)); cards.add(new SetCardInfo("Show and Tell", 21, Rarity.MYTHIC, mage.cards.s.ShowAndTell.class));
cards.add(new SetCardInfo("Skysovereign, Consul Flagship", 103, Rarity.MYTHIC, mage.cards.s.SkysovereignConsulFlagship.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Skysovereign, Consul Flagship", 103, Rarity.MYTHIC, mage.cards.s.SkysovereignConsulFlagship.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Skysovereign, Consul Flagship", 93, Rarity.MYTHIC, mage.cards.s.SkysovereignConsulFlagship.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Skysovereign, Consul Flagship", 93, Rarity.MYTHIC, mage.cards.s.SkysovereignConsulFlagship.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Sliver Overlord", 128, Rarity.RARE, mage.cards.s.SliverOverlord.class, FULL_ART)); cards.add(new SetCardInfo("Sliver Overlord", 128, Rarity.MYTHIC, mage.cards.s.SliverOverlord.class, FULL_ART));
cards.add(new SetCardInfo("Solitude", 44, Rarity.MYTHIC, mage.cards.s.Solitude.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Solitude", 44, Rarity.MYTHIC, mage.cards.s.Solitude.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Solitude", 49, Rarity.MYTHIC, mage.cards.s.Solitude.class, NON_FULL_USE_VARIOUS)); cards.add(new SetCardInfo("Solitude", 49, Rarity.MYTHIC, mage.cards.s.Solitude.class, NON_FULL_USE_VARIOUS));
cards.add(new SetCardInfo("Soul Warden", 65, Rarity.MYTHIC, mage.cards.s.SoulWarden.class)); cards.add(new SetCardInfo("Soul Warden", 65, Rarity.MYTHIC, mage.cards.s.SoulWarden.class));

View file

@ -2,6 +2,7 @@ package org.mage.test.cards.abilities.keywords;
import mage.constants.PhaseStep; import mage.constants.PhaseStep;
import mage.constants.Zone; import mage.constants.Zone;
import mage.counters.CounterType;
import org.junit.Test; import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase; import org.mage.test.serverside.base.CardTestPlayerBase;
@ -81,4 +82,243 @@ public class ForetellTest extends CardTestPlayerBase {
assertExileCount(playerA, "Lightning Bolt", 1); // foretold card in exile assertExileCount(playerA, "Lightning Bolt", 1); // foretold card in exile
assertPowerToughness(playerA, "Dream Devourer", 2, 3); // +2 power boost from trigger due to foretell of Lightning Bolt assertPowerToughness(playerA, "Dream Devourer", 2, 3); // +2 power boost from trigger due to foretell of Lightning Bolt
} }
// Tests needed to check watcher scope issue (see issue #7493 and issue #13774)
private static final String scornEffigy = "Scorn Effigy"; // {3} 2/3 foretell {0}
private static final String poisonCup = "Poison the Cup"; // {1}{B}{B} instant destroy target creature
// Foretell {1}{B}, if spell was foretold, scry 2
private static final String flamespeaker = "Flamespeaker Adept"; // {2}{R} 2/3
// Whenever you scry, gets +2/+0 and first strike until end of turn
private static final String chancemetElves = "Chance-Met Elves"; // {2}{G} 3/2
// Whenever you scry, gets a +1/+1 counter, triggers once per turn
private static final String cardE = "Elite Vanguard";
private static final String cardD = "Devilthorn Fox";
private static final String cardC = "Canopy Gorger";
private static final String cardB = "Barbtooth Wurm";
private static final String cardA = "Alaborn Trooper";
private void setupLibrariesEtc() {
// make a library of 5 cards, bottom : E D C B A : top
skipInitShuffling();
removeAllCardsFromLibrary(playerA);
addCard(Zone.LIBRARY, playerA, cardE);
addCard(Zone.LIBRARY, playerA, cardD);
addCard(Zone.LIBRARY, playerA, cardC);
addCard(Zone.LIBRARY, playerA, cardB);
addCard(Zone.LIBRARY, playerA, cardA);
removeAllCardsFromLibrary(playerB);
addCard(Zone.LIBRARY, playerB, cardE);
addCard(Zone.LIBRARY, playerB, cardD);
addCard(Zone.LIBRARY, playerB, cardC);
addCard(Zone.LIBRARY, playerB, cardB);
addCard(Zone.LIBRARY, playerB, cardA);
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 5);
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 5);
addCard(Zone.BATTLEFIELD, playerA, flamespeaker);
addCard(Zone.BATTLEFIELD, playerB, chancemetElves);
addCard(Zone.HAND, playerA, scornEffigy);
}
@Test
public void testForetellWatcherPlayerA() {
setupLibrariesEtc();
addCard(Zone.HAND, playerA, poisonCup);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, scornEffigy);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell");
checkExileCount("foretold in exile", 2, PhaseStep.PRECOMBAT_MAIN, playerA, poisonCup, 1);
// turn 3, draw card A
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell {1}{B}", chancemetElves);
// foretold, so scry 2 (cards B and C)
addTarget(playerA, cardB); // scrying B bottom (C remains on top)
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertPowerToughness(playerA, scornEffigy, 2, 3);
assertGraveyardCount(playerA, poisonCup, 1);
assertGraveyardCount(playerB, chancemetElves, 1);
assertPowerToughness(playerA, flamespeaker, 4, 3);
}
@Test
public void testForetellWatcherPlayerB() {
setupLibrariesEtc();
addCard(Zone.HAND, playerB, poisonCup);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, scornEffigy);
// turn 2, draw card A
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Foretell");
checkExileCount("foretold in exile", 2, PhaseStep.PRECOMBAT_MAIN, playerB, poisonCup, 1);
// turn 4, draw card B
activateAbility(4, PhaseStep.PRECOMBAT_MAIN, playerB, "Foretell {1}{B}", flamespeaker);
// foretold, so scry 2 (cards C and D)
addTarget(playerB, cardD); // scrying D bottom (C remains on top)
setStrictChooseMode(true);
setStopAt(4, PhaseStep.END_TURN);
execute();
assertPowerToughness(playerA, scornEffigy, 2, 3);
assertGraveyardCount(playerB, poisonCup, 1);
assertGraveyardCount(playerA, flamespeaker, 1);
assertPowerToughness(playerB, chancemetElves, 4, 3);
}
@Test
public void testRanar() {
skipInitShuffling();
String ranar = "Ranar the Ever-Watchful"; // 2WU 2/3 Flying Vigilance
// The first card you foretell each turn costs {0} to foretell.
// Whenever one or more cards are put into exile from your hand or a spell or ability you control exiles
// one or more permanents from the battlefield, create a 1/1 white Spirit creature token with flying.
addCard(Zone.BATTLEFIELD, playerA, ranar);
addCard(Zone.BATTLEFIELD, playerA, "Sage of the Falls"); // may loot on creature ETB
addCard(Zone.HAND, playerA, poisonCup);
addCard(Zone.LIBRARY, playerA, scornEffigy);
addCard(Zone.HAND, playerA, "Wastes");
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell"); // poison the cup
setChoice(playerA, true); // yes to loot
setChoice(playerA, "Wastes"); // discard
checkExileCount("Poison the Cup foretold", 1, PhaseStep.BEGIN_COMBAT, playerA, poisonCup, 1);
checkHandCardCount("scorn effigy drawn", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, scornEffigy, 1);
checkPlayableAbility("can't foretell another for free", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Foretell", false);
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell"); // scorn effigy
setChoice(playerA, false); // no loot
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, "Spirit Token", 2);
assertExileCount(playerA, 2);
assertGraveyardCount(playerA, "Wastes", 1);
}
@Test
public void testCosmosCharger() {
addCard(Zone.BATTLEFIELD, playerA, "Cosmos Charger");
// Foretelling cards from your hand costs {1} less and can be done on any players turn.
addCard(Zone.HAND, playerA, scornEffigy);
addCard(Zone.BATTLEFIELD, playerA, "Wastes");
activateAbility(2, PhaseStep.UPKEEP, playerA, "Foretell");
setStrictChooseMode(true);
setStopAt(2, PhaseStep.END_TURN);
execute();
assertExileCount(playerA, scornEffigy, 1);
}
@Test
public void testAlrund() {
String alrund = "Alrund, God of the Cosmos";
// Alrund gets +1/+1 for each card in your hand and each foretold card you own in exile.
addCard(Zone.BATTLEFIELD, playerA, alrund); // 1/1
addCard(Zone.HAND, playerA, scornEffigy);
addCard(Zone.HAND, playerA, "Lightning Bolt");
addCard(Zone.BATTLEFIELD, playerA, "Cadaverous Bloom");
// Exile a card from your hand: Add {B}{B} or {G}{G}.
activateAbility(1, PhaseStep.BEGIN_COMBAT, playerA, "Exile a card from your hand: Add {B}{B}");
setChoice(playerA, "Lightning Bolt");
activateAbility(1, PhaseStep.BEGIN_COMBAT, playerA, "Foretell");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
execute();
assertHandCount(playerA, 0);
assertExileCount(playerA, scornEffigy, 1);
assertPowerToughness(playerA, alrund, 2, 2);
}
private static final String valkyrie = "Ethereal Valkyrie"; // 4/4 flying
// Whenever this creature enters or attacks, draw a card, then exile a card from your hand face down.
// It becomes foretold. Its foretell cost is its mana cost reduced by {2}.
@Test
public void testEtherealValkyrie() {
skipInitShuffling();
removeAllCardsFromLibrary(playerA);
String saga = "Niko Defies Destiny";
// I - You gain 2 life for each foretold card you own in exile.
// II - Add {W}{U}. Spend this mana only to foretell cards or cast spells that have foretell.
String crab = "Fortress Crab"; // 3U 1/6
String puma = "Stonework Puma"; // {3} 2/2
addCard(Zone.BATTLEFIELD, playerA, valkyrie);
addCard(Zone.HAND, playerA, saga);
addCard(Zone.HAND, playerA, crab);
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 5);
addCard(Zone.LIBRARY, playerA, "Wastes");
addCard(Zone.LIBRARY, playerA, puma);
attack(1, playerA, valkyrie, playerB);
addTarget(playerA, crab); // exile becomes foretold
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, saga); // gain 2 life
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
checkExileCount("crab foretold", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, crab, 1);
checkPlayableAbility("can't cast foretold same turn", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Foretell", false);
waitStackResolved(3, PhaseStep.PRECOMBAT_MAIN);
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, puma);
activateAbility(3, PhaseStep.POSTCOMBAT_MAIN, playerA, "Foretell");
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertLife(playerA, 22);
assertLife(playerB, 16);
assertCounterCount(saga, CounterType.LORE, 2);
assertPowerToughness(playerA, crab, 1, 6);
assertPowerToughness(playerA, valkyrie, 4, 4);
assertPowerToughness(playerA, puma, 2, 2);
assertHandCount(playerA, 1);
assertHandCount(playerA, "Wastes", 1);
assertTappedCount("Tundra", true, 5);
}
@Test
public void testForetoldNotForetell() {
skipInitShuffling();
removeAllCardsFromLibrary(playerA);
addCard(Zone.LIBRARY, playerA, "Wastes");
addCard(Zone.LIBRARY, playerA, "Darksteel Citadel");
addCard(Zone.BATTLEFIELD, playerA, valkyrie);
addCard(Zone.BATTLEFIELD, playerA, "Dream Devourer");
addCard(Zone.HAND, playerA, "Papercraft Decoy");
attack(1, playerA, valkyrie, playerB);
addTarget(playerA, "Papercraft Decoy"); // exile becomes foretold
checkPT("Dream Devourer not boosted", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Dream Devourer", 0, 3);
checkPlayableAbility("Can't cast this turn", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Foretell", false);
checkHandCardCount("card drawn", 1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Darksteel Citadel", 1);
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell");
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
execute();
assertLife(playerA, 20);
assertLife(playerB, 16);
assertPowerToughness(playerA, "Papercraft Decoy", 2, 1);
assertPowerToughness(playerA, "Dream Devourer", 0, 3);
assertHandCount(playerA, 2);
}
} }

View file

@ -0,0 +1,89 @@
package org.mage.test.cards.abilities.keywords;
import mage.constants.PhaseStep;
import mage.constants.Zone;
import org.junit.Assert;
import org.junit.Test;
import org.mage.test.serverside.base.CardTestPlayerBase;
/**
* @author TheElk801
*/
public class MayhemTest extends CardTestPlayerBase {
private static final String islanders = "Spider-Islanders";
@Test
public void testCastRegular() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
addCard(Zone.HAND, playerA, islanders);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, islanders);
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, islanders, 1);
}
private static final String imp = "Putrid Imp";
@Test
public void testCastDiscarded() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.BATTLEFIELD, playerA, imp);
addCard(Zone.HAND, playerA, islanders);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Discard");
setChoice(playerA, islanders);
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, islanders + " with Mayhem");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
execute();
assertPermanentCount(playerA, islanders, 1);
}
@Test
public void testCantCastGraveyard() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.GRAVEYARD, playerA, islanders);
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, islanders + " with Mayhem");
setStrictChooseMode(true);
setStopAt(1, PhaseStep.END_TURN);
try {
execute();
} catch (Throwable e) {
Assert.assertEquals(
"Should fail to be able to cast " + islanders + " with mayhem as it wasn't discarded this turn",
"Can't find ability to activate command: Cast " + islanders + " with Mayhem", e.getMessage()
);
}
}
@Test
public void testCantCastDiscardedPreviously() {
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
addCard(Zone.BATTLEFIELD, playerA, imp);
addCard(Zone.HAND, playerA, islanders);
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Discard");
setChoice(playerA, islanders);
castSpell(3, PhaseStep.POSTCOMBAT_MAIN, playerA, islanders + " with Mayhem");
setStrictChooseMode(true);
setStopAt(3, PhaseStep.END_TURN);
try {
execute();
} catch (Throwable e) {
Assert.assertEquals(
"Should fail to be able to cast " + islanders + " with mayhem as it wasn't discarded this turn",
"Can't find ability to activate command: Cast " + islanders + " with Mayhem", e.getMessage()
);
}
}
}

View file

@ -5,10 +5,7 @@ import com.google.gson.Gson;
import mage.MageObject; import mage.MageObject;
import mage.Mana; import mage.Mana;
import mage.ObjectColor; import mage.ObjectColor;
import mage.abilities.Ability; import mage.abilities.*;
import mage.abilities.AbilityImpl;
import mage.abilities.Mode;
import mage.abilities.TriggeredAbility;
import mage.abilities.common.*; import mage.abilities.common.*;
import mage.abilities.condition.Condition; import mage.abilities.condition.Condition;
import mage.abilities.costs.Cost; import mage.abilities.costs.Cost;
@ -2081,7 +2078,6 @@ public class VerifyCardDataTest {
} }
} }
} }
private void checkSubtypes(Card card, MtgJsonCard ref) { private void checkSubtypes(Card card, MtgJsonCard ref) {
if (skipListHaveName(SKIP_LIST_SUBTYPE, card.getExpansionSetCode(), card.getName())) { if (skipListHaveName(SKIP_LIST_SUBTYPE, card.getExpansionSetCode(), card.getName())) {
return; return;
@ -2152,6 +2148,73 @@ public class VerifyCardDataTest {
} }
} }
// There are many cards that use the word "target" or "targets" in reference to spells/abilities that target rather than actually themselves having a target.
// Examples include Wall of Shadows, Psychic Battle, Coalition Honor Guard, Aboleth Spawn, Akroan Crusader, Grip of Chaos, and many more
Pattern singularTargetRegexPattern = Pattern.compile("\\b(?<!(can|the|that|could|each|single|its|new|spell's) )target\\b");
Pattern pluralTargetsRegexPattern = Pattern.compile("\\b(?<!(new|the|that|copy|choosing|it|more|spell|or|changing|legal|has) )targets\\b");
// Note that the check includes reminder text, so any keyword ability with reminder text always included in the card text doesn't need to be added
// FIN added equip abilities with flavor words, allow for those. There are also cards that affect equip costs or equip abilities, exclude those
// Technically Enchant should be in this list, but that's added to the SpellAbility in XMage
Pattern targetKeywordRegexPattern = Pattern.compile("^((.*— )?equip(?! cost| abilit)|bestow|partner with|modular|backup)\\b", Pattern.MULTILINE);
// Checks for targeted reflexive or delayed triggered abilities, ones that only can trigger as a result of another ability
// and thus have their "when" located after a previous statement (detected by a period or comma followed by a space) instead of the start.
// Some reflexive triggers (Cemetery Desecrator, Tranquil Frillback) have a modal decision before the word target, need to check across multiple lines of text for those (and . doesn't match newlines)
// Many delayed triggers only get caught by the recursiveTargetAbilityCheck, if we want to improve that check to be an "and" instead of the current "or", we'll need to add them here
Pattern indirectTriggerTargetRegexPattern = Pattern.compile("([.,] when)(.|—\\n)+target");
// Check if the word "target" is inside a quoted ability being granted or of a token (or is using GiveScavengeContinuousEffect)
// A quoted ability always has a space before the opening quote and never before the closing one, so we can use that to ensure we're only checking inside
Pattern quotedTargetRegexPattern = Pattern.compile(" \"[^\"]*target|has scavenge");
// This check looks inside the abilities' effects to try to find a target that's not part of the main ability
// Examples include reflexive triggers (Ahn-Crop Crasher), delayed triggers (Feral Encounter), ability granting (Acidic Sliver), or tokens with abilities (Dance with Devils)
// Ideally the indirect/quoted text check and this check would always return the same result, but that would require both better regexes for checking and a lot of card changes
boolean recursiveTargetObjectCheck(Object obj, int depth) {
if (depth < 0) {
return false;
}
if (obj instanceof Effect) {
return recursiveTargetEffectCheck((Effect) obj, depth - 1);
}
if (obj instanceof Ability) {
return recursiveTargetAbilityCheck((Ability) obj, depth - 1);
}
if (obj instanceof Token) {
return ((Token) obj).getAbilities().stream().anyMatch(ability -> recursiveTargetAbilityCheck(ability, depth - 1));
}
if (obj instanceof Collection) {
return ((Collection) obj).stream().anyMatch(x -> recursiveTargetObjectCheck(x, depth - 1));
}
return false;
}
boolean recursiveTargetEffectCheck(Effect effect, int depth) {
if (depth < 0) {
return false;
}
return Arrays.stream(effect.getClass().getDeclaredFields())
.anyMatch(f -> {
f.setAccessible(true);
try {
return recursiveTargetObjectCheck(f.get(effect), depth); // Intentionally not decreasing depth here
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex); // Should never happen due to setAccessible
}
});
}
boolean recursiveTargetAbilityCheck(Ability ability, int depth) {
if (depth < 0) {
return false;
}
Collection<Mode> modes = ability.getModes().values();
return modes.stream().flatMap(mode -> mode.getTargets().stream()).anyMatch(target -> !target.isNotTarget())
|| ability.getTargetAdjuster() != null
|| modes.stream().flatMap(mode -> mode.getEffects().stream()).anyMatch(effect -> recursiveTargetEffectCheck(effect, depth - 1));
}
private void checkMissingAbilities(Card card, MtgJsonCard ref) { private void checkMissingAbilities(Card card, MtgJsonCard ref) {
if (skipListHaveName(SKIP_LIST_MISSING_ABILITIES, card.getExpansionSetCode(), card.getName())) { if (skipListHaveName(SKIP_LIST_MISSING_ABILITIES, card.getExpansionSetCode(), card.getName())) {
return; return;
@ -2315,57 +2378,51 @@ public class VerifyCardDataTest {
} }
} }
// special check: wrong targeted ability
// possible fixes:
// * on "must set withNotTarget(true)":
// - check card's ability constructors and fix missing withNotTarget(true) param/field
// - it's can be a keyword action (only mtg rules contains a target word), so add it to the targetedKeywords
// * on "must be targeted":
// - TODO: enable and research checkMissTargeted - too much errors with it (is it possible to use that checks?)
boolean checkMissNonTargeted = true; // must set withNotTarget(true)
boolean checkMissTargeted = false; // must be targeted
List<String> targetedKeywords = Arrays.asList(
"target",
"enchant",
"equip",
"backup",
"modular",
"partner"
);
// xmage card can contain rules text from both sides, so must search ref card for all sides too
String additionalName;
if (card instanceof CardWithSpellOption) {
// adventure/omen cards
additionalName = ((CardWithSpellOption) card).getSpellCard().getName();
} else if (card.isTransformable() && !card.isNightCard()) {
additionalName = card.getSecondCardFace().getName();
} else {
additionalName = null;
}
if (additionalName != null) {
MtgJsonCard additionalRef = MtgJsonService.cardFromSet(card.getExpansionSetCode(), additionalName, card.getCardNumber());
if (additionalRef == null) {
// how-to fix: add new card type processing for an additionalName searching above
fail(card, "abilities", "can't find second side info for target check");
} else {
if (additionalRef.text != null && !additionalRef.text.isEmpty()) {
refLowerText += "\r\n" + additionalRef.text.toLowerCase(Locale.ENGLISH);
}
}
}
boolean needTargetedAbility = targetedKeywords.stream().anyMatch(refLowerText::contains); // special check: wrong targeted ability
boolean foundTargetedAbility = card.getAbilities() // Checks that no ability targets use withNotTarget (use OneShotNonTargetEffect if it's a choose effect)
.stream() // Checks that, if the text contains the word target, the ability does have a target.
.map(Ability::getTargets) // - In cases involving a target in a reflexive trigger or token or other complex situation, it assumes that it's fine
.flatMap(Collection::stream) // - There are two versions of this complexity check, either can trigger: one on card text, one that uses Java reflection to inspect the ability's effects.
.anyMatch(target -> !target.isNotTarget()); String[] excludedCards = {"Lodestone Bauble", // Needs to choose a player before targets are selected
boolean foundProblem = needTargetedAbility != foundTargetedAbility; "Blink", // Current XMage code does not correctly support non-consecutive chapter effects, duplicates effects as a workaround
if (checkMissTargeted && needTargetedAbility && foundProblem) { "Artifact Ward"}; // This card is just implemented wrong, but would need significant work to fix
fail(card, "abilities", "wrong target settings (must be targeted, but it not)"); if (Arrays.stream(excludedCards).noneMatch(x -> x.equals(ref.name))) {
for (Ability ability : card.getAbilities()) {
boolean foundNotTarget = ability.getModes().values().stream()
.flatMap(mode -> mode.getTargets().stream()).anyMatch(Target::isNotTarget);
if (foundNotTarget) {
fail(card, "abilities", "notTarget should not be used as ability target, should be inside ability effect");
}
String abilityText = ability.getRule().toLowerCase(Locale.ENGLISH);
boolean needTargetedAbility = singularTargetRegexPattern.matcher(abilityText).find() || pluralTargetsRegexPattern.matcher(abilityText).find() || targetKeywordRegexPattern.matcher(abilityText).find();
boolean recursiveAbilityText = indirectTriggerTargetRegexPattern.matcher(abilityText).find() || quotedTargetRegexPattern.matcher(abilityText).find();
boolean foundTargetedAbility = recursiveTargetAbilityCheck(ability, 0);
boolean recursiveAbility = recursiveTargetAbilityCheck(ability, 4);
if (needTargetedAbility && !(foundTargetedAbility || recursiveAbilityText || recursiveAbility)
&& card.getAbilities().stream().noneMatch(x -> x instanceof LevelUpAbility)) { // Targeting Level Up abilities' text is put in the power-toughness setting effect
fail(card, "abilities", "wrong target settings (must be targeted, but is not):" + ability.getClass().getSimpleName());
}
if (!needTargetedAbility && foundTargetedAbility
&& !(ability instanceof SpellAbility && abilityText.equals("") && card.getSubtype().contains(SubType.AURA)) // Auras' SpellAbility targets, not the EnchantAbility
&& !(ability instanceof SpellAbility && (recursiveTargetAbilityCheck(card.getSpellAbility(), 0))) // SurgeAbility is a modified copy of the main SpellAbility, so it targets
&& !(ability instanceof SpellTransformedAbility)) { // DisturbAbility targets if the backside aura targets
fail(card, "abilities", "wrong target settings (targeted ability found but no target in text):" + ability.getClass().getSimpleName());
}
}
// Also check that the reference text and the final ability text have the same number of "target"
String preparedRefText = refLowerText.replaceAll("\\([^)]+\\)", ""); // Remove reminder text
int refTargetCount = (preparedRefText.length() - preparedRefText.replace("target", "").length());
String preparedRuleText = cardLowerText.replaceAll("\\([^)]+\\)", "");
if (!ref.subtypes.contains("Adventure") && !ref.subtypes.contains("Omen")) {
preparedRuleText = preparedRuleText.replaceAll("^(adventure|omen).*", "");
}
int cardTargetCount = (preparedRuleText.length() - preparedRuleText.replace("target", "").length());
if (refTargetCount != cardTargetCount) {
fail(card, "abilities", "target count text discrepancy: " + (refTargetCount / 6) + " in reference but " + (cardTargetCount / 6) + " in card.");
} }
if (checkMissNonTargeted && !needTargetedAbility && foundProblem) {
fail(card, "abilities", "wrong target settings (must set withNotTarget(true), but it not)");
} }
// special check: missing or wrong ability/effect rules hint // special check: missing or wrong ability/effect rules hint
@ -3064,6 +3121,11 @@ public class VerifyCardDataTest {
return; return;
} }
// Spacecraft are ignored as they shouldn't have a printed power/toughness but they do in the data
if (ref.subtypes.contains("Spacecraft")) {
return;
}
if (!eqPT(card.getPower().toString(), ref.power) || !eqPT(card.getToughness().toString(), ref.toughness)) { if (!eqPT(card.getPower().toString(), ref.power) || !eqPT(card.getToughness().toString(), ref.toughness)) {
String pt = card.getPower() + "/" + card.getToughness(); String pt = card.getPower() + "/" + card.getToughness();
String expected = ref.power + '/' + ref.toughness; String expected = ref.power + '/' + ref.toughness;

View file

@ -7,6 +7,7 @@ import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
import mage.players.Player; import mage.players.Player;
import mage.watchers.common.ForetoldWatcher;
/** /**
* @author jeffwadsworth * @author jeffwadsworth
@ -16,6 +17,7 @@ public class ForetellSourceControllerTriggeredAbility extends TriggeredAbilityIm
public ForetellSourceControllerTriggeredAbility(Effect effect) { public ForetellSourceControllerTriggeredAbility(Effect effect) {
super(Zone.BATTLEFIELD, effect, false); super(Zone.BATTLEFIELD, effect, false);
setTriggerPhrase("Whenever you foretell a card, "); setTriggerPhrase("Whenever you foretell a card, ");
addWatcher(new ForetoldWatcher());
} }
protected ForetellSourceControllerTriggeredAbility(final ForetellSourceControllerTriggeredAbility ability) { protected ForetellSourceControllerTriggeredAbility(final ForetellSourceControllerTriggeredAbility ability) {
@ -24,16 +26,14 @@ public class ForetellSourceControllerTriggeredAbility extends TriggeredAbilityIm
@Override @Override
public boolean checkEventType(GameEvent event, Game game) { public boolean checkEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.FORETELL; return event.getType() == GameEvent.EventType.CARD_FORETOLD;
} }
@Override @Override
public boolean checkTrigger(GameEvent event, Game game) { public boolean checkTrigger(GameEvent event, Game game) {
Card card = game.getCard(event.getTargetId()); Card card = game.getCard(event.getTargetId());
Player player = game.getPlayer(event.getPlayerId()); Player player = game.getPlayer(event.getPlayerId());
return (card != null return event.getFlag() && card != null && player != null && isControlledBy(player.getId());
&& player != null
&& isControlledBy(player.getId()));
} }
@Override @Override

View file

@ -17,7 +17,7 @@ public enum ForetoldCondition implements Condition {
public boolean apply(Game game, Ability source) { public boolean apply(Game game, Ability source) {
ForetoldWatcher watcher = game.getState().getWatcher(ForetoldWatcher.class); ForetoldWatcher watcher = game.getState().getWatcher(ForetoldWatcher.class);
if (watcher != null) { if (watcher != null) {
return watcher.cardWasForetold(source.getSourceId()); return watcher.checkForetold(source.getSourceId(), game);
} }
return false; return false;
} }

View file

@ -0,0 +1,37 @@
package mage.abilities.effects.common;
import mage.abilities.Ability;
import mage.abilities.effects.OneShotEffect;
import mage.constants.Outcome;
import mage.game.Game;
import mage.players.Player;
/**
* @author TheElk801
*/
public class DrawCardsEqualToDifferenceEffect extends OneShotEffect {
private final int amount;
public DrawCardsEqualToDifferenceEffect(int amount) {
super(Outcome.Benefit);
this.amount = amount;
staticText = "draw cards equal to the difference";
}
private DrawCardsEqualToDifferenceEffect(final DrawCardsEqualToDifferenceEffect effect) {
super(effect);
this.amount = effect.amount;
}
@Override
public DrawCardsEqualToDifferenceEffect copy() {
return new DrawCardsEqualToDifferenceEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player player = game.getPlayer(source.getControllerId());
return player != null && player.drawCards(Math.max(amount - player.getHand().size(), 0), source, game) > 0;
}
}

View file

@ -0,0 +1,47 @@
package mage.abilities.effects.common.ruleModifying;
import mage.abilities.Ability;
import mage.abilities.effects.ContinuousRuleModifyingEffectImpl;
import mage.constants.Duration;
import mage.constants.Outcome;
import mage.game.Game;
import mage.game.events.GameEvent;
import mage.players.Player;
/**
* @author TheElk801
*/
public class CantCastDuringFirstThreeTurnsEffect extends ContinuousRuleModifyingEffectImpl {
public CantCastDuringFirstThreeTurnsEffect() {
this("this spell");
}
public CantCastDuringFirstThreeTurnsEffect(String selfName) {
super(Duration.WhileOnBattlefield, Outcome.Detriment);
staticText = "you can't cast " + selfName + " during your first, second, or third turns of the game";
}
private CantCastDuringFirstThreeTurnsEffect(final CantCastDuringFirstThreeTurnsEffect effect) {
super(effect);
}
@Override
public CantCastDuringFirstThreeTurnsEffect copy() {
return new CantCastDuringFirstThreeTurnsEffect(this);
}
@Override
public boolean checksEventType(GameEvent event, Game game) {
return event.getType() == GameEvent.EventType.CAST_SPELL;
}
@Override
public boolean applies(GameEvent event, Ability source, Game game) {
if (!event.getSourceId().equals(source.getSourceId())) {
return false;
}
Player controller = game.getPlayer(source.getControllerId());
return controller != null && controller.getTurns() <= 3 && game.isActivePlayer(source.getControllerId());
}
}

View file

@ -11,11 +11,15 @@ import mage.abilities.costs.Costs;
import mage.abilities.costs.mana.GenericManaCost; import mage.abilities.costs.mana.GenericManaCost;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.AsThoughEffectImpl;
import mage.abilities.effects.ContinuousEffect;
import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.ContinuousEffectImpl;
import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.OneShotEffect;
import mage.abilities.effects.common.ExileTargetEffect; import mage.abilities.effects.common.ExileTargetEffect;
import mage.cards.*; import mage.cards.*;
import mage.constants.*; import mage.constants.*;
import mage.filter.common.FilterNonlandCard;
import mage.filter.predicate.Predicates;
import mage.filter.predicate.mageobject.AbilityPredicate;
import mage.game.ExileZone; import mage.game.ExileZone;
import mage.game.Game; import mage.game.Game;
import mage.game.events.GameEvent; import mage.game.events.GameEvent;
@ -90,7 +94,90 @@ public class ForetellAbility extends SpecialAction {
return " foretells a card from hand"; return " foretells a card from hand";
} }
static class ForetellExileEffect extends OneShotEffect { public static boolean isCardInForetell(Card card, Game game) {
// searching ForetellCostAbility - it adds for foretelled cards only after exile
return card.getAbilities(game).containsClass(ForetellCostAbility.class);
}
public static ContinuousEffect makeAddForetellEffect() {
return new ForetellAddAbilityEffect();
}
/**
* For use in apply() method of OneShotEffect
* Exile the target card. It becomes foretold.
* Its foretell cost is its mana cost reduced by [amountToReduceCost]
*/
public static boolean doExileBecomesForetold(Card card, Game game, Ability source, int amountToReduceCost) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
// process Split, MDFC, and Adventure cards first
// note that 'Foretell Cost' refers to the main card (left) and 'Foretell Split Cost' refers to the (right) card if it exists
ForetellAbility foretellAbility = null;
if (card instanceof SplitCard) {
String leftHalfCost = CardUtil.reduceCost(((SplitCard) card).getLeftHalfCard().getManaCost(), amountToReduceCost).getText();
String rightHalfCost = CardUtil.reduceCost(((SplitCard) card).getRightHalfCard().getManaCost(), amountToReduceCost).getText();
game.getState().setValue(card.getMainCard().getId().toString() + "Foretell Cost", leftHalfCost);
game.getState().setValue(card.getMainCard().getId().toString() + "Foretell Split Cost", rightHalfCost);
foretellAbility = new ForetellAbility(card, leftHalfCost, rightHalfCost);
} else if (card instanceof ModalDoubleFacedCard) {
ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard();
if (!leftHalfCard.isLand(game)) { // Only MDFC cards with a left side a land have a land on the right side too
String leftHalfCost = CardUtil.reduceCost(leftHalfCard.getManaCost(), amountToReduceCost).getText();
game.getState().setValue(card.getMainCard().getId().toString() + "Foretell Cost", leftHalfCost);
ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard();
if (rightHalfCard.isLand(game)) {
foretellAbility = new ForetellAbility(card, leftHalfCost);
} else {
String rightHalfCost = CardUtil.reduceCost(rightHalfCard.getManaCost(), amountToReduceCost).getText();
game.getState().setValue(card.getMainCard().getId().toString() + "Foretell Split Cost", rightHalfCost);
foretellAbility = new ForetellAbility(card, leftHalfCost, rightHalfCost);
}
}
} else if (card instanceof CardWithSpellOption) {
String creatureCost = CardUtil.reduceCost(card.getMainCard().getManaCost(), amountToReduceCost).getText();
String spellCost = CardUtil.reduceCost(((CardWithSpellOption) card).getSpellCard().getManaCost(), amountToReduceCost).getText();
game.getState().setValue(card.getMainCard().getId().toString() + "Foretell Cost", creatureCost);
game.getState().setValue(card.getMainCard().getId().toString() + "Foretell Split Cost", spellCost);
foretellAbility = new ForetellAbility(card, creatureCost, spellCost);
} else if (!card.isLand(game)) {
// normal card
String costText = CardUtil.reduceCost(card.getManaCost(), amountToReduceCost).getText();
game.getState().setValue(card.getId().toString() + "Foretell Cost", costText);
foretellAbility = new ForetellAbility(card, costText);
}
// All card types (including lands) must be exiled
UUID exileId = CardUtil.getExileZoneId(card.getMainCard().getId().toString() + "foretellAbility", game);
controller.moveCardsToExile(card, source, game, false, exileId, " Foretell Turn Number: " + game.getTurnNum());
card.setFaceDown(true, game);
// all done pre-processing so stick the foretell cost effect onto the main card
// note that the card is not foretell'd into exile, it is put into exile and made foretold
// If the card is a non-land, it will not be exiled.
if (foretellAbility != null) {
// copy source and use it for the foretold effect on the exiled card
// bug #8673
Ability copiedSource = source.copy();
copiedSource.newId();
copiedSource.setSourceId(card.getId());
game.getState().setValue(card.getMainCard().getId().toString() + "Foretell Turn Number", game.getTurnNum());
foretellAbility.setSourceId(card.getId());
foretellAbility.setControllerId(card.getOwnerId());
game.getState().addOtherAbility(card, foretellAbility);
foretellAbility.activate(game, true);
game.addEffect(new ForetellAddCostEffect(new MageObjectReference(card, game)), copiedSource);
game.fireEvent(new GameEvent(GameEvent.EventType.CARD_FORETOLD, card.getId(), copiedSource, copiedSource.getControllerId(), 0, false));
}
return true;
}
}
class ForetellExileEffect extends OneShotEffect {
private final Card card; private final Card card;
String foretellCost; String foretellCost;
@ -103,7 +190,7 @@ public class ForetellAbility extends SpecialAction {
this.foretellSplitCost = foretellSplitCost; this.foretellSplitCost = foretellSplitCost;
} }
protected ForetellExileEffect(final ForetellExileEffect effect) { private ForetellExileEffect(final ForetellExileEffect effect) {
super(effect); super(effect);
this.card = effect.card; this.card = effect.card;
this.foretellCost = effect.foretellCost; this.foretellCost = effect.foretellCost;
@ -143,20 +230,20 @@ public class ForetellAbility extends SpecialAction {
effect.apply(game, source); effect.apply(game, source);
card.setFaceDown(true, game); card.setFaceDown(true, game);
game.addEffect(new ForetellAddCostEffect(new MageObjectReference(card, game)), source); game.addEffect(new ForetellAddCostEffect(new MageObjectReference(card, game)), source);
game.fireEvent(GameEvent.getEvent(GameEvent.EventType.FORETELL, card.getId(), null, source.getControllerId())); game.fireEvent(new GameEvent(GameEvent.EventType.CARD_FORETOLD, card.getId(), source, source.getControllerId(), 0, true));
return true; return true;
} }
return false; return false;
} }
} }
static class ForetellLookAtCardEffect extends AsThoughEffectImpl { class ForetellLookAtCardEffect extends AsThoughEffectImpl {
ForetellLookAtCardEffect() { ForetellLookAtCardEffect() {
super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.AIDontUseIt); super(AsThoughEffectType.LOOK_AT_FACE_DOWN, Duration.EndOfGame, Outcome.AIDontUseIt);
} }
protected ForetellLookAtCardEffect(final ForetellLookAtCardEffect effect) { private ForetellLookAtCardEffect(final ForetellLookAtCardEffect effect) {
super(effect); super(effect);
} }
@ -188,19 +275,19 @@ public class ForetellAbility extends SpecialAction {
} }
return false; return false;
} }
} }
public static class ForetellAddCostEffect extends ContinuousEffectImpl { class ForetellAddCostEffect extends ContinuousEffectImpl {
private final MageObjectReference mor; private final MageObjectReference mor;
public ForetellAddCostEffect(MageObjectReference mor) { ForetellAddCostEffect(MageObjectReference mor) {
super(Duration.EndOfGame, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility); super(Duration.EndOfGame, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
this.mor = mor; this.mor = mor;
staticText = "Foretold card"; staticText = "Foretold card";
} }
protected ForetellAddCostEffect(final ForetellAddCostEffect effect) { private ForetellAddCostEffect(final ForetellAddCostEffect effect) {
super(effect); super(effect);
this.mor = effect.mor; this.mor = effect.mor;
} }
@ -295,9 +382,9 @@ public class ForetellAbility extends SpecialAction {
public ForetellAddCostEffect copy() { public ForetellAddCostEffect copy() {
return new ForetellAddCostEffect(this); return new ForetellAddCostEffect(this);
} }
} }
static class ForetellCostAbility extends SpellAbility { class ForetellCostAbility extends SpellAbility {
private String abilityName; private String abilityName;
private SpellAbility spellAbilityToResolve; private SpellAbility spellAbilityToResolve;
@ -315,7 +402,7 @@ public class ForetellAbility extends SpecialAction {
this.addCost(new ManaCostsImpl<>(foretellCost)); this.addCost(new ManaCostsImpl<>(foretellCost));
} }
protected ForetellCostAbility(final ForetellCostAbility ability) { private ForetellCostAbility(final ForetellCostAbility ability) {
super(ability); super(ability);
this.spellAbilityType = ability.spellAbilityType; this.spellAbilityType = ability.spellAbilityType;
this.abilityName = ability.abilityName; this.abilityName = ability.abilityName;
@ -458,14 +545,74 @@ public class ForetellAbility extends SpecialAction {
* Used for split card in PlayerImpl method: * Used for split card in PlayerImpl method:
* getOtherUseableActivatedAbilities * getOtherUseableActivatedAbilities
*/ */
public void setAbilityName(String abilityName) { void setAbilityName(String abilityName) {
this.abilityName = abilityName; this.abilityName = abilityName;
} }
}
class ForetellAddAbilityEffect extends ContinuousEffectImpl {
private static final FilterNonlandCard filter = new FilterNonlandCard();
static {
filter.add(Predicates.not(new AbilityPredicate(ForetellAbility.class)));
} }
public static boolean isCardInForetell(Card card, Game game) { ForetellAddAbilityEffect() {
// searching ForetellCostAbility - it adds for foretelled cards only after exile super(Duration.WhileOnBattlefield, Layer.AbilityAddingRemovingEffects_6, SubLayer.NA, Outcome.AddAbility);
return card.getAbilities(game).containsClass(ForetellCostAbility.class); this.staticText = "Each nonland card in your hand without foretell has foretell. Its foretell cost is equal to its mana cost reduced by {2}";
}
private ForetellAddAbilityEffect(final ForetellAddAbilityEffect effect) {
super(effect);
}
@Override
public ForetellAddAbilityEffect copy() {
return new ForetellAddAbilityEffect(this);
}
@Override
public boolean apply(Game game, Ability source) {
Player controller = game.getPlayer(source.getControllerId());
if (controller == null) {
return false;
}
for (Card card : controller.getHand().getCards(filter, game)) {
ForetellAbility foretellAbility = null;
if (card instanceof SplitCard) {
String leftHalfCost = CardUtil.reduceCost(((SplitCard) card).getLeftHalfCard().getManaCost(), 2).getText();
String rightHalfCost = CardUtil.reduceCost(((SplitCard) card).getRightHalfCard().getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, leftHalfCost, rightHalfCost);
} else if (card instanceof ModalDoubleFacedCard) {
ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard();
// If front side of MDFC is land, do nothing as Dream Devourer does not apply to lands
// MDFC cards in hand are considered lands if front side is land
if (!leftHalfCard.isLand(game)) {
String leftHalfCost = CardUtil.reduceCost(leftHalfCard.getManaCost(), 2).getText();
ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard();
if (rightHalfCard.isLand(game)) {
foretellAbility = new ForetellAbility(card, leftHalfCost);
} else {
String rightHalfCost = CardUtil.reduceCost(rightHalfCard.getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, leftHalfCost, rightHalfCost);
}
}
} else if (card instanceof CardWithSpellOption) {
String creatureCost = CardUtil.reduceCost(card.getMainCard().getManaCost(), 2).getText();
String spellCost = CardUtil.reduceCost(((CardWithSpellOption) card).getSpellCard().getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, creatureCost, spellCost);
} else {
String costText = CardUtil.reduceCost(card.getManaCost(), 2).getText();
foretellAbility = new ForetellAbility(card, costText);
}
if (foretellAbility != null) {
foretellAbility.setSourceId(card.getId());
foretellAbility.setControllerId(card.getOwnerId());
game.getState().addOtherAbility(card, foretellAbility);
}
}
return true;
} }
} }

View file

@ -1,16 +1,19 @@
package mage.abilities.keyword; package mage.abilities.keyword;
import mage.ApprovingObject;
import mage.MageIdentifier; import mage.MageIdentifier;
import mage.MageObjectReference;
import mage.abilities.SpellAbility; import mage.abilities.SpellAbility;
import mage.abilities.costs.mana.ManaCostsImpl; import mage.abilities.costs.mana.ManaCostsImpl;
import mage.cards.Card; import mage.cards.Card;
import mage.constants.SpellAbilityType; import mage.constants.SpellAbilityType;
import mage.constants.WatcherScope;
import mage.constants.Zone; import mage.constants.Zone;
import mage.game.Game; import mage.game.Game;
import mage.players.Player; import mage.game.events.DiscardedCardsEvent;
import mage.watchers.common.CastSpellLastTurnWatcher; import mage.game.events.GameEvent;
import mage.watchers.Watcher;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@ -33,10 +36,10 @@ public class MayhemAbility extends SpellAbility {
this.clearManaCosts(); this.clearManaCosts();
this.clearManaCostsToPay(); this.clearManaCostsToPay();
this.addCost(new ManaCostsImpl<>(manaString)); this.addCost(new ManaCostsImpl<>(manaString));
this.addWatcher(new MayhemWatcher());
this.setRuleAtTheTop(true); this.setRuleAtTheTop(true);
this.rule = "Surge " + manaString + this.rule = "Mayhem " + manaString +
" <i>(You may cast this card from your graveyard for "+manaString+ " <i>(You may cast this card from your graveyard for " + manaString +
" if you discarded it this turn. Timing rules still apply.)</i>"; " if you discarded it this turn. Timing rules still apply.)</i>";
} }
@ -47,8 +50,11 @@ public class MayhemAbility extends SpellAbility {
@Override @Override
public ActivationStatus canActivate(UUID playerId, Game game) { public ActivationStatus canActivate(UUID playerId, Game game) {
// TODO: Implement this if (!Zone.GRAVEYARD.match(game.getState().getZone(getSourceId()))
return super.canActivate(playerId,game); || !MayhemWatcher.checkCard(getSourceId(), game)) {
return ActivationStatus.getFalse();
}
return super.canActivate(playerId, game);
} }
@Override @Override
@ -69,5 +75,38 @@ public class MayhemAbility extends SpellAbility {
public String getRule() { public String getRule() {
return rule; return rule;
} }
}
class MayhemWatcher extends Watcher {
private final Set<MageObjectReference> set = new HashSet<>();
MayhemWatcher() {
super(WatcherScope.GAME);
}
@Override
public void watch(GameEvent event, Game game) {
if (event.getType() != GameEvent.EventType.DISCARDED_CARDS) {
return;
}
for (Card card : ((DiscardedCardsEvent) event).getDiscardedCards().getCards(game)) {
set.add(new MageObjectReference(card, game));
}
}
@Override
public void reset() {
super.reset();
set.clear();
}
static boolean checkCard(UUID cardId, Game game) {
return game
.getState()
.getWatcher(MayhemWatcher.class)
.set
.stream()
.anyMatch(mor -> mor.refersTo(cardId, game));
}
} }

Some files were not shown because too many files have changed in this diff Show more