diff --git a/Mage.Sets/src/mage/cards/b/BolassCitadel.java b/Mage.Sets/src/mage/cards/b/BolassCitadel.java index a3f56f3094f..bfe9fe96e3b 100644 --- a/Mage.Sets/src/mage/cards/b/BolassCitadel.java +++ b/Mage.Sets/src/mage/cards/b/BolassCitadel.java @@ -11,16 +11,16 @@ import mage.abilities.costs.common.TapSourceCost; import mage.abilities.effects.AsThoughEffectImpl; import mage.abilities.effects.common.LoseLifeOpponentsEffect; import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect; -import mage.cards.*; +import mage.cards.Card; +import mage.cards.CardImpl; +import mage.cards.CardSetInfo; import mage.constants.*; import mage.filter.common.FilterControlledPermanent; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.players.Player; import mage.target.common.TargetControlledPermanent; -import mage.util.CardUtil; -import java.util.Objects; import java.util.UUID; @@ -89,69 +89,37 @@ class BolassCitadelPlayTheTopCardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - return applies(objectId, null, source, game, affectedControllerId); - } - - @Override - public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) { - if (!Objects.equals(source.getControllerId(), playerId)) { + // current card's part + Card cardToCheck = game.getCard(objectId); + if (cardToCheck == null) { return false; } - Player player = game.getPlayer(playerId); - if (player != null) { - Card topCard = player.getLibrary().getFromTop(game); - UUID objectIdToCast = CardUtil.getMainCardId(game, objectId); // for adventure cards - if (topCard == null || !topCard.getId().equals(objectIdToCast)) { - return false; - } - - if (topCard instanceof SplitCard || topCard instanceof ModalDoubleFacesCard) { - // double faces cards - Card card1; - Card card2; - if (topCard instanceof SplitCard) { - card1 = ((SplitCard) topCard).getLeftHalfCard(); - card2 = ((SplitCard) topCard).getRightHalfCard(); - } else { - card1 = ((ModalDoubleFacesCard) topCard).getLeftHalfCard(); - card2 = ((ModalDoubleFacesCard) topCard).getRightHalfCard(); - } - - // left - if (!card1.isLand()) { - PayLifeCost lifeCost = new PayLifeCost(card1.getSpellAbility().getManaCosts().convertedManaCost()); - Costs newCosts = new CostsImpl(); - newCosts.add(lifeCost); - newCosts.addAll(card1.getSpellAbility().getCosts()); - player.setCastSourceIdWithAlternateMana(card1.getId(), null, newCosts); - } - - // right - if (!card2.isLand()) { - PayLifeCost lifeCost = new PayLifeCost(card2.getSpellAbility().getManaCosts().convertedManaCost()); - Costs newCosts = new CostsImpl(); - newCosts.add(lifeCost); - newCosts.addAll(card2.getSpellAbility().getCosts()); - player.setCastSourceIdWithAlternateMana(card2.getId(), null, newCosts); - } - } else { - // other single face cards - if (!topCard.isLand()) { - if (affectedAbility == null) { - affectedAbility = topCard.getSpellAbility(); - } else { - objectIdToCast = affectedAbility.getSourceId(); - } - PayLifeCost cost = new PayLifeCost(affectedAbility.getManaCosts().convertedManaCost()); - Costs costs = new CostsImpl(); - costs.add(cost); - costs.addAll(affectedAbility.getCosts()); - player.setCastSourceIdWithAlternateMana(objectIdToCast, null, costs); - } - } - return true; + // must be you + if (!affectedControllerId.equals(source.getControllerId())) { + return false; } - return false; + + // must be your card + Player player = game.getPlayer(cardToCheck.getOwnerId()); + if (player == null) { + return false; + } + + // must be from your library + Card topCard = player.getLibrary().getFromTop(game); + if (topCard == null || !topCard.getId().equals(cardToCheck.getMainCard().getId())) { + return false; + } + + // allows to play/cast with alternative life cost + if (!cardToCheck.isLand()) { + PayLifeCost lifeCost = new PayLifeCost(cardToCheck.getSpellAbility().getManaCosts().convertedManaCost()); + Costs newCosts = new CostsImpl(); + newCosts.add(lifeCost); + newCosts.addAll(cardToCheck.getSpellAbility().getCosts()); + player.setCastSourceIdWithAlternateMana(cardToCheck.getId(), null, newCosts); + } + return true; } } diff --git a/Mage.Sets/src/mage/cards/c/ConspicuousSnoop.java b/Mage.Sets/src/mage/cards/c/ConspicuousSnoop.java index 1edb15357c2..a3ef5dfbb94 100644 --- a/Mage.Sets/src/mage/cards/c/ConspicuousSnoop.java +++ b/Mage.Sets/src/mage/cards/c/ConspicuousSnoop.java @@ -14,7 +14,6 @@ import mage.filter.FilterCard; import java.util.UUID; /** - * * @author htrajan */ public final class ConspicuousSnoop extends CardImpl { @@ -27,7 +26,7 @@ public final class ConspicuousSnoop extends CardImpl { public ConspicuousSnoop(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{R}{R}"); - + this.subtype.add(SubType.GOBLIN); this.subtype.add(SubType.ROGUE); this.power = new MageInt(2); @@ -37,7 +36,7 @@ public final class ConspicuousSnoop extends CardImpl { this.addAbility(new SimpleStaticAbility(new PlayWithTheTopCardRevealedEffect())); // You may cast Goblin spells from the top of your library. - this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter))); + this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false))); // As long as the top card of your library is a Goblin card, Conspicuous Snoop has all activated abilities of that card. this.addAbility(new SimpleStaticAbility(new GainActivatedAbilitiesOfTopCardEffect(filter.copy().withMessage("a Goblin card")))); diff --git a/Mage.Sets/src/mage/cards/c/CourserOfKruphix.java b/Mage.Sets/src/mage/cards/c/CourserOfKruphix.java index 2dcbcb047f0..3dd49b34446 100644 --- a/Mage.Sets/src/mage/cards/c/CourserOfKruphix.java +++ b/Mage.Sets/src/mage/cards/c/CourserOfKruphix.java @@ -21,7 +21,7 @@ import java.util.UUID; */ public final class CourserOfKruphix extends CardImpl { - private static final FilterCard filter = new FilterLandCard("play land cards"); + private static final FilterCard filter = new FilterLandCard("play lands"); public CourserOfKruphix(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "{1}{G}{G}"); @@ -33,8 +33,8 @@ public final class CourserOfKruphix extends CardImpl { // Play with the top card of your library revealed. this.addAbility(new SimpleStaticAbility(new PlayWithTheTopCardRevealedEffect())); - // You may play the top card of your library if it's a land card. - this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter))); + // You may play lands from the top of your library. + this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false))); // Whenever a land enters the battlefield under your control, you gain 1 life. this.addAbility(new EntersBattlefieldControlledTriggeredAbility(new GainLifeEffect(1), StaticFilters.FILTER_LAND_A)); diff --git a/Mage.Sets/src/mage/cards/c/CrucibleOfWorlds.java b/Mage.Sets/src/mage/cards/c/CrucibleOfWorlds.java index f140d47247f..e084861b33c 100644 --- a/Mage.Sets/src/mage/cards/c/CrucibleOfWorlds.java +++ b/Mage.Sets/src/mage/cards/c/CrucibleOfWorlds.java @@ -17,7 +17,7 @@ public final class CrucibleOfWorlds extends CardImpl { public CrucibleOfWorlds(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}"); - // You may play land cards from your graveyard. + // You may play lands from your graveyard. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayLandsFromGraveyardControllerEffect())); } diff --git a/Mage.Sets/src/mage/cards/e/ElshaOfTheInfinite.java b/Mage.Sets/src/mage/cards/e/ElshaOfTheInfinite.java index 5d4f9255c2d..c86f167b62f 100644 --- a/Mage.Sets/src/mage/cards/e/ElshaOfTheInfinite.java +++ b/Mage.Sets/src/mage/cards/e/ElshaOfTheInfinite.java @@ -45,8 +45,8 @@ public final class ElshaOfTheInfinite extends CardImpl { // You may look at the top card of your library any time. this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); - // You may cast the top card of your library if it's a noncreature, nonland card, and you may cast it as though it had flash. - Ability ability = new SimpleStaticAbility(new PlayTheTopCardEffect(filter)); + // You may cast noncreature spells from the top of your library. If you cast a spell this way, you may cast it as though it had flash. + Ability ability = new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false)); ability.addEffect(new CastAsThoughItHadFlashAllEffect( Duration.WhileOnBattlefield, filter ).setText("If you cast a spell this way, you may cast it as though it had flash.")); diff --git a/Mage.Sets/src/mage/cards/e/ExperimentalFrenzy.java b/Mage.Sets/src/mage/cards/e/ExperimentalFrenzy.java index e4d6d07d259..c376398c33f 100644 --- a/Mage.Sets/src/mage/cards/e/ExperimentalFrenzy.java +++ b/Mage.Sets/src/mage/cards/e/ExperimentalFrenzy.java @@ -30,7 +30,7 @@ public final class ExperimentalFrenzy extends CardImpl { // You may look at the top card of your library any time. this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); - // You may play the top card of your library. + // You may play lands and cast spells from the top of your library. this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect())); // You can't play cards from your hand. diff --git a/Mage.Sets/src/mage/cards/f/FutureSight.java b/Mage.Sets/src/mage/cards/f/FutureSight.java index 88d4a826e2b..b8427292165 100644 --- a/Mage.Sets/src/mage/cards/f/FutureSight.java +++ b/Mage.Sets/src/mage/cards/f/FutureSight.java @@ -1,7 +1,5 @@ - package mage.cards.f; -import java.util.UUID; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.PlayTheTopCardEffect; import mage.abilities.effects.common.continuous.PlayWithTheTopCardRevealedEffect; @@ -10,18 +8,20 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author Plopman */ public final class FutureSight extends CardImpl { public FutureSight(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.ENCHANTMENT},"{2}{U}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{2}{U}{U}{U}"); // Play with the top card of your library revealed. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayWithTheTopCardRevealedEffect())); - // You may play the top card of your library. + + // You may play lands and cast spells from the top of your library. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect())); } diff --git a/Mage.Sets/src/mage/cards/g/GarruksHorde.java b/Mage.Sets/src/mage/cards/g/GarruksHorde.java index a8513fe25fa..37cb6954913 100644 --- a/Mage.Sets/src/mage/cards/g/GarruksHorde.java +++ b/Mage.Sets/src/mage/cards/g/GarruksHorde.java @@ -34,8 +34,8 @@ public final class GarruksHorde extends CardImpl { // Play with the top card of your library revealed. this.addAbility(new SimpleStaticAbility(new PlayWithTheTopCardRevealedEffect())); - // You may cast the top card of your library if it's a creature card. - this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter))); + // You may cast creature spells from the top of your library. + this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false))); } private GarruksHorde(final GarruksHorde card) { diff --git a/Mage.Sets/src/mage/cards/m/MagusOfTheFuture.java b/Mage.Sets/src/mage/cards/m/MagusOfTheFuture.java index 31ad2a0d674..f03135109c7 100644 --- a/Mage.Sets/src/mage/cards/m/MagusOfTheFuture.java +++ b/Mage.Sets/src/mage/cards/m/MagusOfTheFuture.java @@ -1,7 +1,5 @@ - package mage.cards.m; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.SimpleStaticAbility; import mage.abilities.effects.common.continuous.PlayTheTopCardEffect; @@ -12,14 +10,15 @@ import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import java.util.UUID; + /** - * * @author emerald000 */ public final class MagusOfTheFuture extends CardImpl { public MagusOfTheFuture(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"{2}{U}{U}{U}"); + super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}{U}{U}"); this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.WIZARD); @@ -29,7 +28,7 @@ public final class MagusOfTheFuture extends CardImpl { // Play with the top card of your library revealed. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayWithTheTopCardRevealedEffect())); - // You may play the top card of your library. + // You may play lands and cast spells from the top of your library. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect())); } diff --git a/Mage.Sets/src/mage/cards/m/MelekIzzetParagon.java b/Mage.Sets/src/mage/cards/m/MelekIzzetParagon.java index 07c81b9ea16..40a46a08f3f 100644 --- a/Mage.Sets/src/mage/cards/m/MelekIzzetParagon.java +++ b/Mage.Sets/src/mage/cards/m/MelekIzzetParagon.java @@ -17,7 +17,6 @@ import mage.filter.FilterCard; import mage.filter.predicate.Predicates; import mage.game.Game; import mage.game.events.GameEvent; -import mage.game.events.GameEvent.EventType; import mage.game.stack.Spell; import mage.target.targetpointer.FixedTarget; @@ -49,8 +48,8 @@ public final class MelekIzzetParagon extends CardImpl { // Play with the top card of your library revealed. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayWithTheTopCardRevealedEffect())); - // You may cast the top card of your library if it's an instant or sorcery card. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect(filter))); + // You may cast instant and sorcery spells from the top of your library. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect(filter, false))); // Whenever you cast an instant or sorcery spell from your library, copy it. You may choose new targets for the copy. this.addAbility(new MelekIzzetParagonTriggeredAbility()); diff --git a/Mage.Sets/src/mage/cards/m/Mutilate.java b/Mage.Sets/src/mage/cards/m/Mutilate.java index 03e33ae231a..c13bcd64cbf 100644 --- a/Mage.Sets/src/mage/cards/m/Mutilate.java +++ b/Mage.Sets/src/mage/cards/m/Mutilate.java @@ -1,9 +1,6 @@ - package mage.cards.m; -import java.util.UUID; import mage.abilities.dynamicvalue.common.PermanentsOnBattlefieldCount; -import mage.abilities.effects.ContinuousEffect; import mage.abilities.effects.common.continuous.BoostAllEffect; import mage.cards.CardImpl; import mage.cards.CardSetInfo; @@ -14,9 +11,10 @@ import mage.constants.TargetController; import mage.filter.StaticFilters; import mage.filter.common.FilterLandPermanent; +import java.util.UUID; + /** - * * @author North */ public final class Mutilate extends CardImpl { @@ -31,14 +29,15 @@ public final class Mutilate extends CardImpl { } public Mutilate(UUID ownerId, CardSetInfo setInfo) { - super(ownerId,setInfo,new CardType[]{CardType.SORCERY},"{2}{B}{B}"); + super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{B}{B}"); // All creatures get -1/-1 until end of turn for each Swamp you control. PermanentsOnBattlefieldCount count = new PermanentsOnBattlefieldCount(filter, -1); - ContinuousEffect effect = new BoostAllEffect(count, count, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES, false, null, true); - effect.overrideRuleText(ruleText); - this.getSpellAbility().addEffect(effect); + this.getSpellAbility().addEffect( + new BoostAllEffect(count, count, Duration.EndOfTurn, StaticFilters.FILTER_PERMANENT_CREATURES, false, null, true) + .setText(ruleText) + ); } private Mutilate(final Mutilate card) { diff --git a/Mage.Sets/src/mage/cards/m/MysticForge.java b/Mage.Sets/src/mage/cards/m/MysticForge.java index 2cfee980edd..1975c5d34b5 100644 --- a/Mage.Sets/src/mage/cards/m/MysticForge.java +++ b/Mage.Sets/src/mage/cards/m/MysticForge.java @@ -43,7 +43,7 @@ public final class MysticForge extends CardImpl { this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); // You may cast artifact spells and colorless spells from the top of your library. - this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter))); + this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false))); // {T}, Pay 1 life: Exile the top card of your library. Ability ability = new SimpleActivatedAbility(new MysticForgeExileEffect(), new TapSourceCost()); diff --git a/Mage.Sets/src/mage/cards/o/OracleOfMulDaya.java b/Mage.Sets/src/mage/cards/o/OracleOfMulDaya.java index dcebbc1b061..3e077c7696a 100644 --- a/Mage.Sets/src/mage/cards/o/OracleOfMulDaya.java +++ b/Mage.Sets/src/mage/cards/o/OracleOfMulDaya.java @@ -20,7 +20,7 @@ import java.util.UUID; */ public final class OracleOfMulDaya extends CardImpl { - private static final FilterCard filter = new FilterLandCard("play land cards"); + private static final FilterCard filter = new FilterLandCard("play lands"); public OracleOfMulDaya(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{G}"); @@ -38,8 +38,8 @@ public final class OracleOfMulDaya extends CardImpl { // Play with the top card of your library revealed. this.addAbility(new SimpleStaticAbility(new PlayWithTheTopCardRevealedEffect())); - // You may play the top card of your library if it's a land card. - this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter))); + // You may play lands from the top of your library. + this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false))); } private OracleOfMulDaya(final OracleOfMulDaya card) { diff --git a/Mage.Sets/src/mage/cards/p/PrecognitionField.java b/Mage.Sets/src/mage/cards/p/PrecognitionField.java index 9d5b8e1a6e3..3f9ac0ef0db 100644 --- a/Mage.Sets/src/mage/cards/p/PrecognitionField.java +++ b/Mage.Sets/src/mage/cards/p/PrecognitionField.java @@ -40,8 +40,8 @@ public final class PrecognitionField extends CardImpl { // You may look at the top card of your library. this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); - // You may cast the top card of your library if it's an instant or sorcery card. - this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter))); + // You may cast instant and sorcery spells from the top of your library. + this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false))); // {3}: Exile the top card of your library. this.addAbility(new SimpleActivatedAbility(new PrecognitionFieldExileEffect(), new GenericManaCost(3))); diff --git a/Mage.Sets/src/mage/cards/r/RadhaHeartOfKeld.java b/Mage.Sets/src/mage/cards/r/RadhaHeartOfKeld.java index adaecbd2615..912e8e00233 100644 --- a/Mage.Sets/src/mage/cards/r/RadhaHeartOfKeld.java +++ b/Mage.Sets/src/mage/cards/r/RadhaHeartOfKeld.java @@ -31,7 +31,7 @@ import java.util.UUID; */ public final class RadhaHeartOfKeld extends CardImpl { - private static final FilterCard filter = new FilterLandCard("play land cards"); + private static final FilterCard filter = new FilterLandCard("play lands"); public RadhaHeartOfKeld(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{R}{G}"); @@ -50,9 +50,9 @@ public final class RadhaHeartOfKeld extends CardImpl { // You may look at the top card of your library any time, and you may play lands from the top of your library. LookAtTopCardOfLibraryAnyTimeEffect lookEffect = new LookAtTopCardOfLibraryAnyTimeEffect(); - lookEffect.overrideRuleText("You may look at the top card of your library any time"); - PlayTheTopCardEffect playEffect = new PlayTheTopCardEffect(filter); - playEffect.overrideRuleText(", and you may play lands from the top of your library"); + lookEffect.setText("You may look at the top card of your library any time"); + PlayTheTopCardEffect playEffect = new PlayTheTopCardEffect(filter, false); + playEffect.setText(", and you may play lands from the top of your library"); SimpleStaticAbility lookAndPlayAbility = new SimpleStaticAbility(lookEffect); lookAndPlayAbility.addEffect(playEffect); @@ -61,7 +61,7 @@ public final class RadhaHeartOfKeld extends CardImpl { // 4RG: Radha gets +X/+X until end of turn, where X is the number of lands you control. DynamicValue controlledLands = new PermanentsOnBattlefieldCount(StaticFilters.FILTER_CONTROLLED_PERMANENT_LANDS); BoostSourceEffect bse = new BoostSourceEffect(controlledLands, controlledLands, Duration.EndOfTurn, true); - bse.overrideRuleText("Radha gets +X/+X until end of turn, where X is the number of lands you control"); + bse.setText("Radha gets +X/+X until end of turn, where X is the number of lands you control"); this.addAbility(new SimpleActivatedAbility(bse, new ManaCostsImpl("{4}{R}{G}"))); } diff --git a/Mage.Sets/src/mage/cards/r/RamunapExcavator.java b/Mage.Sets/src/mage/cards/r/RamunapExcavator.java index 2de1ddf71e1..26096ba53c5 100644 --- a/Mage.Sets/src/mage/cards/r/RamunapExcavator.java +++ b/Mage.Sets/src/mage/cards/r/RamunapExcavator.java @@ -24,7 +24,7 @@ public final class RamunapExcavator extends CardImpl { this.power = new MageInt(2); this.toughness = new MageInt(3); - // You may play land cards from your graveyard. + // You may play lands from your graveyard. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayLandsFromGraveyardControllerEffect())); } diff --git a/Mage.Sets/src/mage/cards/r/Realmwalker.java b/Mage.Sets/src/mage/cards/r/Realmwalker.java index b08dc1ac26d..6f57551358f 100644 --- a/Mage.Sets/src/mage/cards/r/Realmwalker.java +++ b/Mage.Sets/src/mage/cards/r/Realmwalker.java @@ -1,6 +1,5 @@ package mage.cards.r; -import java.util.UUID; import mage.MageInt; import mage.abilities.common.AsEntersBattlefieldAbility; import mage.abilities.common.SimpleStaticAbility; @@ -16,13 +15,15 @@ import mage.constants.SubType; import mage.filter.common.FilterCreatureCard; import mage.filter.predicate.mageobject.ChosenSubtypePredicate; +import java.util.UUID; + /** - * * @author weirddan455 */ public final class Realmwalker extends CardImpl { private static final FilterCreatureCard filter = new FilterCreatureCard("cast creature spells of the chosen type"); + static { filter.add(ChosenSubtypePredicate.TRUE); } @@ -44,7 +45,7 @@ public final class Realmwalker extends CardImpl { this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); // You may cast creature spells of the chosen type from the top of your library. - this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter))); + this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false))); } private Realmwalker(final Realmwalker card) { diff --git a/Mage.Sets/src/mage/cards/v/VergeRangers.java b/Mage.Sets/src/mage/cards/v/VergeRangers.java index f4b9228294b..37743c747d0 100644 --- a/Mage.Sets/src/mage/cards/v/VergeRangers.java +++ b/Mage.Sets/src/mage/cards/v/VergeRangers.java @@ -11,21 +11,22 @@ import mage.cards.CardSetInfo; import mage.constants.CardType; import mage.constants.SubType; import mage.constants.Zone; +import mage.filter.FilterCard; import mage.filter.StaticFilters; +import mage.filter.common.FilterLandCard; import mage.game.Game; import java.util.Comparator; import java.util.UUID; /** - * * @author htrajan */ public final class VergeRangers extends CardImpl { public VergeRangers(UUID ownerId, CardSetInfo setInfo) { super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{W}"); - + this.subtype.add(SubType.HUMAN); this.subtype.add(SubType.SCOUT); this.power = new MageInt(3); @@ -53,9 +54,11 @@ public final class VergeRangers extends CardImpl { class VergeRangersEffect extends PlayTheTopCardEffect { + private static final FilterCard filter = new FilterLandCard("play lands"); + public VergeRangersEffect() { - super(StaticFilters.FILTER_CARD_LAND); - staticText = "As long as an opponent controls more lands than you, you may play lands from the top of your library."; + super(filter, false); + staticText = "As long as an opponent controls more lands than you, you may play lands from the top of your library"; } public VergeRangersEffect(final VergeRangersEffect effect) { @@ -68,15 +71,16 @@ class VergeRangersEffect extends PlayTheTopCardEffect { } @Override - public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) { - if (super.applies(objectId, affectedAbility, source, game, playerId)) { - int myLandCount = game.getBattlefield().countAll(StaticFilters.FILTER_LAND, playerId, game); - int maxOpponentLandCount = game.getOpponents(playerId).stream() - .map(opponentId -> game.getBattlefield().countAll(StaticFilters.FILTER_LAND, opponentId, game)) - .max(Comparator.naturalOrder()) - .orElse(0); - return maxOpponentLandCount > myLandCount; + public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { + if (!super.applies(objectId, source, affectedControllerId, game)) { + return false; } - return false; + + int myLandCount = game.getBattlefield().countAll(StaticFilters.FILTER_LAND, source.getControllerId(), game); + int maxOpponentLandCount = game.getOpponents(source.getControllerId()).stream() + .map(opponentId -> game.getBattlefield().countAll(StaticFilters.FILTER_LAND, opponentId, game)) + .max(Comparator.naturalOrder()) + .orElse(0); + return maxOpponentLandCount > myLandCount; } } \ No newline at end of file diff --git a/Mage.Sets/src/mage/cards/v/VivienMonstersAdvocate.java b/Mage.Sets/src/mage/cards/v/VivienMonstersAdvocate.java index 959f89dcee3..05c32853046 100644 --- a/Mage.Sets/src/mage/cards/v/VivienMonstersAdvocate.java +++ b/Mage.Sets/src/mage/cards/v/VivienMonstersAdvocate.java @@ -27,6 +27,7 @@ import mage.game.permanent.token.Token; import mage.game.stack.Spell; import mage.players.Player; import mage.target.common.TargetCardInLibrary; + import java.util.Arrays; import java.util.Locale; import java.util.Set; @@ -51,7 +52,7 @@ public final class VivienMonstersAdvocate extends CardImpl { this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect())); // You may cast creature spells from the top of your library. - this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter))); + this.addAbility(new SimpleStaticAbility(new PlayTheTopCardEffect(filter, false))); // +1: Create a 3/3 green Beast creature token. Put your choice of a vigilance // counter, a reach counter, or a trample counter on it. diff --git a/Mage.Sets/src/mage/cards/v/VizierOfTheMenagerie.java b/Mage.Sets/src/mage/cards/v/VizierOfTheMenagerie.java index 440412b6267..7ad95d44d15 100644 --- a/Mage.Sets/src/mage/cards/v/VizierOfTheMenagerie.java +++ b/Mage.Sets/src/mage/cards/v/VizierOfTheMenagerie.java @@ -36,8 +36,8 @@ public final class VizierOfTheMenagerie extends CardImpl { // You may look at the top card of your library. (You may do this at any time.) this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new LookAtTopCardOfLibraryAnyTimeEffect())); - // You may cast the top card of your library if it's a creature card. - this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect(filter))); + // You may cast creature spells from the top of your library. + this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new PlayTheTopCardEffect(filter, false))); // You may spend mana as though it were mana of any type to cast creature spells. this.addAbility(new SimpleStaticAbility(Zone.BATTLEFIELD, new VizierOfTheMenagerieManaEffect())); diff --git a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java index db9cc79df87..47cb9d81237 100644 --- a/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java +++ b/Mage.Tests/src/test/java/org/mage/test/cards/asthough/PlayTopCardFromLibraryTest.java @@ -94,6 +94,7 @@ public class PlayTopCardFromLibraryTest extends CardTestPlayerBase { addCard(Zone.BATTLEFIELD, playerA, "Bolas's Citadel", 1); // Double your life total. Target opponent loses half their life, rounded up. + checkPlayableAbility("playable", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Revenge", true); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Revenge", playerB); // {4}{W}{B} = 6 life setStrictChooseMode(true); @@ -113,6 +114,7 @@ public class PlayTopCardFromLibraryTest extends CardTestPlayerBase { addCard(Zone.GRAVEYARD, playerA, "Balduvian Bears", 1); // Return target creature card with converted mana cost 3 or less from your graveyard to the battlefield. + checkPlayableAbility("playable", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Revival", true); castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Revival", "Balduvian Bears"); // {W/B}{W/B} = 2 life setStrictChooseMode(true); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java index 11a001c5275..77faf553bfb 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffect.java @@ -1,9 +1,5 @@ package mage.abilities.effects; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import java.util.UUID; import mage.MageObjectReference; import mage.abilities.Ability; import mage.constants.DependencyType; @@ -13,6 +9,11 @@ import mage.constants.SubLayer; import mage.game.Game; import mage.target.targetpointer.TargetPointer; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import java.util.UUID; + /** * @author BetaSteward_at_googlemail.com */ @@ -46,8 +47,6 @@ public interface ContinuousEffect extends Effect { SubLayer getSublayer(); - void overrideRuleText(String text); - List getAffectedObjects(); Set isDependentTo(List allEffectsInLayer); diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java index 4558b0496f5..184d24f6589 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffectImpl.java @@ -275,11 +275,6 @@ public abstract class ContinuousEffectImpl extends EffectImpl implements Continu return sublayer; } - @Override - public void overrideRuleText(String text) { - this.staticText = text; - } - protected static boolean isCanKill(DynamicValue toughness) { if (toughness instanceof StaticValue) { return toughness.calculate(null, null, null) < 0; diff --git a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java index 2e4c8d115ed..0708a510c4c 100644 --- a/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java +++ b/Mage/src/main/java/mage/abilities/effects/ContinuousEffects.java @@ -532,7 +532,10 @@ public class ContinuousEffects implements Serializable { } UUID idToCheck; - if (objectToCheck instanceof SplitCardHalf) { + if (!type.needPlayCardAbility() && objectToCheck instanceof SplitCardHalf) { + // each split side uses own characteristics to check for playing, all other cases must use main card + // rules: + // 708.4. In every zone except the stack, the characteristics of a split card are those of its two halves combined. idToCheck = ((SplitCardHalf) objectToCheck).getMainCard().getId(); } else if (!type.needPlayCardAbility() && objectToCheck instanceof AdventureCardSpell) { // adventure spell uses alternative characteristics for spell/stack, all other cases must use main card diff --git a/Mage/src/main/java/mage/abilities/effects/common/continuous/PlayTheTopCardEffect.java b/Mage/src/main/java/mage/abilities/effects/common/continuous/PlayTheTopCardEffect.java index 34b136f26ad..7df1c2071e6 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/continuous/PlayTheTopCardEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/continuous/PlayTheTopCardEffect.java @@ -7,34 +7,44 @@ import mage.constants.AsThoughEffectType; import mage.constants.Duration; import mage.constants.Outcome; import mage.filter.FilterCard; -import mage.filter.StaticFilters; import mage.game.Game; import mage.players.Player; -import mage.util.CardUtil; +import java.util.Locale; import java.util.UUID; /** - * @author nantuko + * @author nantuko, JayDi85 */ public class PlayTheTopCardEffect extends AsThoughEffectImpl { private final FilterCard filter; + // can play card or can play lands/cast spells, see two modes below + private final boolean canPlayCardOnly; + + public PlayTheTopCardEffect() { - this(StaticFilters.FILTER_CARD); - staticText = "You may play lands and cast spells from the top of your library"; + this(new FilterCard("play lands and cast spells"), false); } - public PlayTheTopCardEffect(FilterCard filter) { + public PlayTheTopCardEffect(FilterCard filter, boolean canPlayCardOnly) { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); this.filter = filter; - staticText = "You may " + filter.getMessage() + " from the top of your library"; + this.canPlayCardOnly = canPlayCardOnly; + this.staticText = "You may " + filter.getMessage() + " from the top of your library"; + + // verify check: if you see "card" text in the rules then use card mode + // (there aren't any real cards after oracle update, but can be added in the future) + if (this.canPlayCardOnly != filter.getMessage().toLowerCase(Locale.ENGLISH).contains("card")) { + throw new IllegalArgumentException("Wrong usage of card mode settings"); + } } public PlayTheTopCardEffect(final PlayTheTopCardEffect effect) { super(effect); this.filter = effect.filter; + this.canPlayCardOnly = effect.canPlayCardOnly; } @Override @@ -49,25 +59,45 @@ public class PlayTheTopCardEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - return applies(objectId, null, source, game, affectedControllerId); - } + // main card and all parts are checks in different calls. + // two modes: + // * can play cards (must check main card and allows any parts) + // * can play lands/spells (must check specific part and allows specific part) - @Override - public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) { + // current card's part Card cardToCheck = game.getCard(objectId); - objectId = CardUtil.getMainCardId(game, objectId); // for split cards - - if (cardToCheck != null - && playerId.equals(source.getControllerId()) - && cardToCheck.isOwnedBy(source.getControllerId()) - && (!cardToCheck.getManaCost().isEmpty() || cardToCheck.isLand()) - && filter.match(cardToCheck, source.getSourceId(), source.getControllerId(), game)) { - Player player = game.getPlayer(cardToCheck.getOwnerId()); - - UUID needCardID = player.getLibrary().getFromTop(game) == null ? null : player.getLibrary().getFromTop(game).getId(); - return objectId.equals(needCardID); + if (cardToCheck == null) { + return false; } - return false; - } + if (this.canPlayCardOnly) { + // check whole card intead part + cardToCheck = cardToCheck.getMainCard(); + } + + // must be you + if (!affectedControllerId.equals(source.getControllerId())) { + return false; + } + + // must be your card + Player player = game.getPlayer(cardToCheck.getOwnerId()); + if (player == null) { + return false; + } + + // must be from your library + Card topCard = player.getLibrary().getFromTop(game); + if (topCard == null || !topCard.getId().equals(cardToCheck.getMainCard().getId())) { + return false; + } + + // can't cast without mana cost + if (!cardToCheck.isLand() && cardToCheck.getManaCost().isEmpty()) { + return false; + } + + // must be correct card + return filter.match(cardToCheck, source.getSourceId(), source.getControllerId(), game); + } } diff --git a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java index 4a2eb21a7c6..c6fa6186615 100644 --- a/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java +++ b/Mage/src/main/java/mage/abilities/effects/common/ruleModifying/PlayLandsFromGraveyardControllerEffect.java @@ -10,7 +10,6 @@ import mage.filter.FilterCard; import mage.filter.common.FilterLandCard; import mage.game.Game; import mage.players.Player; -import mage.util.CardUtil; import java.util.UUID; @@ -28,7 +27,7 @@ public class PlayLandsFromGraveyardControllerEffect extends AsThoughEffectImpl { public PlayLandsFromGraveyardControllerEffect(FilterCard filter) { super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.WhileOnBattlefield, Outcome.Benefit); this.filter = filter; - staticText = "You may play " + filter.getMessage() + " from your graveyard"; + this.staticText = "You may play " + filter.getMessage() + " from your graveyard"; } public PlayLandsFromGraveyardControllerEffect(final PlayLandsFromGraveyardControllerEffect effect) { @@ -49,30 +48,35 @@ public class PlayLandsFromGraveyardControllerEffect extends AsThoughEffectImpl { @Override public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) { - return applies(objectId, null, source, game, affectedControllerId); - } - - @Override - public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) { + // current card's part Card cardToCheck = game.getCard(objectId); - objectId = CardUtil.getMainCardId(game, objectId); // for split cards if (cardToCheck == null) { return false; } + // must be you + if (!affectedControllerId.equals(source.getControllerId())) { + return false; + } + + // must be your card Player player = game.getPlayer(cardToCheck.getOwnerId()); if (player == null) { return false; } - UUID needCardId = objectId; + // must be from your graveyard + UUID needCardId = cardToCheck.getMainCard().getId(); if (player.getGraveyard().getCards(game).stream().noneMatch(c -> c.getId().equals(needCardId))) { return false; } - return playerId.equals(source.getControllerId()) - && cardToCheck.isOwnedBy(source.getControllerId()) - && (!cardToCheck.getManaCost().isEmpty() || cardToCheck.isLand()) - && filter.match(cardToCheck, game); + // can't cast without mana cost + if (!cardToCheck.isLand() && cardToCheck.getManaCost().isEmpty()) { + return false; + } + + // must be correct card + return filter.match(cardToCheck, source.getSourceId(), source.getControllerId(), game); } } diff --git a/Mage/src/main/java/mage/abilities/keyword/ProwessAbility.java b/Mage/src/main/java/mage/abilities/keyword/ProwessAbility.java index dd242a70dfc..f3d46f24d4f 100644 --- a/Mage/src/main/java/mage/abilities/keyword/ProwessAbility.java +++ b/Mage/src/main/java/mage/abilities/keyword/ProwessAbility.java @@ -1,5 +1,3 @@ - - package mage.abilities.keyword; import mage.abilities.common.SpellCastControllerTriggeredAbility; @@ -10,20 +8,19 @@ import mage.filter.FilterSpell; import mage.filter.predicate.Predicates; /** - * * @author LevelX2 */ public class ProwessAbility extends SpellCastControllerTriggeredAbility { - private static final FilterSpell filterNonCreatureSpell = new FilterSpell("noncreature spell"); + private static final FilterSpell filterNonCreatureSpell = new FilterSpell("noncreature spell"); static { filterNonCreatureSpell.add(Predicates.not(CardType.CREATURE.getPredicate())); } public ProwessAbility() { - super(new BoostSourceEffect(1,1,Duration.EndOfTurn), false); - this.filter = filterNonCreatureSpell; + super(new BoostSourceEffect(1, 1, Duration.EndOfTurn), false); + this.filter = filterNonCreatureSpell; } public ProwessAbility(final ProwessAbility ability) {