mirror of
https://github.com/correl/mage.git
synced 2024-12-24 03:00:14 +00:00
PlayTheTopCard improves: added correct usage check, fixed outdated rule texts, Bolas's Citadel simplified (related to #7605);
This commit is contained in:
parent
bfe91ad32b
commit
48e9cc3e07
27 changed files with 182 additions and 182 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"))));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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."));
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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}")));
|
||||
}
|
||||
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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()));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<MageObjectReference> getAffectedObjects();
|
||||
|
||||
Set<UUID> isDependentTo(List<ContinuousEffect> allEffectsInLayer);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue