diff --git a/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java b/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java index 70e55d2687c..2fcc2311642 100644 --- a/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java +++ b/Mage.Sets/src/mage/cards/a/AbandonedSarcophagus.java @@ -7,7 +7,7 @@ import java.util.UUID; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.asthought.PlayFromNotOwnHandZoneAllEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.abilities.keyword.CyclingAbility; import mage.cards.*; import mage.constants.*; @@ -26,7 +26,7 @@ import mage.watchers.Watcher; */ public final class AbandonedSarcophagus extends CardImpl { - private static final FilterCard filter = new FilterCard("nonland cards with cycling"); + private static final FilterCard filter = new FilterCard("spells that have a cycling ability"); static { filter.add(Predicates.not(CardType.LAND.getPredicate())); @@ -37,11 +37,7 @@ public final class AbandonedSarcophagus extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // You may cast nonland cards with cycling from your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new PlayFromNotOwnHandZoneAllEffect(filter, - Zone.GRAVEYARD, true, TargetController.YOU, Duration.WhileOnBattlefield) - .setText("You may cast nonland cards with cycling from your graveyard")) - ); + this.addAbility(new SimpleStaticAbility(new PlayFromGraveyardControllerEffect(filter))); // If a card with cycling would be put into your graveyard from anywhere and it wasn't cycled, exile it instead. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new AbandonedSarcophagusReplacementEffect()), new AbandonedSarcophagusWatcher()); @@ -101,7 +97,7 @@ class AbandonedSarcophagusReplacementEffect extends ReplacementEffectImpl { @Override public boolean applies(GameEvent event, Ability source, Game game) { - if (!(((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD)) { + if (((ZoneChangeEvent) event).getToZone() != Zone.GRAVEYARD) { return false; } diff --git a/Mage.Sets/src/mage/cards/a/AncientGreenwarden.java b/Mage.Sets/src/mage/cards/a/AncientGreenwarden.java index 74aebc13b10..99e8a054976 100644 --- a/Mage.Sets/src/mage/cards/a/AncientGreenwarden.java +++ b/Mage.Sets/src/mage/cards/a/AncientGreenwarden.java @@ -4,7 +4,7 @@ import mage.MageInt; import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.ReplacementEffectImpl; -import mage.abilities.effects.common.ruleModifying.PlayLandsFromGraveyardControllerEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.abilities.keyword.ReachAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -36,7 +36,7 @@ public final class AncientGreenwarden extends CardImpl { this.addAbility(ReachAbility.getInstance()); // You may play lands from your graveyard. - this.addAbility(new SimpleStaticAbility(new PlayLandsFromGraveyardControllerEffect())); + this.addAbility(new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLands())); // If a land entering the battlefield causes a triggered ability of a permanent you control to trigger, that ability triggers an additional time. this.addAbility(new SimpleStaticAbility(new AncientGreenwardenEffect())); diff --git a/Mage.Sets/src/mage/cards/c/ConduitOfWorlds.java b/Mage.Sets/src/mage/cards/c/ConduitOfWorlds.java index 9f2c649eaf0..b0b39d8a3e3 100644 --- a/Mage.Sets/src/mage/cards/c/ConduitOfWorlds.java +++ b/Mage.Sets/src/mage/cards/c/ConduitOfWorlds.java @@ -8,7 +8,7 @@ import mage.abilities.condition.common.HaventCastSpellThisTurnCondition; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.OneShotEffect; -import mage.abilities.effects.common.ruleModifying.PlayLandsFromGraveyardControllerEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -40,7 +40,7 @@ public final class ConduitOfWorlds extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{2}{G}{G}"); // You may play lands from your graveyard. - this.addAbility(new SimpleStaticAbility(new PlayLandsFromGraveyardControllerEffect())); + this.addAbility(new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLands())); // {T}: Choose target nonland permanent card in your graveyard. If you haven't cast a spell this turn, you may cast that card. If you do, you can't cast additional spells this turn. Activate only as a sorcery. Ability ability = new ActivateAsSorceryActivatedAbility(new ConduitOfWorldsEffect(), new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/c/CrucibleOfWorlds.java b/Mage.Sets/src/mage/cards/c/CrucibleOfWorlds.java index e084861b33c..60fc8de5097 100644 --- a/Mage.Sets/src/mage/cards/c/CrucibleOfWorlds.java +++ b/Mage.Sets/src/mage/cards/c/CrucibleOfWorlds.java @@ -1,11 +1,10 @@ package mage.cards.c; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.ruleModifying.PlayLandsFromGraveyardControllerEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; -import mage.constants.Zone; import java.util.UUID; @@ -18,7 +17,7 @@ public final class CrucibleOfWorlds extends CardImpl { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); // You may play lands from your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayLandsFromGraveyardControllerEffect())); + this.addAbility(new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLands())); } private CrucibleOfWorlds(final CrucibleOfWorlds card) { diff --git a/Mage.Sets/src/mage/cards/g/GaeasWill.java b/Mage.Sets/src/mage/cards/g/GaeasWill.java index 34cc9981afe..efa9a913796 100644 --- a/Mage.Sets/src/mage/cards/g/GaeasWill.java +++ b/Mage.Sets/src/mage/cards/g/GaeasWill.java @@ -1,16 +1,14 @@ package mage.cards.g; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.abilities.keyword.SuspendAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.Duration; import java.util.UUID; @@ -28,8 +26,8 @@ public final class GaeasWill extends CardImpl { // Suspend 4—{G} this.addAbility(new SuspendAbility(4, new ManaCostsImpl<>("{G}"), this)); - // Until end of turn, you may play land cards and cast spells from your graveyard. - this.getSpellAbility().addEffect(new GaeasWillGraveyardEffect()); + // Until end of turn, you may play lands and cast spells from your graveyard. + this.getSpellAbility().addEffect(PlayFromGraveyardControllerEffect.playLandsAndCastSpells(Duration.EndOfTurn)); // If a card would be put into your graveyard from anywhere this turn, exile that card instead. this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(Duration.EndOfTurn))); @@ -44,34 +42,3 @@ public final class GaeasWill extends CardImpl { return new GaeasWill(this); } } - -class GaeasWillGraveyardEffect extends ContinuousEffectImpl { - - GaeasWillGraveyardEffect() { - this(Duration.EndOfTurn); - } - - public GaeasWillGraveyardEffect(Duration duration) { - super(duration, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); - this.staticText = "Until end of turn, you may play lands and cast spells from your graveyard"; - } - - private GaeasWillGraveyardEffect(final GaeasWillGraveyardEffect effect) { - super(effect); - } - - @Override - public GaeasWillGraveyardEffect copy() { - return new GaeasWillGraveyardEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.setPlayCardsFromGraveyard(true); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HaakonStromgaldScourge.java b/Mage.Sets/src/mage/cards/h/HaakonStromgaldScourge.java index 7545e783849..4af1a2678bf 100644 --- a/Mage.Sets/src/mage/cards/h/HaakonStromgaldScourge.java +++ b/Mage.Sets/src/mage/cards/h/HaakonStromgaldScourge.java @@ -1,5 +1,3 @@ - - package mage.cards.h; import mage.MageInt; @@ -9,10 +7,12 @@ import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.ContinuousRuleModifyingEffectImpl; import mage.abilities.effects.common.LoseLifeSourceControllerEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.cards.Card; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; +import mage.filter.common.FilterNonlandCard; import mage.game.Game; import mage.game.events.GameEvent; @@ -23,6 +23,11 @@ import java.util.UUID; */ public final class HaakonStromgaldScourge extends CardImpl { + private static final FilterNonlandCard filter = new FilterNonlandCard("Knight spells"); + static { + filter.add(SubType.KNIGHT.getPredicate()); + } + public HaakonStromgaldScourge(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{B}{B}"); this.supertype.add(SuperType.LEGENDARY); @@ -37,8 +42,9 @@ public final class HaakonStromgaldScourge extends CardImpl { ability.addEffect(new HaakonStromgaldScourgePlayEffect2()); this.addAbility(ability); - // As long as Haakon is on the battlefield, you may play Knight cards from your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new HaakonPlayKnightsFromGraveyardEffect())); + // As long as Haakon is on the battlefield, you may cast Knight spells from your graveyard. + this.addAbility(new SimpleStaticAbility(new PlayFromGraveyardControllerEffect(filter) + .setText("As long as {this} is on the battlefield, you may cast Knight spells from your graveyard"))); // When Haakon dies, you lose 2 life. this.addAbility(new DiesSourceTriggeredAbility(new LoseLifeSourceControllerEffect(2))); @@ -119,38 +125,3 @@ class HaakonStromgaldScourgePlayEffect2 extends ContinuousRuleModifyingEffectImp return false; } } - -class HaakonPlayKnightsFromGraveyardEffect extends AsThoughEffectImpl { - - public HaakonPlayKnightsFromGraveyardEffect() { - super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "As long as {this} is on the battlefield, you may cast Knight spells from your graveyard"; - } - - private HaakonPlayKnightsFromGraveyardEffect(final HaakonPlayKnightsFromGraveyardEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public HaakonPlayKnightsFromGraveyardEffect copy() { - return new HaakonPlayKnightsFromGraveyardEffect(this); - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getControllerId())) { - Card knightToCast = game.getCard(objectId); - return knightToCast != null - && knightToCast.hasSubtype(SubType.KNIGHT, game) - && !knightToCast.isLand(game) - && knightToCast.isOwnedBy(source.getControllerId()) - && game.getState().getZone(objectId) == Zone.GRAVEYARD; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/h/HazezonShaperOfSand.java b/Mage.Sets/src/mage/cards/h/HazezonShaperOfSand.java index a4094cc2087..e6bddc5981c 100644 --- a/Mage.Sets/src/mage/cards/h/HazezonShaperOfSand.java +++ b/Mage.Sets/src/mage/cards/h/HazezonShaperOfSand.java @@ -4,14 +4,13 @@ import mage.MageInt; import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; -import mage.abilities.effects.common.ruleModifying.PlayLandsFromGraveyardControllerEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.abilities.keyword.LandwalkAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.SuperType; -import mage.constants.Zone; import mage.filter.common.FilterControlledLandPermanent; import mage.filter.common.FilterLandCard; import mage.game.permanent.token.SandWarriorToken; @@ -46,7 +45,7 @@ public final class HazezonShaperOfSand extends CardImpl { this.addAbility(new LandwalkAbility(filter)); // You may play Desert lands from your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayLandsFromGraveyardControllerEffect(filter2))); + this.addAbility(new SimpleStaticAbility(new PlayFromGraveyardControllerEffect(filter2))); // Whenever a Desert you control enters create two 1/1 red, green, and white Sand Warrior creature tokens. this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new CreateTokenEffect( diff --git a/Mage.Sets/src/mage/cards/l/LilianaUntouchedByDeath.java b/Mage.Sets/src/mage/cards/l/LilianaUntouchedByDeath.java index ed5809a3b97..5f40643925c 100644 --- a/Mage.Sets/src/mage/cards/l/LilianaUntouchedByDeath.java +++ b/Mage.Sets/src/mage/cards/l/LilianaUntouchedByDeath.java @@ -5,15 +5,15 @@ import mage.abilities.LoyaltyAbility; import mage.abilities.dynamicvalue.DynamicValue; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; import mage.abilities.dynamicvalue.common.SignInversionDynamicValue; -import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.OneShotEffect; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; -import mage.cards.Card; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterControlledPermanent; +import mage.filter.common.FilterNonlandCard; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetCreaturePermanent; @@ -29,6 +29,11 @@ public final class LilianaUntouchedByDeath extends CardImpl { new PermanentsOnBattlefieldCount(new FilterControlledPermanent(SubType.ZOMBIE, "Zombies you control"), null) ); + private static final FilterNonlandCard filter = new FilterNonlandCard("Zombie spells"); + static { + filter.add(SubType.ZOMBIE.getPredicate()); + } + public LilianaUntouchedByDeath(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "{2}{B}{B}"); @@ -44,8 +49,9 @@ public final class LilianaUntouchedByDeath extends CardImpl { ability.addTarget(new TargetCreaturePermanent()); this.addAbility(ability); - // -3: You may cast Zombie cards from your graveyard this turn. - this.addAbility(new LoyaltyAbility(new LilianaUntouchedByDeathGraveyardEffect(), -3)); + // -3: You may cast Zombie spells from your graveyard this turn. + this.addAbility(new LoyaltyAbility(new PlayFromGraveyardControllerEffect(filter, Duration.EndOfTurn) + .setText("You may cast Zombie spells from your graveyard this turn"), -3)); } private LilianaUntouchedByDeath(final LilianaUntouchedByDeath card) { @@ -91,39 +97,3 @@ class LilianaUntouchedByDeathEffect extends OneShotEffect { return true; } } - -class LilianaUntouchedByDeathGraveyardEffect extends AsThoughEffectImpl { - - LilianaUntouchedByDeathGraveyardEffect() { - super(AsThoughEffectType.CAST_FROM_NOT_OWN_HAND_ZONE, Duration.EndOfTurn, Outcome.Benefit); - staticText = "You may cast Zombie cards from your graveyard this turn"; - } - - private LilianaUntouchedByDeathGraveyardEffect(final LilianaUntouchedByDeathGraveyardEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public LilianaUntouchedByDeathGraveyardEffect copy() { - return new LilianaUntouchedByDeathGraveyardEffect(this); - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (affectedControllerId.equals(source.getControllerId())) { - Card card = game.getCard(objectId); - if (card != null - && card.hasSubtype(SubType.ZOMBIE, game) - && card.isOwnedBy(source.getControllerId()) - && game.getState().getZone(objectId) == Zone.GRAVEYARD) { - return true; - } - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheWill.java b/Mage.Sets/src/mage/cards/m/MagusOfTheWill.java index 7fb505b88c4..782e10e775d 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheWill.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheWill.java @@ -1,4 +1,3 @@ - package mage.cards.m; import mage.MageInt; @@ -7,13 +6,14 @@ import mage.abilities.common.SimpleActivatedAbility; import mage.abilities.costs.common.ExileSourceCost; import mage.abilities.costs.common.TapSourceCost; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.SubType; +import mage.constants.Zone; import java.util.UUID; @@ -31,9 +31,11 @@ public final class MagusOfTheWill extends CardImpl { this.power = new MageInt(3); this.toughness = new MageInt(3); - // {2}{B}, {T}, Exile Magus of the Will: Until end of turn, you may play cards from your graveyard. + // {2}{B}, {T}, Exile Magus of the Will: Until end of turn, you may play lands and cast spells from your graveyard. // If a card would be put into your graveyard from anywhere else this turn, exile that card instead. - Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, new CanPlayCardsFromGraveyardEffect(), new ManaCostsImpl<>("{2}{B}")); + Ability ability = new SimpleActivatedAbility(Zone.BATTLEFIELD, + PlayFromGraveyardControllerEffect.playLandsAndCastSpells(Duration.EndOfTurn), + new ManaCostsImpl<>("{2}{B}")); ability.addEffect(new GraveyardFromAnywhereExileReplacementEffect(Duration.EndOfTurn)); ability.addCost(new TapSourceCost()); ability.addCost(new ExileSourceCost()); @@ -49,35 +51,3 @@ public final class MagusOfTheWill extends CardImpl { return new MagusOfTheWill(this); } } - -class CanPlayCardsFromGraveyardEffect extends ContinuousEffectImpl { - - CanPlayCardsFromGraveyardEffect() { - this(Duration.EndOfTurn); - } - - public CanPlayCardsFromGraveyardEffect(Duration duration) { - super(duration, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); - staticText = "Until end of turn, you may play cards from your graveyard"; - } - - private CanPlayCardsFromGraveyardEffect(final CanPlayCardsFromGraveyardEffect effect) { - super(effect); - } - - @Override - public CanPlayCardsFromGraveyardEffect copy() { - return new CanPlayCardsFromGraveyardEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.setPlayCardsFromGraveyard(true); - return true; - } - return false; - } - -} diff --git a/Mage.Sets/src/mage/cards/p/PerennialBehemoth.java b/Mage.Sets/src/mage/cards/p/PerennialBehemoth.java index b9eb831ffbe..b9be5f67820 100644 --- a/Mage.Sets/src/mage/cards/p/PerennialBehemoth.java +++ b/Mage.Sets/src/mage/cards/p/PerennialBehemoth.java @@ -3,7 +3,7 @@ package mage.cards.p; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.costs.mana.ManaCostsImpl; -import mage.abilities.effects.common.ruleModifying.PlayLandsFromGraveyardControllerEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.abilities.keyword.UnearthAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -25,7 +25,7 @@ public final class PerennialBehemoth extends CardImpl { this.toughness = new MageInt(7); // You may play land cards from your graveyard. - this.addAbility(new SimpleStaticAbility(new PlayLandsFromGraveyardControllerEffect())); + this.addAbility(new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLands())); // Unearth {G}{G} this.addAbility(new UnearthAbility(new ManaCostsImpl<>("{G}{G}"))); diff --git a/Mage.Sets/src/mage/cards/r/RamunapExcavator.java b/Mage.Sets/src/mage/cards/r/RamunapExcavator.java index 6fe090f7033..6b849abadb7 100644 --- a/Mage.Sets/src/mage/cards/r/RamunapExcavator.java +++ b/Mage.Sets/src/mage/cards/r/RamunapExcavator.java @@ -2,12 +2,11 @@ package mage.cards.r; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.common.ruleModifying.PlayLandsFromGraveyardControllerEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; -import mage.constants.Zone; import java.util.UUID; @@ -25,7 +24,7 @@ public final class RamunapExcavator extends CardImpl { this.toughness = new MageInt(3); // You may play lands from your graveyard. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayLandsFromGraveyardControllerEffect())); + this.addAbility(new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLands())); } private RamunapExcavator(final RamunapExcavator card) { @@ -36,4 +35,4 @@ public final class RamunapExcavator extends CardImpl { public RamunapExcavator copy() { return new RamunapExcavator(this); } -} \ No newline at end of file +} diff --git a/Mage.Sets/src/mage/cards/t/TitaniaNaturesForce.java b/Mage.Sets/src/mage/cards/t/TitaniaNaturesForce.java index 88177ad55eb..0707ec84d44 100644 --- a/Mage.Sets/src/mage/cards/t/TitaniaNaturesForce.java +++ b/Mage.Sets/src/mage/cards/t/TitaniaNaturesForce.java @@ -6,7 +6,7 @@ import mage.abilities.common.EntersBattlefieldControlledTriggeredAbility; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.CreateTokenEffect; import mage.abilities.effects.common.MillCardsControllerEffect; -import mage.abilities.effects.common.ruleModifying.PlayLandsFromGraveyardControllerEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; import mage.constants.CardType; @@ -24,7 +24,7 @@ import java.util.UUID; */ public final class TitaniaNaturesForce extends CardImpl { - private static final FilterCard filter = new FilterCard("Forests"); + private static final FilterCard filter = new FilterCard("play Forests"); private static final FilterPermanent filter2 = new FilterPermanent(SubType.FOREST, "a Forest"); private static final FilterPermanent filter3 = new FilterControlledPermanent(SubType.ELEMENTAL, "an Elemental you control"); @@ -42,7 +42,7 @@ public final class TitaniaNaturesForce extends CardImpl { this.toughness = new MageInt(6); // You may play Forests from your graveyard. - this.addAbility(new SimpleStaticAbility(new PlayLandsFromGraveyardControllerEffect(filter))); + this.addAbility(new SimpleStaticAbility(new PlayFromGraveyardControllerEffect(filter))); // Whenever a Forest you control enters, create a 5/3 green Elemental creature token. this.addAbility(new EntersBattlefieldControlledTriggeredAbility( diff --git a/Mage.Sets/src/mage/cards/y/YawgmothsAgenda.java b/Mage.Sets/src/mage/cards/y/YawgmothsAgenda.java index 3c06fb78394..6bf54afe5bf 100644 --- a/Mage.Sets/src/mage/cards/y/YawgmothsAgenda.java +++ b/Mage.Sets/src/mage/cards/y/YawgmothsAgenda.java @@ -1,16 +1,14 @@ - package mage.cards.y; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.continuous.CantCastMoreThanOneSpellEffect; import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.Duration; +import mage.constants.TargetController; import java.util.UUID; @@ -25,8 +23,10 @@ public final class YawgmothsAgenda extends CardImpl { // You can't cast more than one spell each turn. this.addAbility(new SimpleStaticAbility(new CantCastMoreThanOneSpellEffect(TargetController.YOU))); - // You may play cards from your graveyard. - this.addAbility(new SimpleStaticAbility(new YawgmothsAgendaCanPlayCardsFromGraveyardEffect())); + + // You may play lands and cast spells from your graveyard. + this.addAbility(new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLandsAndCastSpells(Duration.WhileOnBattlefield))); + // If a card would be put into your graveyard from anywhere, exile it instead. this.addAbility(new SimpleStaticAbility(new GraveyardFromAnywhereExileReplacementEffect(true, false))); } @@ -40,34 +40,3 @@ public final class YawgmothsAgenda extends CardImpl { return new YawgmothsAgenda(this); } } - -class YawgmothsAgendaCanPlayCardsFromGraveyardEffect extends ContinuousEffectImpl { - - YawgmothsAgendaCanPlayCardsFromGraveyardEffect() { - this(Duration.WhileOnBattlefield); - } - - public YawgmothsAgendaCanPlayCardsFromGraveyardEffect(Duration duration) { - super(duration, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); - staticText = "You may play cards from your graveyard"; - } - - private YawgmothsAgendaCanPlayCardsFromGraveyardEffect(final YawgmothsAgendaCanPlayCardsFromGraveyardEffect effect) { - super(effect); - } - - @Override - public YawgmothsAgendaCanPlayCardsFromGraveyardEffect copy() { - return new YawgmothsAgendaCanPlayCardsFromGraveyardEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.setPlayCardsFromGraveyard(true); - return true; - } - return false; - } -} diff --git a/Mage.Sets/src/mage/cards/y/YawgmothsWill.java b/Mage.Sets/src/mage/cards/y/YawgmothsWill.java index f6af0a369a1..03d24b5e084 100644 --- a/Mage.Sets/src/mage/cards/y/YawgmothsWill.java +++ b/Mage.Sets/src/mage/cards/y/YawgmothsWill.java @@ -1,14 +1,11 @@ - package mage.cards.y; -import mage.abilities.Ability; -import mage.abilities.effects.ContinuousEffectImpl; import mage.abilities.effects.common.replacement.GraveyardFromAnywhereExileReplacementEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; -import mage.constants.*; -import mage.game.Game; -import mage.players.Player; +import mage.constants.CardType; +import mage.constants.Duration; import java.util.UUID; @@ -21,8 +18,8 @@ public final class YawgmothsWill extends CardImpl { public YawgmothsWill(UUID ownerId, CardSetInfo setInfo) { super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}"); - // Until end of turn, you may play cards from your graveyard. - this.getSpellAbility().addEffect(new CanPlayCardsFromGraveyardEffect()); + // Until end of turn, you may play lands and cast spells from your graveyard. + this.getSpellAbility().addEffect(PlayFromGraveyardControllerEffect.playLandsAndCastSpells(Duration.EndOfTurn)); // If a card would be put into your graveyard from anywhere this turn, exile that card instead. this.getSpellAbility().addEffect(new GraveyardFromAnywhereExileReplacementEffect(Duration.EndOfTurn).concatBy("
")); @@ -37,35 +34,3 @@ public final class YawgmothsWill extends CardImpl { return new YawgmothsWill(this); } } - -class CanPlayCardsFromGraveyardEffect extends ContinuousEffectImpl { - - CanPlayCardsFromGraveyardEffect() { - this(Duration.EndOfTurn); - } - - public CanPlayCardsFromGraveyardEffect(Duration duration) { - super(duration, Layer.PlayerEffects, SubLayer.NA, Outcome.Benefit); - staticText = "Until end of turn, you may play cards from your graveyard"; - } - - private CanPlayCardsFromGraveyardEffect(final CanPlayCardsFromGraveyardEffect effect) { - super(effect); - } - - @Override - public CanPlayCardsFromGraveyardEffect copy() { - return new CanPlayCardsFromGraveyardEffect(this); - } - - @Override - public boolean apply(Game game, Ability source) { - Player controller = game.getPlayer(source.getControllerId()); - if (controller != null) { - controller.setPlayCardsFromGraveyard(true); - return true; - } - return false; - } - -} diff --git a/Mage.Sets/src/mage/cards/z/ZaskSkitteringSwarmlord.java b/Mage.Sets/src/mage/cards/z/ZaskSkitteringSwarmlord.java index 0d026512ed5..b213e2dac86 100644 --- a/Mage.Sets/src/mage/cards/z/ZaskSkitteringSwarmlord.java +++ b/Mage.Sets/src/mage/cards/z/ZaskSkitteringSwarmlord.java @@ -9,7 +9,7 @@ import mage.abilities.effects.common.MillCardsControllerEffect; import mage.abilities.effects.common.PutOnLibraryTargetEffect; import mage.abilities.effects.common.continuous.BoostTargetEffect; import mage.abilities.effects.common.continuous.GainAbilityTargetEffect; -import mage.abilities.effects.common.ruleModifying.PlayLandsFromGraveyardControllerEffect; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.abilities.keyword.DeathtouchAbility; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -27,7 +27,7 @@ import java.util.UUID; */ public final class ZaskSkitteringSwarmlord extends CardImpl { - private static final FilterCard filter = new FilterCard("lands and cast Insect spells"); + private static final FilterCard filter = new FilterCard("play lands and cast Insect spells"); private static final FilterCreaturePermanent filter2 = new FilterCreaturePermanent(SubType.INSECT, "another Insect you control"); private static final FilterCreaturePermanent filter3 = new FilterCreaturePermanent(SubType.INSECT, "Insect"); @@ -46,7 +46,7 @@ public final class ZaskSkitteringSwarmlord extends CardImpl { // You may play lands and cast Insect spells from your graveyard. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, - new PlayLandsFromGraveyardControllerEffect(filter) + new PlayFromGraveyardControllerEffect(filter) )); // Whenever another Insect you control dies, put it on the bottom of its owner's library, then mill two cards. diff --git a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java index 62231cb948e..ff6d8181f3d 100644 --- a/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java +++ b/Mage.Tests/src/test/java/org/mage/test/player/TestPlayer.java @@ -3864,11 +3864,6 @@ public class TestPlayer implements Player { computerPlayer.setLoseByZeroOrLessLife(loseByZeroOrLessLife); } - @Override - public boolean canPlayCardsFromGraveyard() { - return computerPlayer.canPlayCardsFromGraveyard(); - } - @Override public boolean canPlotFromTopOfLibrary() { return computerPlayer.canPlotFromTopOfLibrary(); @@ -3904,11 +3899,6 @@ public class TestPlayer implements Player { computerPlayer.setPayManaMode(payManaMode); } - @Override - public void setPlayCardsFromGraveyard(boolean playCardsFromGraveyard) { - computerPlayer.setPlayCardsFromGraveyard(playCardsFromGraveyard); - } - @Override public boolean autoLoseGame() { return computerPlayer.autoLoseGame(); diff --git a/Mage/src/main/java/mage/abilities/effects/common/asthought/PlayFromNotOwnHandZoneAllEffect.java b/Mage/src/main/java/mage/abilities/effects/common/asthought/PlayFromNotOwnHandZoneAllEffect.java index d5476db5e81..3b2dc907ce9 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/asthought/PlayFromNotOwnHandZoneAllEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/asthought/PlayFromNotOwnHandZoneAllEffect.java @@ -20,6 +20,7 @@ public class PlayFromNotOwnHandZoneAllEffect extends AsThoughEffectImpl { private final boolean onlyOwnedCards; private final TargetController allowedCaster; + @Deprecated // Only used in some tests - should be refactored and removed public PlayFromNotOwnHandZoneAllEffect(FilterCard filter, Zone fromZone, boolean onlyOwnedCards, TargetController allowedCaster, Duration duration) { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, duration, Outcome.Benefit); this.filter = filter; diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayFromGraveyardControllerEffect.java similarity index 51% rename from Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java rename to Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayFromGraveyardControllerEffect.java index 873c3272488..3cd6d1a22c7 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayFromGraveyardControllerEffect.java @@ -15,23 +15,58 @@ import mage.players.Player; import java.util.UUID; /** - * @author JayDi85 + * @author JayDi85, xenohedron */ -public class PlayLandsFromGraveyardControllerEffect extends AsThoughEffectImpl { +public class PlayFromGraveyardControllerEffect extends AsThoughEffectImpl { + + private static final FilterCard filterPlayLands = new FilterLandCard("lands"); + private static final FilterCard filterPlayCast = new FilterCard("play lands and cast spells"); private final FilterCard filter; - public PlayLandsFromGraveyardControllerEffect() { - this(new FilterLandCard("lands")); + /** + * You may play lands from your graveyard. + */ + public static PlayFromGraveyardControllerEffect playLands() { + return new PlayFromGraveyardControllerEffect(filterPlayLands); } - public PlayLandsFromGraveyardControllerEffect(FilterCard filter) { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); + /** + * You may play lands and cast spells from your graveyard. + */ + public static PlayFromGraveyardControllerEffect playLandsAndCastSpells(Duration duration) { + return new PlayFromGraveyardControllerEffect(filterPlayCast, duration); + } + + /** + * You may [play/cast xxx] from your graveyard. + */ + public PlayFromGraveyardControllerEffect(FilterCard filter) { + this(filter, Duration.WhileOnBattlefield); + } + + /** + * [Until duration,] you may [play/cast xxx] from your graveyard. + */ + public PlayFromGraveyardControllerEffect(FilterCard filter, Duration duration) { + super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, duration, Outcome.Benefit); this.filter = filter; - this.staticText = "You may play " + filter.getMessage() + " from your graveyard"; + String filterMessage = filter.getMessage(); + if (!filterMessage.startsWith("play ") && !filterMessage.startsWith("cast")) { + if (filterMessage.contains("lands")) { + filterMessage = "play " + filterMessage; + } else { + filterMessage = "cast " + filterMessage; + } + } + String durationString = duration.toString(); + if (!durationString.isEmpty()) { + durationString += ", "; + } + this.staticText = durationString + "you may " + filterMessage + " from your graveyard"; } - protected PlayLandsFromGraveyardControllerEffect(final PlayLandsFromGraveyardControllerEffect effect) { + protected PlayFromGraveyardControllerEffect(final PlayFromGraveyardControllerEffect effect) { super(effect); this.filter = effect.filter; } @@ -41,16 +76,16 @@ public class PlayLandsFromGraveyardControllerEffect extends AsThoughEffectImpl { return true; } - @Override - public PlayLandsFromGraveyardControllerEffect copy() { - return new PlayLandsFromGraveyardControllerEffect(this); + public PlayFromGraveyardControllerEffect copy() { + return new PlayFromGraveyardControllerEffect(this); } @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { throw new IllegalArgumentException("Wrong code usage: can't call applies method on empty affectedAbility"); } + @Override public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) { // current card's part @@ -80,7 +115,7 @@ public class PlayLandsFromGraveyardControllerEffect extends AsThoughEffectImpl { if (!cardToCheck.isLand(game) && cardToCheck.getManaCost().isEmpty()) { return false; } - if (affectedAbility instanceof SpellAbility){ + if (affectedAbility instanceof SpellAbility) { cardToCheck = ((SpellAbility) affectedAbility).getCharacteristics(game); } // must be correct card diff --git a/Mage/src/main/java/mage/game/command/emblems/WrennAndRealmbreakerEmblem.java b/Mage/src/main/java/mage/game/command/emblems/WrennAndRealmbreakerEmblem.java index 6d53bd0fa4a..13eff45ec55 100644 --- a/Mage/src/main/java/mage/game/command/emblems/WrennAndRealmbreakerEmblem.java +++ b/Mage/src/main/java/mage/game/command/emblems/WrennAndRealmbreakerEmblem.java @@ -1,27 +1,22 @@ package mage.game.command.emblems; -import mage.abilities.Ability; import mage.abilities.common.SimpleStaticAbility; -import mage.abilities.effects.AsThoughEffectImpl; -import mage.cards.Card; -import mage.constants.AsThoughEffectType; -import mage.constants.Duration; -import mage.constants.Outcome; +import mage.abilities.effects.common.ruleModifying.PlayFromGraveyardControllerEffect; import mage.constants.Zone; -import mage.game.Game; +import mage.filter.common.FilterPermanentCard; import mage.game.command.Emblem; -import java.util.UUID; - /** * @author TheElk801 */ public final class WrennAndRealmbreakerEmblem extends Emblem { + private static final FilterPermanentCard filter = new FilterPermanentCard("play lands and cast permanent spells"); + // -7: You get an emblem with "You may play lands and cast permanent spells from your graveyard." public WrennAndRealmbreakerEmblem() { super("Emblem Wrenn"); - this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new WrennAndRealmbreakerEmblemEffect())); + this.getAbilities().add(new SimpleStaticAbility(Zone.COMMAND, new PlayFromGraveyardControllerEffect(filter))); } private WrennAndRealmbreakerEmblem(final WrennAndRealmbreakerEmblem card) { @@ -33,37 +28,3 @@ public final class WrennAndRealmbreakerEmblem extends Emblem { return new WrennAndRealmbreakerEmblem(this); } } - -class WrennAndRealmbreakerEmblemEffect extends AsThoughEffectImpl { - - public WrennAndRealmbreakerEmblemEffect() { - super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); - staticText = "you may play lands and cast permanent spells from your graveyard"; - } - - protected WrennAndRealmbreakerEmblemEffect(final WrennAndRealmbreakerEmblemEffect effect) { - super(effect); - } - - @Override - public boolean apply(Game game, Ability source) { - return true; - } - - @Override - public WrennAndRealmbreakerEmblemEffect copy() { - return new WrennAndRealmbreakerEmblemEffect(this); - } - - @Override - public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - if (!source.isControlledBy(affectedControllerId)) { - return false; - } - Card card = game.getCard(objectId); - return card != null - && card.isPermanent(game) - && card.isOwnedBy(source.getControllerId()) - && game.getState().getZone(objectId) == Zone.GRAVEYARD; - } -} diff --git a/Mage/src/main/java/mage/players/Player.java b/Mage/src/main/java/mage/players/Player.java index b147806a0e3..97ca015e5c1 100644 --- a/Mage/src/main/java/mage/players/Player.java +++ b/Mage/src/main/java/mage/players/Player.java @@ -196,10 +196,6 @@ public interface Player extends MageItem, Copyable { boolean canLoseByZeroOrLessLife(); - void setPlayCardsFromGraveyard(boolean playCardsFromGraveyard); - - boolean canPlayCardsFromGraveyard(); - void setPlotFromTopOfLibrary(boolean canPlotFromTopOfLibrary); boolean canPlotFromTopOfLibrary(); diff --git a/Mage/src/main/java/mage/players/PlayerImpl.java b/Mage/src/main/java/mage/players/PlayerImpl.java index 1e4628f2e34..4492b47d95a 100644 --- a/Mage/src/main/java/mage/players/PlayerImpl.java +++ b/Mage/src/main/java/mage/players/PlayerImpl.java @@ -152,7 +152,6 @@ public abstract class PlayerImpl implements Player, Serializable { protected boolean canLoseLife = true; protected PayLifeCostLevel payLifeCostLevel = PayLifeCostLevel.allAbilities; protected boolean loseByZeroOrLessLife = true; - protected boolean canPlayCardsFromGraveyard = true; protected boolean canPlotFromTopOfLibrary = false; protected boolean drawsFromBottom = false; protected boolean drawsOnOpponentsTurn = false; @@ -252,7 +251,6 @@ public abstract class PlayerImpl implements Player, Serializable { this.canGainLife = player.canGainLife; this.canLoseLife = player.canLoseLife; this.loseByZeroOrLessLife = player.loseByZeroOrLessLife; - this.canPlayCardsFromGraveyard = player.canPlayCardsFromGraveyard; this.canPlotFromTopOfLibrary = player.canPlotFromTopOfLibrary; this.drawsFromBottom = player.drawsFromBottom; this.drawsOnOpponentsTurn = player.drawsOnOpponentsTurn; @@ -367,7 +365,6 @@ public abstract class PlayerImpl implements Player, Serializable { this.sacrificeCostFilter = player.getSacrificeCostFilter() != null ? player.getSacrificeCostFilter().copy() : null; this.loseByZeroOrLessLife = player.canLoseByZeroOrLessLife(); - this.canPlayCardsFromGraveyard = player.canPlayCardsFromGraveyard(); this.canPlotFromTopOfLibrary = player.canPlotFromTopOfLibrary(); this.drawsFromBottom = player.isDrawsFromBottom(); this.drawsOnOpponentsTurn = player.isDrawsOnOpponentsTurn(); @@ -482,7 +479,6 @@ public abstract class PlayerImpl implements Player, Serializable { this.canLoseLife = true; this.payLifeCostLevel = PayLifeCostLevel.allAbilities; this.loseByZeroOrLessLife = true; - this.canPlayCardsFromGraveyard = true; this.canPlotFromTopOfLibrary = false; this.drawsFromBottom = false; this.drawsOnOpponentsTurn = false; @@ -526,7 +522,6 @@ public abstract class PlayerImpl implements Player, Serializable { this.payLifeCostLevel = PayLifeCostLevel.allAbilities; this.sacrificeCostFilter = null; this.loseByZeroOrLessLife = true; - this.canPlayCardsFromGraveyard = false; this.canPlotFromTopOfLibrary = false; this.drawsFromBottom = false; this.drawsOnOpponentsTurn = false; @@ -4138,9 +4133,7 @@ public abstract class PlayerImpl implements Player, Serializable { approvingObjects = new HashSet<>(); } - boolean canActivateAsHandZone = !approvingObjects.isEmpty() - || (fromZone == Zone.GRAVEYARD && canPlayCardsFromGraveyard()); - boolean possibleToPlay = canActivateAsHandZone + boolean possibleToPlay = !approvingObjects.isEmpty() && ability.getZone().match(Zone.HAND) && (isPlaySpell || isPlayLand); @@ -4164,7 +4157,7 @@ public abstract class PlayerImpl implements Player, Serializable { } // from non hand mode (with affected controller) - if (canActivateAsHandZone && ability.getControllerId() != this.getId()) { + if (!approvingObjects.isEmpty() && ability.getControllerId() != this.getId()) { UUID savedControllerId = ability.getControllerId(); ability.setControllerId(this.getId()); try { @@ -4646,16 +4639,6 @@ public abstract class PlayerImpl implements Player, Serializable { this.loseByZeroOrLessLife = loseByZeroOrLessLife; } - @Override - public boolean canPlayCardsFromGraveyard() { - return canPlayCardsFromGraveyard; - } - - @Override - public void setPlayCardsFromGraveyard(boolean playCardsFromGraveyard) { - this.canPlayCardsFromGraveyard = playCardsFromGraveyard; - } - @Override public boolean canPlotFromTopOfLibrary() { return canPlotFromTopOfLibrary;