mirror of
https://github.com/correl/mage.git
synced 2024-12-26 03:00:11 +00:00
commit
04f78500eb
51 changed files with 1278 additions and 235 deletions
|
@ -43,16 +43,16 @@ public final class AnimatingFaerie extends AdventureCard {
|
||||||
|
|
||||||
// Bring to Life
|
// Bring to Life
|
||||||
// Target noncreature artifact you control becomes a 0/0 artifact creature. Put four +1/+1 counters on it.
|
// Target noncreature artifact you control becomes a 0/0 artifact creature. Put four +1/+1 counters on it.
|
||||||
this.getAdventureSpellAbility().addEffect(new AddCardTypeTargetEffect(
|
this.getSpellCard().getSpellAbility().addEffect(new AddCardTypeTargetEffect(
|
||||||
Duration.EndOfGame, CardType.ARTIFACT, CardType.CREATURE
|
Duration.EndOfGame, CardType.ARTIFACT, CardType.CREATURE
|
||||||
).setText("Target noncreature artifact you control becomes"));
|
).setText("Target noncreature artifact you control becomes"));
|
||||||
this.getAdventureSpellAbility().addEffect(new SetPowerToughnessTargetEffect(
|
this.getSpellCard().getSpellAbility().addEffect(new SetPowerToughnessTargetEffect(
|
||||||
0, 0, Duration.EndOfGame
|
0, 0, Duration.EndOfGame
|
||||||
).setText("a 0/0 artifact creature."));
|
).setText("a 0/0 artifact creature."));
|
||||||
this.getAdventureSpellAbility().addEffect(new AddCountersTargetEffect(
|
this.getSpellCard().getSpellAbility().addEffect(new AddCountersTargetEffect(
|
||||||
CounterType.P1P1.createInstance(4)
|
CounterType.P1P1.createInstance(4)
|
||||||
).setText("Put four +1/+1 counters on it."));
|
).setText("Put four +1/+1 counters on it."));
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetPermanent(filter));
|
this.getSpellCard().getSpellAbility().addTarget(new TargetPermanent(filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
private AnimatingFaerie(final AnimatingFaerie card) {
|
private AnimatingFaerie(final AnimatingFaerie card) {
|
||||||
|
|
|
@ -29,8 +29,8 @@ public final class ArdenvaleTactician extends AdventureCard {
|
||||||
|
|
||||||
// Dizzying Swoop
|
// Dizzying Swoop
|
||||||
// Tap up to two target creatures.
|
// Tap up to two target creatures.
|
||||||
this.getAdventureSpellAbility().addEffect(new TapTargetEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new TapTargetEffect());
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent(0, 2));
|
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent(0, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArdenvaleTactician(final ArdenvaleTactician card) {
|
private ArdenvaleTactician(final ArdenvaleTactician card) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ public final class BeanstalkGiant extends AdventureCard {
|
||||||
|
|
||||||
// Fertile Footsteps
|
// Fertile Footsteps
|
||||||
// Search your library for a basic land card, put it onto the battlefield, then shuffle your library.
|
// Search your library for a basic land card, put it onto the battlefield, then shuffle your library.
|
||||||
this.getAdventureSpellAbility().addEffect(
|
this.getSpellCard().getSpellAbility().addEffect(
|
||||||
new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND))
|
new SearchLibraryPutInPlayEffect(new TargetCardInLibrary(StaticFilters.FILTER_CARD_BASIC_LAND))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,118 +1,122 @@
|
||||||
package mage.cards.b;
|
package mage.cards.b;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
import mage.abilities.ActivatedAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
import mage.abilities.costs.Costs;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.costs.CostsImpl;
|
import mage.abilities.costs.Costs;
|
||||||
import mage.abilities.costs.common.PayLifeCost;
|
import mage.abilities.costs.CostsImpl;
|
||||||
import mage.abilities.costs.common.SacrificeTargetCost;
|
import mage.abilities.costs.common.PayLifeCost;
|
||||||
import mage.abilities.costs.common.TapSourceCost;
|
import mage.abilities.costs.common.SacrificeTargetCost;
|
||||||
import mage.abilities.effects.AsThoughEffectImpl;
|
import mage.abilities.costs.common.TapSourceCost;
|
||||||
import mage.abilities.effects.common.LoseLifeOpponentsEffect;
|
import mage.abilities.effects.AsThoughEffectImpl;
|
||||||
import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect;
|
import mage.abilities.effects.common.LoseLifeOpponentsEffect;
|
||||||
import mage.cards.Card;
|
import mage.abilities.effects.common.continuous.LookAtTopCardOfLibraryAnyTimeEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardImpl;
|
||||||
import mage.constants.*;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.filter.common.FilterControlledPermanent;
|
import mage.constants.*;
|
||||||
import mage.filter.predicate.Predicates;
|
import mage.filter.common.FilterControlledPermanent;
|
||||||
import mage.filter.predicate.mageobject.CardTypePredicate;
|
import mage.filter.predicate.Predicates;
|
||||||
import mage.game.Game;
|
import mage.filter.predicate.mageobject.CardTypePredicate;
|
||||||
import mage.players.Player;
|
import mage.game.Game;
|
||||||
import mage.target.common.TargetControlledPermanent;
|
import mage.players.Player;
|
||||||
|
import mage.target.common.TargetControlledPermanent;
|
||||||
import java.util.UUID;
|
|
||||||
import mage.abilities.costs.Cost;
|
import java.util.UUID;
|
||||||
|
import mage.abilities.costs.Cost;
|
||||||
/**
|
|
||||||
* @author jeffwadsworth
|
/**
|
||||||
*/
|
* @author jeffwadsworth
|
||||||
public final class BolassCitadel extends CardImpl {
|
*/
|
||||||
|
public final class BolassCitadel extends CardImpl {
|
||||||
private static final FilterControlledPermanent filter = new FilterControlledPermanent("nonland permanents");
|
|
||||||
|
private static final FilterControlledPermanent filter = new FilterControlledPermanent("nonland permanents");
|
||||||
static {
|
|
||||||
filter.add(Predicates.not(new CardTypePredicate(CardType.LAND)));
|
static {
|
||||||
}
|
filter.add(Predicates.not(new CardTypePredicate(CardType.LAND)));
|
||||||
|
}
|
||||||
public BolassCitadel(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{B}{B}{B}");
|
public BolassCitadel(UUID ownerId, CardSetInfo setInfo) {
|
||||||
|
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{3}{B}{B}{B}");
|
||||||
this.addSuperType(SuperType.LEGENDARY);
|
|
||||||
|
this.addSuperType(SuperType.LEGENDARY);
|
||||||
// You may look at the top card of your library any time.
|
|
||||||
this.addAbility(new SimpleStaticAbility(new LookAtTopCardOfLibraryAnyTimeEffect()));
|
// 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. If you cast a spell this way, pay life equal to its converted mana cost rather than pay its mana cost.
|
|
||||||
this.addAbility(new SimpleStaticAbility(new BolassCitadelPlayTheTopCardEffect()));
|
// You may play the top card of your library. If you cast a spell this way, pay life equal to its converted mana cost rather than pay its mana cost.
|
||||||
|
this.addAbility(new SimpleStaticAbility(new BolassCitadelPlayTheTopCardEffect()));
|
||||||
// {T}, Sacrifice ten nonland permanents: Each opponent loses 10 life.
|
|
||||||
Ability ability = new SimpleActivatedAbility(new LoseLifeOpponentsEffect(10), new TapSourceCost());
|
// {T}, Sacrifice ten nonland permanents: Each opponent loses 10 life.
|
||||||
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(
|
Ability ability = new SimpleActivatedAbility(new LoseLifeOpponentsEffect(10), new TapSourceCost());
|
||||||
10, 10, filter, true
|
ability.addCost(new SacrificeTargetCost(new TargetControlledPermanent(
|
||||||
)));
|
10, 10, filter, true
|
||||||
this.addAbility(ability);
|
)));
|
||||||
}
|
this.addAbility(ability);
|
||||||
|
}
|
||||||
private BolassCitadel(final BolassCitadel card) {
|
|
||||||
super(card);
|
private BolassCitadel(final BolassCitadel card) {
|
||||||
}
|
super(card);
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public BolassCitadel copy() {
|
@Override
|
||||||
return new BolassCitadel(this);
|
public BolassCitadel copy() {
|
||||||
}
|
return new BolassCitadel(this);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
class BolassCitadelPlayTheTopCardEffect extends AsThoughEffectImpl {
|
|
||||||
|
class BolassCitadelPlayTheTopCardEffect extends AsThoughEffectImpl {
|
||||||
BolassCitadelPlayTheTopCardEffect() {
|
|
||||||
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE,
|
BolassCitadelPlayTheTopCardEffect() {
|
||||||
Duration.WhileOnBattlefield, Outcome.AIDontUseIt); // AI will need help with this
|
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE,
|
||||||
staticText = "You may play the top card of your library. If you cast a spell this way, "
|
Duration.WhileOnBattlefield, Outcome.AIDontUseIt); // AI will need help with this
|
||||||
+ "pay life equal to its converted mana cost rather than pay its mana cost.";
|
staticText = "You may play the top card of your library. If you cast a spell this way, "
|
||||||
}
|
+ "pay life equal to its converted mana cost rather than pay its mana cost.";
|
||||||
|
}
|
||||||
private BolassCitadelPlayTheTopCardEffect(final BolassCitadelPlayTheTopCardEffect effect) {
|
|
||||||
super(effect);
|
private BolassCitadelPlayTheTopCardEffect(final BolassCitadelPlayTheTopCardEffect effect) {
|
||||||
}
|
super(effect);
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
@Override
|
||||||
return true;
|
public boolean apply(Game game, Ability source) {
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public BolassCitadelPlayTheTopCardEffect copy() {
|
@Override
|
||||||
return new BolassCitadelPlayTheTopCardEffect(this);
|
public BolassCitadelPlayTheTopCardEffect copy() {
|
||||||
}
|
return new BolassCitadelPlayTheTopCardEffect(this);
|
||||||
|
}
|
||||||
@Override
|
|
||||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
@Override
|
||||||
Card cardOnTop = game.getCard(objectId);
|
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||||
if (cardOnTop == null) {
|
return applies(objectId, null, source, game, affectedControllerId);
|
||||||
return false;
|
}
|
||||||
}
|
|
||||||
if (affectedControllerId.equals(source.getControllerId())
|
@Override
|
||||||
&& cardOnTop.isOwnedBy(source.getControllerId())) {
|
public boolean applies(UUID objectId, Ability affectedAbility, Ability source, Game game, UUID playerId) {
|
||||||
Player controller = game.getPlayer(cardOnTop.getOwnerId());
|
Card cardOnTop = game.getCard(objectId);
|
||||||
if (controller != null
|
if (cardOnTop == null) {
|
||||||
&& cardOnTop.equals(controller.getLibrary().getFromTop(game))) {
|
return false;
|
||||||
// add the life cost first
|
}
|
||||||
PayLifeCost cost = new PayLifeCost(cardOnTop.getManaCost().convertedManaCost());
|
if (playerId.equals(source.getControllerId())
|
||||||
Costs costs = new CostsImpl();
|
&& cardOnTop.isOwnedBy(source.getControllerId())) {
|
||||||
costs.add(cost);
|
Player controller = game.getPlayer(cardOnTop.getOwnerId());
|
||||||
// check for additional costs that must be paid
|
if (controller != null
|
||||||
if (cardOnTop.getSpellAbility() != null) {
|
&& cardOnTop.equals(controller.getLibrary().getFromTop(game))) {
|
||||||
for (Cost additionalCost : cardOnTop.getSpellAbility().getCosts()) {
|
if (affectedAbility instanceof ActivatedAbility) {
|
||||||
costs.add(additionalCost);
|
ActivatedAbility activatedAbility = (ActivatedAbility) affectedAbility;
|
||||||
}
|
// add the life cost first
|
||||||
}
|
PayLifeCost cost = new PayLifeCost(activatedAbility.getManaCosts().convertedManaCost());
|
||||||
controller.setCastSourceIdWithAlternateMana(cardOnTop.getId(), null, costs);
|
Costs costs = new CostsImpl();
|
||||||
return true;
|
costs.add(cost);
|
||||||
}
|
costs.addAll(activatedAbility.getCosts());
|
||||||
}
|
controller.setCastSourceIdWithAlternateMana(activatedAbility.getSourceId(), null, costs);
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -34,9 +34,9 @@ public final class BonecrusherGiant extends AdventureCard {
|
||||||
|
|
||||||
// Stomp
|
// Stomp
|
||||||
// Damage can’t be prevented this turn. Stomp deals 2 damage to any target.
|
// Damage can’t be prevented this turn. Stomp deals 2 damage to any target.
|
||||||
this.getAdventureSpellAbility().addEffect(new StompEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new StompEffect());
|
||||||
this.getAdventureSpellAbility().addEffect(new DamageTargetEffect(2));
|
this.getSpellCard().getSpellAbility().addEffect(new DamageTargetEffect(2));
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetAnyTarget());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetAnyTarget());
|
||||||
}
|
}
|
||||||
|
|
||||||
private BonecrusherGiant(final BonecrusherGiant card) {
|
private BonecrusherGiant(final BonecrusherGiant card) {
|
||||||
|
|
|
@ -48,8 +48,8 @@ public final class BrazenBorrower extends AdventureCard {
|
||||||
|
|
||||||
// Petty Theft
|
// Petty Theft
|
||||||
// Return target nonland permanent an opponent controls to its owner's hand.
|
// Return target nonland permanent an opponent controls to its owner's hand.
|
||||||
this.getAdventureSpellAbility().addEffect(new ReturnToHandTargetEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new ReturnToHandTargetEffect());
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetPermanent(filter));
|
this.getSpellCard().getSpellAbility().addTarget(new TargetPermanent(filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
private BrazenBorrower(final BrazenBorrower card) {
|
private BrazenBorrower(final BrazenBorrower card) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ public final class CuriousPair extends AdventureCard {
|
||||||
|
|
||||||
// Treats to Share
|
// Treats to Share
|
||||||
// Create a Food token.
|
// Create a Food token.
|
||||||
this.getAdventureSpellAbility().addEffect(new CreateTokenEffect(new FoodToken()));
|
this.getSpellCard().getSpellAbility().addEffect(new CreateTokenEffect(new FoodToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private CuriousPair(final CuriousPair card) {
|
private CuriousPair(final CuriousPair card) {
|
||||||
|
|
|
@ -25,8 +25,8 @@ public final class EmberethShieldbreaker extends AdventureCard {
|
||||||
|
|
||||||
// Battle Display
|
// Battle Display
|
||||||
// Destroy target artifact.
|
// Destroy target artifact.
|
||||||
this.getAdventureSpellAbility().addEffect(new DestroyTargetEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new DestroyTargetEffect());
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetArtifactPermanent());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetArtifactPermanent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private EmberethShieldbreaker(final EmberethShieldbreaker card) {
|
private EmberethShieldbreaker(final EmberethShieldbreaker card) {
|
||||||
|
|
|
@ -42,7 +42,7 @@ public final class FaeOfWishes extends AdventureCard {
|
||||||
|
|
||||||
// Granted
|
// Granted
|
||||||
// You may choose a noncreature card you own from outside the game, reveal it, and put it into your hand.
|
// You may choose a noncreature card you own from outside the game, reveal it, and put it into your hand.
|
||||||
this.getAdventureSpellAbility().addEffect(new WishEffect(StaticFilters.FILTER_CARD_A_NON_LAND));
|
this.getSpellCard().getSpellAbility().addEffect(new WishEffect(StaticFilters.FILTER_CARD_A_NON_LAND));
|
||||||
}
|
}
|
||||||
|
|
||||||
private FaeOfWishes(final FaeOfWishes card) {
|
private FaeOfWishes(final FaeOfWishes card) {
|
||||||
|
|
|
@ -30,13 +30,13 @@ public final class FaerieGuidemother extends AdventureCard {
|
||||||
|
|
||||||
// Gift of the Fae
|
// Gift of the Fae
|
||||||
// Target creature gets +2/+1 and gains flying until end of turn.
|
// Target creature gets +2/+1 and gains flying until end of turn.
|
||||||
this.getAdventureSpellAbility().addEffect(new BoostTargetEffect(
|
this.getSpellCard().getSpellAbility().addEffect(new BoostTargetEffect(
|
||||||
2, 1, Duration.EndOfTurn
|
2, 1, Duration.EndOfTurn
|
||||||
).setText("Target creature gets +2/+1"));
|
).setText("Target creature gets +2/+1"));
|
||||||
this.getAdventureSpellAbility().addEffect(new GainAbilityTargetEffect(
|
this.getSpellCard().getSpellAbility().addEffect(new GainAbilityTargetEffect(
|
||||||
FlyingAbility.getInstance(), Duration.EndOfTurn
|
FlyingAbility.getInstance(), Duration.EndOfTurn
|
||||||
).setText("and gains flying until end of turn"));
|
).setText("and gains flying until end of turn"));
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private FaerieGuidemother(final FaerieGuidemother card) {
|
private FaerieGuidemother(final FaerieGuidemother card) {
|
||||||
|
|
|
@ -44,7 +44,7 @@ public final class FlaxenIntruder extends AdventureCard {
|
||||||
|
|
||||||
// Welcome Home
|
// Welcome Home
|
||||||
// Create three 2/2 green Bear creature tokens.
|
// Create three 2/2 green Bear creature tokens.
|
||||||
this.getAdventureSpellAbility().addEffect(new CreateTokenEffect(new BearToken(), 3));
|
this.getSpellCard().getSpellAbility().addEffect(new CreateTokenEffect(new BearToken(), 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
private FlaxenIntruder(final FlaxenIntruder card) {
|
private FlaxenIntruder(final FlaxenIntruder card) {
|
||||||
|
|
|
@ -29,8 +29,8 @@ public final class FoulmireKnight extends AdventureCard {
|
||||||
|
|
||||||
// Profane Insight
|
// Profane Insight
|
||||||
// You draw a card and you lose 1 life.
|
// You draw a card and you lose 1 life.
|
||||||
this.getAdventureSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).setText("You draw a card and"));
|
this.getSpellCard().getSpellAbility().addEffect(new DrawCardSourceControllerEffect(1).setText("You draw a card and"));
|
||||||
this.getAdventureSpellAbility().addEffect(new LoseLifeSourceControllerEffect(1));
|
this.getSpellCard().getSpellAbility().addEffect(new LoseLifeSourceControllerEffect(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private FoulmireKnight(final FoulmireKnight card) {
|
private FoulmireKnight(final FoulmireKnight card) {
|
||||||
|
|
|
@ -26,8 +26,8 @@ public final class GarenbrigCarver extends AdventureCard {
|
||||||
|
|
||||||
// Shield's Might
|
// Shield's Might
|
||||||
// Target creature gets +2/+2 until end of turn.
|
// Target creature gets +2/+2 until end of turn.
|
||||||
this.getAdventureSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn));
|
this.getSpellCard().getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn));
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private GarenbrigCarver(final GarenbrigCarver card) {
|
private GarenbrigCarver(final GarenbrigCarver card) {
|
||||||
|
|
|
@ -47,8 +47,8 @@ public final class GiantKiller extends AdventureCard {
|
||||||
|
|
||||||
// Chop Down
|
// Chop Down
|
||||||
// Destroy target creature with power 4 or greater.
|
// Destroy target creature with power 4 or greater.
|
||||||
this.getAdventureSpellAbility().addEffect(new DestroyTargetEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new DestroyTargetEffect());
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetPermanent(filter));
|
this.getSpellCard().getSpellAbility().addTarget(new TargetPermanent(filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
private GiantKiller(final GiantKiller card) {
|
private GiantKiller(final GiantKiller card) {
|
||||||
|
|
|
@ -37,8 +37,8 @@ public final class HypnoticSprite extends AdventureCard {
|
||||||
|
|
||||||
// Mesmeric Glare
|
// Mesmeric Glare
|
||||||
// Counter target spell with converted mana cost 3 or less.
|
// Counter target spell with converted mana cost 3 or less.
|
||||||
this.getAdventureSpellAbility().addEffect(new CounterTargetEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new CounterTargetEffect());
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetSpell(filter));
|
this.getSpellCard().getSpellAbility().addTarget(new TargetSpell(filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
private HypnoticSprite(final HypnoticSprite card) {
|
private HypnoticSprite(final HypnoticSprite card) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ public final class LonesomeUnicorn extends AdventureCard {
|
||||||
|
|
||||||
// Rider in Need
|
// Rider in Need
|
||||||
// Create a 2/2 white Knight creature token with vigilance.
|
// Create a 2/2 white Knight creature token with vigilance.
|
||||||
this.getAdventureSpellAbility().addEffect(new CreateTokenEffect(new KnightToken()));
|
this.getSpellCard().getSpellAbility().addEffect(new CreateTokenEffect(new KnightToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private LonesomeUnicorn(final LonesomeUnicorn card) {
|
private LonesomeUnicorn(final LonesomeUnicorn card) {
|
||||||
|
|
|
@ -39,7 +39,7 @@ public final class LovestruckBeast extends AdventureCard {
|
||||||
|
|
||||||
// Heart's Desire
|
// Heart's Desire
|
||||||
// Create a 1/1 white Human creature token.
|
// Create a 1/1 white Human creature token.
|
||||||
this.getAdventureSpellAbility().addEffect(new CreateTokenEffect(new HumanToken()));
|
this.getSpellCard().getSpellAbility().addEffect(new CreateTokenEffect(new HumanToken()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private LovestruckBeast(final LovestruckBeast card) {
|
private LovestruckBeast(final LovestruckBeast card) {
|
||||||
|
|
|
@ -36,7 +36,7 @@ public final class MerchantOfTheVale extends AdventureCard {
|
||||||
|
|
||||||
// Haggle
|
// Haggle
|
||||||
// You may discard a card. If you do, draw a card.
|
// You may discard a card. If you do, draw a card.
|
||||||
this.getAdventureSpellAbility().addEffect(new DoIfCostPaid(
|
this.getSpellCard().getSpellAbility().addEffect(new DoIfCostPaid(
|
||||||
new DrawCardSourceControllerEffect(1), new DiscardCardCost()
|
new DrawCardSourceControllerEffect(1), new DiscardCardCost()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ public final class MerfolkSecretkeeper extends AdventureCard {
|
||||||
|
|
||||||
// Venture Deeper
|
// Venture Deeper
|
||||||
// Target player puts the top four cards of their library into their graveyard.
|
// Target player puts the top four cards of their library into their graveyard.
|
||||||
this.getAdventureSpellAbility().addEffect(new PutLibraryIntoGraveTargetEffect(4));
|
this.getSpellCard().getSpellAbility().addEffect(new PutLibraryIntoGraveTargetEffect(4));
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetPlayer());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetPlayer());
|
||||||
}
|
}
|
||||||
|
|
||||||
private MerfolkSecretkeeper(final MerfolkSecretkeeper card) {
|
private MerfolkSecretkeeper(final MerfolkSecretkeeper card) {
|
||||||
|
|
|
@ -37,11 +37,11 @@ public final class MurderousRider extends AdventureCard {
|
||||||
|
|
||||||
// Swift End
|
// Swift End
|
||||||
// Destroy target creature or planeswalker. You lose 2 life.
|
// Destroy target creature or planeswalker. You lose 2 life.
|
||||||
this.getAdventureSpellAbility().addEffect(new DestroyTargetEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new DestroyTargetEffect());
|
||||||
this.getAdventureSpellAbility().addEffect(
|
this.getSpellCard().getSpellAbility().addEffect(
|
||||||
new LoseLifeSourceControllerEffect(2).setText("You lose 2 life.")
|
new LoseLifeSourceControllerEffect(2).setText("You lose 2 life.")
|
||||||
);
|
);
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetCreatureOrPlaneswalker());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetCreatureOrPlaneswalker());
|
||||||
}
|
}
|
||||||
|
|
||||||
private MurderousRider(final MurderousRider card) {
|
private MurderousRider(final MurderousRider card) {
|
||||||
|
|
|
@ -34,7 +34,7 @@ public final class OakhameRanger extends AdventureCard {
|
||||||
|
|
||||||
// Bring Back
|
// Bring Back
|
||||||
// Create two 1/1 white Human creature tokens.
|
// Create two 1/1 white Human creature tokens.
|
||||||
this.getAdventureSpellAbility().addEffect(new CreateTokenEffect(new HumanToken(), 2));
|
this.getSpellCard().getSpellAbility().addEffect(new CreateTokenEffect(new HumanToken(), 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
private OakhameRanger(final OakhameRanger card) {
|
private OakhameRanger(final OakhameRanger card) {
|
||||||
|
|
|
@ -34,8 +34,8 @@ public final class OrderOfMidnight extends AdventureCard {
|
||||||
|
|
||||||
// Alter Fate
|
// Alter Fate
|
||||||
// Return target creature card from your graveyard to your hand.
|
// Return target creature card from your graveyard to your hand.
|
||||||
this.getAdventureSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new ReturnFromGraveyardToHandTargetEffect());
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
|
this.getSpellCard().getSpellAbility().addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_CREATURE_YOUR_GRAVEYARD));
|
||||||
}
|
}
|
||||||
|
|
||||||
private OrderOfMidnight(final OrderOfMidnight card) {
|
private OrderOfMidnight(final OrderOfMidnight card) {
|
||||||
|
|
|
@ -39,10 +39,10 @@ public final class QueenOfIce extends AdventureCard {
|
||||||
|
|
||||||
// Rage of Winter
|
// Rage of Winter
|
||||||
// Tap target creature. It doesn’t untap during its controller’s next untap step.
|
// Tap target creature. It doesn’t untap during its controller’s next untap step.
|
||||||
this.getAdventureSpellAbility().addEffect(new TapTargetEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new TapTargetEffect());
|
||||||
this.getAdventureSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect()
|
this.getSpellCard().getSpellAbility().addEffect(new DontUntapInControllersNextUntapStepTargetEffect()
|
||||||
.setText("It doesn't untap during its controller's next untap step"));
|
.setText("It doesn't untap during its controller's next untap step"));
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private QueenOfIce(final QueenOfIce card) {
|
private QueenOfIce(final QueenOfIce card) {
|
||||||
|
|
|
@ -37,7 +37,7 @@ public final class RealmCloakedGiant extends AdventureCard {
|
||||||
|
|
||||||
// Cast Off
|
// Cast Off
|
||||||
// Destroy all non-Giant creatures.
|
// Destroy all non-Giant creatures.
|
||||||
this.getAdventureSpellAbility().addEffect(new DestroyAllEffect(filter));
|
this.getSpellCard().getSpellAbility().addEffect(new DestroyAllEffect(filter));
|
||||||
}
|
}
|
||||||
|
|
||||||
private RealmCloakedGiant(final RealmCloakedGiant card) {
|
private RealmCloakedGiant(final RealmCloakedGiant card) {
|
||||||
|
|
|
@ -41,8 +41,8 @@ public final class ReaperOfNight extends AdventureCard {
|
||||||
|
|
||||||
// Harvest Fear
|
// Harvest Fear
|
||||||
// Target opponent discards two cards.
|
// Target opponent discards two cards.
|
||||||
this.getAdventureSpellAbility().addEffect(new DiscardTargetEffect(2));
|
this.getSpellCard().getSpellAbility().addEffect(new DiscardTargetEffect(2));
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetOpponent());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetOpponent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReaperOfNight(final ReaperOfNight card) {
|
private ReaperOfNight(final ReaperOfNight card) {
|
||||||
|
|
|
@ -30,8 +30,8 @@ public final class RimrockKnight extends AdventureCard {
|
||||||
|
|
||||||
// Boulder Rush
|
// Boulder Rush
|
||||||
// Target creature gets +2/+0 until end of turn.
|
// Target creature gets +2/+0 until end of turn.
|
||||||
this.getAdventureSpellAbility().addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn));
|
this.getSpellCard().getSpellAbility().addEffect(new BoostTargetEffect(2, 0, Duration.EndOfTurn));
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private RimrockKnight(final RimrockKnight card) {
|
private RimrockKnight(final RimrockKnight card) {
|
||||||
|
|
|
@ -28,7 +28,7 @@ public final class RosethornAcolyte extends AdventureCard {
|
||||||
|
|
||||||
// Seasonal Ritual
|
// Seasonal Ritual
|
||||||
// Add one mana of any color.
|
// Add one mana of any color.
|
||||||
this.getAdventureSpellAbility().addEffect(new AddManaOfAnyColorEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new AddManaOfAnyColorEffect());
|
||||||
}
|
}
|
||||||
|
|
||||||
private RosethornAcolyte(final RosethornAcolyte card) {
|
private RosethornAcolyte(final RosethornAcolyte card) {
|
||||||
|
|
|
@ -25,8 +25,8 @@ public final class ShepherdOfTheFlock extends AdventureCard {
|
||||||
|
|
||||||
// Usher to Safety
|
// Usher to Safety
|
||||||
// Return target permanent you control to its owner’s hand.
|
// Return target permanent you control to its owner’s hand.
|
||||||
this.getAdventureSpellAbility().addEffect(new ReturnToHandTargetEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new ReturnToHandTargetEffect());
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetControlledPermanent());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetControlledPermanent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private ShepherdOfTheFlock(final ShepherdOfTheFlock card) {
|
private ShepherdOfTheFlock(final ShepherdOfTheFlock card) {
|
||||||
|
|
|
@ -27,9 +27,9 @@ public final class SilverflameSquire extends AdventureCard {
|
||||||
|
|
||||||
// On Alert
|
// On Alert
|
||||||
// Target creature gets +2/+2 until end of turn. Untap it.
|
// Target creature gets +2/+2 until end of turn. Untap it.
|
||||||
this.getAdventureSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn));
|
this.getSpellCard().getSpellAbility().addEffect(new BoostTargetEffect(2, 2, Duration.EndOfTurn));
|
||||||
this.getAdventureSpellAbility().addEffect(new UntapTargetEffect().setText("Untap it"));
|
this.getSpellCard().getSpellAbility().addEffect(new UntapTargetEffect().setText("Untap it"));
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private SilverflameSquire(final SilverflameSquire card) {
|
private SilverflameSquire(final SilverflameSquire card) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ public final class SmittenSwordmaster extends AdventureCard {
|
||||||
|
|
||||||
// Curry Favor
|
// Curry Favor
|
||||||
// You gain X life and each opponent loses X life, where X is the number of Knights you control.
|
// You gain X life and each opponent loses X life, where X is the number of Knights you control.
|
||||||
this.getAdventureSpellAbility().addEffect(new CurryFavorEffect());
|
this.getSpellCard().getSpellAbility().addEffect(new CurryFavorEffect());
|
||||||
}
|
}
|
||||||
|
|
||||||
private SmittenSwordmaster(final SmittenSwordmaster card) {
|
private SmittenSwordmaster(final SmittenSwordmaster card) {
|
||||||
|
|
|
@ -26,8 +26,8 @@ public final class TuinvaleTreefolk extends AdventureCard {
|
||||||
|
|
||||||
// Oaken Boon
|
// Oaken Boon
|
||||||
// Put two +1/+1 counters on target creature.
|
// Put two +1/+1 counters on target creature.
|
||||||
this.getAdventureSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)));
|
this.getSpellCard().getSpellAbility().addEffect(new AddCountersTargetEffect(CounterType.P1P1.createInstance(2)));
|
||||||
this.getAdventureSpellAbility().addTarget(new TargetCreaturePermanent());
|
this.getSpellCard().getSpellAbility().addTarget(new TargetCreaturePermanent());
|
||||||
}
|
}
|
||||||
|
|
||||||
private TuinvaleTreefolk(final TuinvaleTreefolk card) {
|
private TuinvaleTreefolk(final TuinvaleTreefolk card) {
|
||||||
|
|
|
@ -327,8 +327,5 @@ public final class ThroneOfEldraine extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Worthy Knight", 36, Rarity.RARE, mage.cards.w.WorthyKnight.class));
|
cards.add(new SetCardInfo("Worthy Knight", 36, Rarity.RARE, mage.cards.w.WorthyKnight.class));
|
||||||
cards.add(new SetCardInfo("Yorvo, Lord of Garenbrig", 185, Rarity.RARE, mage.cards.y.YorvoLordOfGarenbrig.class));
|
cards.add(new SetCardInfo("Yorvo, Lord of Garenbrig", 185, Rarity.RARE, mage.cards.y.YorvoLordOfGarenbrig.class));
|
||||||
cards.add(new SetCardInfo("Youthful Knight", 37, Rarity.COMMON, mage.cards.y.YouthfulKnight.class));
|
cards.add(new SetCardInfo("Youthful Knight", 37, Rarity.COMMON, mage.cards.y.YouthfulKnight.class));
|
||||||
|
|
||||||
// This is here to prevent the incomplete adventure implementation from causing problems and will be removed
|
|
||||||
cards.removeIf(setCardInfo -> AdventureCard.class.isAssignableFrom(setCardInfo.getCardClass()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,8 +111,5 @@ public final class ThroneOfEldraineCollectorsEdition extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Witch's Vengeance", 358, Rarity.RARE, mage.cards.w.WitchsVengeance.class));
|
cards.add(new SetCardInfo("Witch's Vengeance", 358, Rarity.RARE, mage.cards.w.WitchsVengeance.class));
|
||||||
cards.add(new SetCardInfo("Worthy Knight", 341, Rarity.RARE, mage.cards.w.WorthyKnight.class));
|
cards.add(new SetCardInfo("Worthy Knight", 341, Rarity.RARE, mage.cards.w.WorthyKnight.class));
|
||||||
cards.add(new SetCardInfo("Yorvo, Lord of Garenbrig", 376, Rarity.RARE, mage.cards.y.YorvoLordOfGarenbrig.class));
|
cards.add(new SetCardInfo("Yorvo, Lord of Garenbrig", 376, Rarity.RARE, mage.cards.y.YorvoLordOfGarenbrig.class));
|
||||||
|
|
||||||
// This is here to prevent the incomplete adventure implementation from causing problems and will be removed
|
|
||||||
cards.removeIf(setCardInfo -> AdventureCard.class.isAssignableFrom(setCardInfo.getCardClass()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,535 @@
|
||||||
|
package org.mage.test.cards.cost.adventure;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.counters.CounterType;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
public class AdventureCardsTest extends CardTestPlayerBase {
|
||||||
|
@Test
|
||||||
|
public void testCastTreatsToShare() {
|
||||||
|
/*
|
||||||
|
* Curious Pair {1}{G}
|
||||||
|
* Creature — Human Peasant
|
||||||
|
* 1/3
|
||||||
|
* ----
|
||||||
|
* Treats to Share {G}
|
||||||
|
* Sorcery — Adventure
|
||||||
|
* Create a Food token.
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 1);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 1);
|
||||||
|
assertGraveyardCount(playerA,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCantCastTreatsToShareTwice() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertActionsCount(playerA, 1);
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 1);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 1);
|
||||||
|
assertGraveyardCount(playerA,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastCuriousPair() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair");
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 0);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 1);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 0);
|
||||||
|
assertGraveyardCount(playerA,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastTreatsToShareAndCuriousPair() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair");
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 1);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 1);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 0);
|
||||||
|
assertGraveyardCount(playerA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastTreatsToShareWithEdgewallInnkeeper() {
|
||||||
|
/*
|
||||||
|
* Edgewall Innkeeper {G}
|
||||||
|
* Creature — Human Peasant
|
||||||
|
* Whenever you cast a creature spell that has an Adventure, draw a card.
|
||||||
|
* 1/1
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Edgewall Innkeeper");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 1);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 0);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 1);
|
||||||
|
assertGraveyardCount(playerA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastCuriousPairWithEdgewallInnkeeper() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Edgewall Innkeeper");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair");
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertHandCount(playerA, 1);
|
||||||
|
assertPermanentCount(playerA, "Food", 0);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 1);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 0);
|
||||||
|
assertGraveyardCount(playerA,0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastTreatsToShareAndCuriousPairWithEdgewallInnkeeper() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Edgewall Innkeeper");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair");
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 1);
|
||||||
|
assertPermanentCount(playerA, "Food", 1);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 1);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 0);
|
||||||
|
assertGraveyardCount(playerA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastMemoryTheft() {
|
||||||
|
/*
|
||||||
|
* Memory Theft {2}{B}
|
||||||
|
* Sorcery
|
||||||
|
* Target opponent reveals their hand. You choose a nonland card from it. That player discards that card.
|
||||||
|
* You may put a card that has an Adventure that player owns from exile into that player's graveyard.
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
addCard(Zone.HAND, playerA, "Opt");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Swamp");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Swamp");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Swamp");
|
||||||
|
addCard(Zone.HAND, playerB, "Memory Theft");
|
||||||
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Memory Theft", playerA);
|
||||||
|
playerB.addChoice("Opt");
|
||||||
|
playerB.addChoice("Curious Pair");
|
||||||
|
|
||||||
|
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 0);
|
||||||
|
assertGraveyardCount(playerA, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastTreatsToShareWithLuckyClover() {
|
||||||
|
/*
|
||||||
|
* Lucky Clover {2}
|
||||||
|
* Artifact
|
||||||
|
* Whenever you cast an Adventure instant or sorcery spell, copy it. You may choose new targets for the copy.
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Lucky Clover");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 2);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 0);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 1);
|
||||||
|
assertGraveyardCount(playerA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastTreatsToShareAndCopy() {
|
||||||
|
/*
|
||||||
|
* Fork {R}{R}
|
||||||
|
* Instant
|
||||||
|
* Copy target instant or sorcery spell, except that the copy is red. You may choose new targets for the copy.
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
addCard(Zone.HAND, playerA, "Fork");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Fork", "Treats to Share");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 2);
|
||||||
|
assertPermanentCount(playerA, 5);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 1);
|
||||||
|
assertExileCount(playerA, 1);
|
||||||
|
assertGraveyardCount(playerA, "Fork", 1);
|
||||||
|
assertGraveyardCount(playerA, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastTreatsToShareAndCounter() {
|
||||||
|
/*
|
||||||
|
* Counterspell {U}{U}
|
||||||
|
* Instant
|
||||||
|
* Counter target spell.
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Island");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Island");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
addCard(Zone.HAND, playerB, "Counterspell");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerB, "Counterspell", "Treats to Share");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 0);
|
||||||
|
assertPermanentCount(playerA, 1);
|
||||||
|
assertExileCount(playerA, 0);
|
||||||
|
assertGraveyardCount(playerA, "Curious Pair", 1);
|
||||||
|
assertGraveyardCount(playerA, 1);
|
||||||
|
assertGraveyardCount(playerB, "Counterspell", 1);
|
||||||
|
assertGraveyardCount(playerB, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastOpponentsHandTreatsToShare() {
|
||||||
|
/*
|
||||||
|
* Psychic Intrusion {3}{U}{B}
|
||||||
|
* Sorcery
|
||||||
|
* Target opponent reveals their hand. You choose a nonland card from that player's graveyard or hand and exile it.
|
||||||
|
* You may cast that card for as long as it remains exiled, and you may spend mana as though it were mana of any color to cast that spell.
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 6);
|
||||||
|
addCard(Zone.HAND, playerA, "Psychic Intrusion");
|
||||||
|
addCard(Zone.HAND, playerB, "Curious Pair");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Psychic Intrusion", playerB);
|
||||||
|
playerA.addChoice("Curious Pair");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertHandCount(playerB, 0);
|
||||||
|
assertPermanentCount(playerB, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 1);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 1);
|
||||||
|
assertExileCount(playerA, 0);
|
||||||
|
assertExileCount(playerB, 0);
|
||||||
|
assertGraveyardCount(playerA, "Psychic Intrusion", 1);
|
||||||
|
assertGraveyardCount(playerA, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMultipleAdventures() {
|
||||||
|
/*
|
||||||
|
* Eager Cadet
|
||||||
|
* Creature — Human Soldier
|
||||||
|
* 1/1
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
* Rimrock Knight {1}{R}
|
||||||
|
* Creature — Dwarf Knight
|
||||||
|
* Rimrock Knight can't block.
|
||||||
|
* 3/1
|
||||||
|
* ----
|
||||||
|
* Boulder Rush {R}
|
||||||
|
* Instant — Adventure
|
||||||
|
* Target creature gets +2/+0 until end of turn.
|
||||||
|
*/
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Eager Cadet");
|
||||||
|
addCard(Zone.HAND, playerA, "Rimrock Knight", 2);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boulder Rush", "Eager Cadet");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Boulder Rush", "Eager Cadet");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rimrock Knight");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rimrock Knight");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Rimrock Knight", 2);
|
||||||
|
assertPermanentCount(playerA, "Eager Cadet", 1);
|
||||||
|
assertPowerToughness(playerA, "Eager Cadet", 5, 1);
|
||||||
|
assertExileCount(playerA, 0);
|
||||||
|
assertGraveyardCount(playerA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRimrockKnightPermanentText() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||||
|
addCard(Zone.HAND, playerA, "Rimrock Knight");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Rimrock Knight");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Rimrock Knight", 1);
|
||||||
|
assertExileCount(playerA, 0);
|
||||||
|
assertGraveyardCount(playerA, 0);
|
||||||
|
|
||||||
|
Permanent rimrock = getPermanent("Rimrock Knight");
|
||||||
|
Assert.assertEquals(rimrock.getRules(currentGame).get(0), "{this} can't block.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tests for Rule 601.3e:
|
||||||
|
* 601.3e If a rule or effect states that only an alternative set of characteristics or a subset of characteristics
|
||||||
|
* are considered to determine if a card or copy of a card is legal to cast, those alternative characteristics
|
||||||
|
* replace the object’s characteristics prior to determining whether the player may begin to cast it.
|
||||||
|
* Example: Garruk’s Horde says, in part, “You may cast the top card of your library if it’s a creature card.” If
|
||||||
|
* you control Garruk’s Horde and the top card of your library is a noncreature card with morph, you may cast it
|
||||||
|
* using its morph ability.
|
||||||
|
* Example: Melek, Izzet Paragon says, in part, “You may cast the top card of your library if it’s an instant or
|
||||||
|
* sorcery card.” If you control Melek, Izzet Paragon and the top card of your library is Giant Killer, an
|
||||||
|
* adventurer creature card whose Adventure is an instant named Chop Down, you may cast Chop Down but not Giant
|
||||||
|
* Killer. If instead you control Garruk’s Horde and the top card of your library is Giant Killer, you may cast
|
||||||
|
* Giant Killer but not Chop Down.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastTreatsToShareWithMelek() {
|
||||||
|
/*
|
||||||
|
* Melek, Izzet Paragon {4}{U}{R}
|
||||||
|
* Legendary Creature — Weird Wizard
|
||||||
|
* Play with the top card of your library revealed.
|
||||||
|
* You may cast the top card of your library if it's an instant or sorcery card.
|
||||||
|
* Whenever you cast an instant or sorcery spell from your library, copy it. You may choose new targets for the copy.
|
||||||
|
* 2/4
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Melek, Izzet Paragon");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
removeAllCardsFromLibrary(playerA);
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Curious Pair");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, 4);
|
||||||
|
assertPermanentCount(playerA, "Food", 2);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 0);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 1);
|
||||||
|
assertGraveyardCount(playerA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCantCastCuriousPairWithMelek() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Melek, Izzet Paragon");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
|
||||||
|
removeAllCardsFromLibrary(playerA);
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Curious Pair");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertActionsCount(playerA, 1);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 0);
|
||||||
|
assertLibraryCount(playerA, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastCuriousPairWithGarruksHorde() {
|
||||||
|
/*
|
||||||
|
* Garruk's Horde {5}{G}{G}
|
||||||
|
* Creature — Beast
|
||||||
|
* Trample
|
||||||
|
* Play with the top card of your library revealed.
|
||||||
|
* You may cast the top card of your library if it's a creature card.
|
||||||
|
* 7/7
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Garruk's Horde");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
|
||||||
|
removeAllCardsFromLibrary(playerA);
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Curious Pair");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Curious Pair");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 0);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 1);
|
||||||
|
assertExileCount(playerA, 0);
|
||||||
|
assertGraveyardCount(playerA, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCantCastTreatsToShareWithGarruksHorde() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Garruk's Horde");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
removeAllCardsFromLibrary(playerA);
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Curious Pair");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertActionsCount(playerA, 1);
|
||||||
|
assertPermanentCount(playerA, "Food", 0);
|
||||||
|
assertLibraryCount(playerA, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore("Not yet working correctly.")
|
||||||
|
public void testCastTreatsToShareWithWrennAndSixEmblem() {
|
||||||
|
/*
|
||||||
|
* Wrenn and Six {R}{G}
|
||||||
|
* Legendary Planeswalker — Wrenn
|
||||||
|
* +1: Return up to one target land card from your graveyard to your hand.
|
||||||
|
* −1: Wrenn and Six deals 1 damage to any target.
|
||||||
|
* −7: You get an emblem with "Instant and sorcery cards in your graveyard have retrace."
|
||||||
|
* Loyalty: 3
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Wrenn and Six");
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, "Curious Pair");
|
||||||
|
addCard(Zone.HAND, playerA, "Forest");
|
||||||
|
|
||||||
|
addCounters(1, PhaseStep.UPKEEP, playerA, "Wrenn and Six", CounterType.LOYALTY, 5);
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "-7: You get an emblem");
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 1);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 0);
|
||||||
|
assertPermanentCount(playerA, "Wrenn and Six", 1);
|
||||||
|
assertEmblemCount(playerA, 1);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 1);
|
||||||
|
assertGraveyardCount(playerA, "Forest", 1);
|
||||||
|
assertGraveyardCount(playerA, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCastTreatsToShareWithTeferiTimeRaveler() {
|
||||||
|
/*
|
||||||
|
* Teferi, Time Raveler {1}{W}{U}
|
||||||
|
* Legendary Planeswalker — Teferi
|
||||||
|
* Each opponent can cast spells only any time they could cast a sorcery.
|
||||||
|
* +1: Until your next turn, you may cast sorcery spells as though they had flash.
|
||||||
|
* −3: Return up to one target artifact, creature, or enchantment to its owner's hand. Draw a card.
|
||||||
|
* Loyalty: 4
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Teferi, Time Raveler");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.HAND, playerA, "Curious Pair");
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "+1: Until your next");
|
||||||
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Treats to Share");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, 3);
|
||||||
|
assertPermanentCount(playerA, "Food", 1);
|
||||||
|
assertPermanentCount(playerA, "Curious Pair", 0);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 1);
|
||||||
|
assertGraveyardCount(playerA, 0);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package org.mage.test.cards.cost.alternate;
|
||||||
|
|
||||||
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
public class BolassCitadelTest extends CardTestPlayerBase {
|
||||||
|
@Test
|
||||||
|
public void testCastEagerCadet() {
|
||||||
|
/*
|
||||||
|
* Eager Cadet
|
||||||
|
* Creature — Human Soldier
|
||||||
|
* 1/1
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Bolas's Citadel");
|
||||||
|
removeAllCardsFromLibrary(playerA);
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Eager Cadet");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Eager Cadet");
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Eager Cadet", 1);
|
||||||
|
assertGraveyardCount(playerA,0);
|
||||||
|
assertLife(playerA, 19);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Ignore("This is broken for now.")
|
||||||
|
public void testCastAdventure() {
|
||||||
|
/*
|
||||||
|
* Curious Pair {1}{G}
|
||||||
|
* Creature — Human Peasant
|
||||||
|
* 1/3
|
||||||
|
* ----
|
||||||
|
* Treats to Share {G}
|
||||||
|
* Sorcery — Adventure
|
||||||
|
* Create a Food token.
|
||||||
|
*/
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Bolas's Citadel");
|
||||||
|
removeAllCardsFromLibrary(playerA);
|
||||||
|
addCard(Zone.LIBRARY, playerA, "Curious Pair");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Treats to Share");
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertAllCommandsUsed();
|
||||||
|
assertTapped("Forest", false);
|
||||||
|
assertHandCount(playerA, 0);
|
||||||
|
assertPermanentCount(playerA, "Food", 1);
|
||||||
|
assertExileCount(playerA, "Curious Pair", 1);
|
||||||
|
assertGraveyardCount(playerA,0);
|
||||||
|
assertLife(playerA, 19);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,10 +5,7 @@ import mage.MageObjectReference;
|
||||||
import mage.abilities.*;
|
import mage.abilities.*;
|
||||||
import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect;
|
import mage.abilities.effects.common.continuous.BecomesFaceDownCreatureEffect;
|
||||||
import mage.abilities.effects.common.continuous.CommanderReplacementEffect;
|
import mage.abilities.effects.common.continuous.CommanderReplacementEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.*;
|
||||||
import mage.cards.Cards;
|
|
||||||
import mage.cards.CardsImpl;
|
|
||||||
import mage.cards.SplitCardHalf;
|
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.filter.FilterCard;
|
import mage.filter.FilterCard;
|
||||||
import mage.filter.predicate.Predicate;
|
import mage.filter.predicate.Predicate;
|
||||||
|
@ -509,8 +506,12 @@ public class ContinuousEffects implements Serializable {
|
||||||
if (affectedAbility != null && affectedAbility.getSourceObject(game) instanceof SplitCardHalf) {
|
if (affectedAbility != null && affectedAbility.getSourceObject(game) instanceof SplitCardHalf) {
|
||||||
idToCheck = ((SplitCardHalf) affectedAbility.getSourceObject(game)).getParentCard().getId();
|
idToCheck = ((SplitCardHalf) affectedAbility.getSourceObject(game)).getParentCard().getId();
|
||||||
} else {
|
} else {
|
||||||
if (game.getObject(objectId) instanceof SplitCardHalf) {
|
Card card = game.getCard(objectId);
|
||||||
idToCheck = ((SplitCardHalf) game.getObject(objectId)).getParentCard().getId();
|
if (card != null && card instanceof SplitCardHalf) {
|
||||||
|
idToCheck = ((SplitCardHalf) card).getParentCard().getId();
|
||||||
|
} else if (card != null && type == AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE
|
||||||
|
&& card instanceof AdventureCardSpell) {
|
||||||
|
idToCheck = ((AdventureCardSpell) card).getParentCard().getId();
|
||||||
} else {
|
} else {
|
||||||
idToCheck = objectId;
|
idToCheck = objectId;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,107 @@
|
||||||
|
package mage.abilities.effects.common;
|
||||||
|
|
||||||
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.MageSingleton;
|
||||||
|
import mage.abilities.effects.AsThoughEffectImpl;
|
||||||
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.cards.AdventureCardSpell;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.constants.AsThoughEffectType;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.Outcome;
|
||||||
|
import mage.game.ExileZone;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.targetpointer.FixedTarget;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author phulin
|
||||||
|
*/
|
||||||
|
public class ExileAdventureSpellEffect extends OneShotEffect implements MageSingleton {
|
||||||
|
|
||||||
|
private static final ExileAdventureSpellEffect instance = new ExileAdventureSpellEffect();
|
||||||
|
|
||||||
|
public static ExileAdventureSpellEffect getInstance() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UUID adventureExileId(UUID controllerId, Game game) {
|
||||||
|
return CardUtil.getExileZoneId(controllerId.toString() + "- On an Adventure", game);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ExileAdventureSpellEffect() {
|
||||||
|
super(Outcome.Exile);
|
||||||
|
staticText = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ExileAdventureSpellEffect copy() {
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
|
if (controller != null) {
|
||||||
|
Spell spell = game.getStack().getSpell(source.getId());
|
||||||
|
if (spell != null && !spell.isCopy()) {
|
||||||
|
Card spellCard = spell.getCard();
|
||||||
|
if (spellCard != null && spellCard instanceof AdventureCardSpell) {
|
||||||
|
UUID exileId = adventureExileId(controller.getId(), game);
|
||||||
|
game.getExile().createZone(exileId, "On an Adventure");
|
||||||
|
AdventureCardSpell adventureSpellCard = (AdventureCardSpell) spellCard;
|
||||||
|
Card parentCard = adventureSpellCard.getParentCard();
|
||||||
|
if (controller.moveCardsToExile(parentCard, source, game, true, exileId, "On an Adventure")) {
|
||||||
|
ContinuousEffect effect = new AdventureCastFromExileEffect();
|
||||||
|
effect.setTargetPointer(new FixedTarget(parentCard.getId(), game));
|
||||||
|
game.addEffect(effect, source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AdventureCastFromExileEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
|
public AdventureCastFromExileEffect() {
|
||||||
|
super(AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, Duration.Custom, Outcome.Benefit);
|
||||||
|
staticText = "Then exile this card. You may cast the creature later from exile.";
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdventureCastFromExileEffect(final AdventureCastFromExileEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AdventureCastFromExileEffect copy() {
|
||||||
|
return new AdventureCastFromExileEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
||||||
|
UUID targetId = getTargetPointer().getFirst(game, source);
|
||||||
|
ExileZone adventureExileZone = game.getExile().getExileZone(ExileAdventureSpellEffect.adventureExileId(affectedControllerId, game));
|
||||||
|
if (targetId == null) {
|
||||||
|
this.discard();
|
||||||
|
} else if (objectId.equals(targetId)
|
||||||
|
&& affectedControllerId.equals(source.getControllerId())
|
||||||
|
&& adventureExileZone.contains(objectId)) {
|
||||||
|
Card card = game.getCard(objectId);
|
||||||
|
return card != null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,10 @@
|
||||||
package mage.abilities.effects.common.continuous;
|
package mage.abilities.effects.common.continuous;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import mage.MageObject;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.effects.AsThoughEffectImpl;
|
import mage.abilities.effects.AsThoughEffectImpl;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.constants.AsThoughEffectType;
|
import mage.constants.AsThoughEffectType;
|
||||||
|
@ -47,12 +50,27 @@ public class PlayTheTopCardEffect extends AsThoughEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(UUID objectId, Ability source, UUID affectedControllerId, Game game) {
|
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) {
|
||||||
Card cardOnTop = game.getCard(objectId);
|
Card cardOnTop = game.getCard(objectId);
|
||||||
|
Card cardToCheckProperties = cardOnTop;
|
||||||
|
|
||||||
|
// Check each ability individually, as e.g. Adventures and associated creatures may get different results from the filter.
|
||||||
|
if (affectedAbility != null) {
|
||||||
|
MageObject sourceObject = affectedAbility.getSourceObject(game);
|
||||||
|
if (sourceObject != null && sourceObject instanceof Card) {
|
||||||
|
cardToCheckProperties = (Card) sourceObject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (cardOnTop != null
|
if (cardOnTop != null
|
||||||
&& affectedControllerId.equals(source.getControllerId())
|
&& playerId.equals(source.getControllerId())
|
||||||
&& cardOnTop.isOwnedBy(source.getControllerId())
|
&& cardOnTop.isOwnedBy(source.getControllerId())
|
||||||
&& (!cardOnTop.getManaCost().isEmpty() || cardOnTop.isLand())
|
&& (!cardToCheckProperties.getManaCost().isEmpty() || cardToCheckProperties.isLand())
|
||||||
&& filter.match(cardOnTop, game)) {
|
&& filter.match(cardToCheckProperties, game)) {
|
||||||
Player player = game.getPlayer(cardOnTop.getOwnerId());
|
Player player = game.getPlayer(cardOnTop.getOwnerId());
|
||||||
if (player != null && cardOnTop.equals(player.getLibrary().getFromTop(game))) {
|
if (player != null && cardOnTop.equals(player.getLibrary().getFromTop(game))) {
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
|
import mage.abilities.Abilities;
|
||||||
|
import mage.abilities.AbilitiesImpl;
|
||||||
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.SpellAbility;
|
import mage.abilities.SpellAbility;
|
||||||
import mage.constants.CardType;
|
import mage.constants.*;
|
||||||
|
import mage.game.Game;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,17 +15,87 @@ import java.util.UUID;
|
||||||
*/
|
*/
|
||||||
public abstract class AdventureCard extends CardImpl {
|
public abstract class AdventureCard extends CardImpl {
|
||||||
|
|
||||||
protected SpellAbility adventureSpellAbility = new SpellAbility(null, null);
|
/* The adventure spell card, i.e. Swift End. */
|
||||||
|
protected Card spellCard;
|
||||||
|
|
||||||
public AdventureCard(UUID ownerId, CardSetInfo setInfo, CardType[] typesLeft, CardType[] typesRight, String costsLeft, String adventureName, String costsRight) {
|
public AdventureCard(UUID ownerId, CardSetInfo setInfo, CardType[] types, CardType[] typesSpell, String costs, String adventureName, String costsSpell) {
|
||||||
super(ownerId, setInfo, typesLeft, costsLeft);
|
super(ownerId, setInfo, types, costs);
|
||||||
|
this.spellCard = new AdventureCardSpellImpl(ownerId, setInfo, adventureName, typesSpell, costsSpell, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public AdventureCard(AdventureCard card) {
|
public AdventureCard(AdventureCard card) {
|
||||||
super(card);
|
super(card);
|
||||||
|
this.spellCard = card.getSpellCard().copy();
|
||||||
|
((AdventureCardSpell)this.spellCard).setParentCard(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellAbility getAdventureSpellAbility() {
|
public Card getSpellCard() {
|
||||||
return adventureSpellAbility;
|
return spellCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assignNewId() {
|
||||||
|
super.assignNewId();
|
||||||
|
spellCard.assignNewId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List<UUID> appliedEffects) {
|
||||||
|
if (super.moveToZone(toZone, sourceId, game, flag, appliedEffects)) {
|
||||||
|
game.getState().setZone(getSpellCard().getId(), toZone);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setZone(Zone zone, Game game) {
|
||||||
|
super.setZone(zone, game);
|
||||||
|
game.setZone(getSpellCard().getId(), zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
|
||||||
|
if (super.moveToExile(exileId, name, sourceId, game, appliedEffects)) {
|
||||||
|
Zone currentZone = game.getState().getZone(getId());
|
||||||
|
game.getState().setZone(getSpellCard().getId(), currentZone);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) {
|
||||||
|
switch (ability.getSpellAbilityType()) {
|
||||||
|
case ADVENTURE_SPELL:
|
||||||
|
return this.getSpellCard().cast(game, fromZone, ability, controllerId);
|
||||||
|
default:
|
||||||
|
this.getSpellCard().getSpellAbility().setControllerId(controllerId);
|
||||||
|
return super.cast(game, fromZone, ability, controllerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Abilities<Ability> getAbilities() {
|
||||||
|
Abilities<Ability> allAbilities = new AbilitiesImpl<>();
|
||||||
|
allAbilities.addAll(spellCard.getAbilities());
|
||||||
|
allAbilities.addAll(super.getAbilities());
|
||||||
|
return allAbilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Abilities<Ability> getAbilities(Game game) {
|
||||||
|
Abilities<Ability> allAbilities = new AbilitiesImpl<>();
|
||||||
|
allAbilities.addAll(spellCard.getAbilities(game));
|
||||||
|
allAbilities.addAll(super.getAbilities(game));
|
||||||
|
return allAbilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOwnerId(UUID ownerId) {
|
||||||
|
super.setOwnerId(ownerId);
|
||||||
|
abilities.setControllerId(ownerId);
|
||||||
|
spellCard.getAbilities().setControllerId(ownerId);
|
||||||
|
spellCard.setOwnerId(ownerId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
20
Mage/src/main/java/mage/cards/AdventureCardSpell.java
Normal file
20
Mage/src/main/java/mage/cards/AdventureCardSpell.java
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package mage.cards;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author phulin
|
||||||
|
*/
|
||||||
|
public interface AdventureCardSpell extends Card {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
AdventureCardSpell copy();
|
||||||
|
|
||||||
|
void setParentCard(AdventureCard card);
|
||||||
|
|
||||||
|
AdventureCard getParentCard();
|
||||||
|
}
|
155
Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java
Normal file
155
Mage/src/main/java/mage/cards/AdventureCardSpellImpl.java
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/*
|
||||||
|
* To change this license header, choose License Headers in Project Properties.
|
||||||
|
* To change this template file, choose Tools | Templates
|
||||||
|
* and open the template in the editor.
|
||||||
|
*/
|
||||||
|
package mage.cards;
|
||||||
|
|
||||||
|
import mage.abilities.Modes;
|
||||||
|
import mage.abilities.SpellAbility;
|
||||||
|
import mage.abilities.effects.common.ExileAdventureSpellEffect;
|
||||||
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.SpellAbilityType;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.ExileZone;
|
||||||
|
import mage.game.Game;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author phulin
|
||||||
|
*/
|
||||||
|
public class AdventureCardSpellImpl extends CardImpl implements AdventureCardSpell {
|
||||||
|
|
||||||
|
private AdventureCard adventureCardParent;
|
||||||
|
|
||||||
|
public AdventureCardSpellImpl(UUID ownerId, CardSetInfo setInfo, String adventureName, CardType[] cardTypes, String costs, AdventureCard adventureCardParent) {
|
||||||
|
super(ownerId, setInfo, cardTypes, costs, SpellAbilityType.ADVENTURE_SPELL);
|
||||||
|
this.subtype.add(SubType.ADVENTURE);
|
||||||
|
|
||||||
|
AdventureCardSpellAbility newSpellAbility = new AdventureCardSpellAbility(getSpellAbility());
|
||||||
|
newSpellAbility.setName(adventureName, costs);
|
||||||
|
newSpellAbility.addEffect(ExileAdventureSpellEffect.getInstance());
|
||||||
|
newSpellAbility.setCardName(adventureName);
|
||||||
|
this.replaceSpellAbility(newSpellAbility);
|
||||||
|
spellAbility = newSpellAbility;
|
||||||
|
|
||||||
|
this.setName(adventureName);
|
||||||
|
this.adventureCardParent = adventureCardParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AdventureCardSpellImpl(final AdventureCardSpellImpl card) {
|
||||||
|
super(card);
|
||||||
|
this.adventureCardParent = card.adventureCardParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getOwnerId() {
|
||||||
|
return adventureCardParent.getOwnerId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getImageName() {
|
||||||
|
return adventureCardParent.getImageName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExpansionSetCode() {
|
||||||
|
return adventureCardParent.getExpansionSetCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCardNumber() {
|
||||||
|
return adventureCardParent.getCardNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveToZone(Zone toZone, UUID sourceId, Game game, boolean flag, List<UUID> appliedEffects) {
|
||||||
|
return adventureCardParent.moveToZone(toZone, sourceId, game, flag, appliedEffects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveToExile(UUID exileId, String name, UUID sourceId, Game game, List<UUID> appliedEffects) {
|
||||||
|
return adventureCardParent.moveToExile(exileId, name, sourceId, game, appliedEffects);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AdventureCard getMainCard() {
|
||||||
|
return adventureCardParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setZone(Zone zone, Game game) {
|
||||||
|
game.setZone(adventureCardParent.getId(), zone);
|
||||||
|
game.setZone(adventureCardParent.getSpellCard().getId(), zone);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AdventureCardSpell copy() {
|
||||||
|
return new AdventureCardSpellImpl(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setParentCard(AdventureCard card) {
|
||||||
|
this.adventureCardParent = card;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AdventureCard getParentCard() {
|
||||||
|
return this.adventureCardParent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AdventureCardSpellAbility extends SpellAbility {
|
||||||
|
public AdventureCardSpellAbility(final SpellAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ActivationStatus canActivate(UUID playerId, Game game) {
|
||||||
|
ExileZone adventureExileZone = game.getExile().getExileZone(ExileAdventureSpellEffect.adventureExileId(playerId, game));
|
||||||
|
Card spellCard = game.getCard(this.getSourceId());
|
||||||
|
if (spellCard != null && spellCard instanceof AdventureCardSpell) {
|
||||||
|
Card card = ((AdventureCardSpell) spellCard).getParentCard();
|
||||||
|
if (adventureExileZone != null && adventureExileZone.contains(card.getId())) {
|
||||||
|
return ActivationStatus.getFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.canActivate(playerId, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name, String costs) {
|
||||||
|
this.name = "Adventure — " + name + " " + costs;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule(boolean all) {
|
||||||
|
return this.getRule();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
StringBuilder sbRule = new StringBuilder();
|
||||||
|
sbRule.append("Adventure — ");
|
||||||
|
sbRule.append(this.getCardName());
|
||||||
|
sbRule.append(" ");
|
||||||
|
sbRule.append(manaCosts.getText());
|
||||||
|
sbRule.append(" — ");
|
||||||
|
Modes modes = this.getModes();
|
||||||
|
if (modes.size() <= 1) {
|
||||||
|
sbRule.append(modes.getMode().getEffects().getTextStartingUpperCase(modes.getMode()));
|
||||||
|
} else {
|
||||||
|
sbRule.append(getModes().getText());
|
||||||
|
}
|
||||||
|
sbRule.append(" <i>(Then exile this card. You may cast the creature later from exile.)</i>");
|
||||||
|
return sbRule.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SpellAbility copy() {
|
||||||
|
return new AdventureCardSpellAbility(this);
|
||||||
|
}
|
||||||
|
}
|
|
@ -150,7 +150,7 @@ public interface Card extends MageObject {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @return The main card of a split half card, otherwise the card itself is
|
* @return The main card of a split half card or adventure spell card, otherwise the card itself is
|
||||||
* returned
|
* returned
|
||||||
*/
|
*/
|
||||||
Card getMainCard();
|
Card getMainCard();
|
||||||
|
|
|
@ -505,6 +505,9 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
stackObject = game.getStack().getSpell(((SplitCard) this).getRightHalfCard().getId());
|
stackObject = game.getStack().getSpell(((SplitCard) this).getRightHalfCard().getId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (stackObject == null && (this instanceof AdventureCard)) {
|
||||||
|
stackObject = game.getStack().getSpell(((AdventureCard) this).getSpellCard().getId());
|
||||||
|
}
|
||||||
if (stackObject == null) {
|
if (stackObject == null) {
|
||||||
stackObject = game.getStack().getSpell(getId());
|
stackObject = game.getStack().getSpell(getId());
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ public enum SpellAbilityType {
|
||||||
SPLIT_RIGHT("RightSplit SpellAbility"),
|
SPLIT_RIGHT("RightSplit SpellAbility"),
|
||||||
MODE("Mode SpellAbility"),
|
MODE("Mode SpellAbility"),
|
||||||
SPLICE("Spliced SpellAbility"),
|
SPLICE("Spliced SpellAbility"),
|
||||||
ADVENTURE("Adventure SpellAbility");
|
ADVENTURE_SPELL("Adventure SpellAbility");
|
||||||
|
|
||||||
private final String text;
|
private final String text;
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,27 @@
|
||||||
package mage.filter.predicate.mageobject;
|
package mage.filter.predicate.mageobject;
|
||||||
|
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
|
import mage.cards.AdventureCard;
|
||||||
|
import mage.cards.Card;
|
||||||
import mage.filter.predicate.Predicate;
|
import mage.filter.predicate.Predicate;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.game.stack.Spell;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
* TODO: make this actually work
|
|
||||||
*/
|
*/
|
||||||
public enum AdventurePredicate implements Predicate<MageObject> {
|
public enum AdventurePredicate implements Predicate<MageObject> {
|
||||||
instance;
|
instance;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(MageObject input, Game game) {
|
public boolean apply(MageObject input, Game game) {
|
||||||
return false;
|
if (input instanceof Spell) {
|
||||||
|
return ((Spell) input).getCard() instanceof AdventureCard;
|
||||||
|
} else if (input instanceof Card) {
|
||||||
|
return input instanceof AdventureCard;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -3,6 +3,8 @@ package mage.filter.predicate.other;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import mage.cards.AdventureCard;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.SplitCard;
|
import mage.cards.SplitCard;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
|
@ -76,6 +78,14 @@ public class CardTextPredicate implements Predicate<Card> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (input instanceof AdventureCard) {
|
||||||
|
for (String rule : ((AdventureCard) input).getSpellCard().getRules(game)) {
|
||||||
|
if (rule.toLowerCase(Locale.ENGLISH).contains(token)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
for (String rule : input.getRules(game)) {
|
for (String rule : input.getRules(game)) {
|
||||||
if (rule.toLowerCase(Locale.ENGLISH).contains(token)) {
|
if (rule.toLowerCase(Locale.ENGLISH).contains(token)) {
|
||||||
found = true;
|
found = true;
|
||||||
|
|
|
@ -230,6 +230,12 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
gameCards.put(rightCard.getId(), rightCard);
|
gameCards.put(rightCard.getId(), rightCard);
|
||||||
state.addCard(rightCard);
|
state.addCard(rightCard);
|
||||||
}
|
}
|
||||||
|
if (card instanceof AdventureCard) {
|
||||||
|
Card spellCard = ((AdventureCard) card).getSpellCard();
|
||||||
|
spellCard.setOwnerId(ownerId);
|
||||||
|
gameCards.put(spellCard.getId(), spellCard);
|
||||||
|
state.addCard(spellCard);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1767,7 +1773,7 @@ public abstract class GameImpl implements Game, Serializable {
|
||||||
Iterator<Card> copiedCards = this.getState().getCopiedCards().iterator();
|
Iterator<Card> copiedCards = this.getState().getCopiedCards().iterator();
|
||||||
while (copiedCards.hasNext()) {
|
while (copiedCards.hasNext()) {
|
||||||
Card card = copiedCards.next();
|
Card card = copiedCards.next();
|
||||||
if (card instanceof SplitCardHalf) {
|
if (card instanceof SplitCardHalf || card instanceof AdventureCardSpell) {
|
||||||
continue; // only the main card is moves, not the halves
|
continue; // only the main card is moves, not the halves
|
||||||
}
|
}
|
||||||
Zone zone = state.getZone(card.getId());
|
Zone zone = state.getZone(card.getId());
|
||||||
|
|
|
@ -5,6 +5,7 @@ import mage.abilities.*;
|
||||||
import mage.abilities.effects.ContinuousEffect;
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
import mage.abilities.effects.ContinuousEffects;
|
import mage.abilities.effects.ContinuousEffects;
|
||||||
import mage.abilities.effects.Effect;
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.cards.AdventureCard;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.SplitCard;
|
import mage.cards.SplitCard;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
@ -811,6 +812,9 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
removeCopiedCard(((SplitCard) card).getLeftHalfCard());
|
removeCopiedCard(((SplitCard) card).getLeftHalfCard());
|
||||||
removeCopiedCard(((SplitCard) card).getRightHalfCard());
|
removeCopiedCard(((SplitCard) card).getRightHalfCard());
|
||||||
}
|
}
|
||||||
|
if (card instanceof AdventureCard) {
|
||||||
|
removeCopiedCard(((AdventureCard) card).getSpellCard());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1166,6 +1170,11 @@ public class GameState implements Serializable, Copyable<GameState> {
|
||||||
copiedCards.put(rightCard.getId(), rightCard);
|
copiedCards.put(rightCard.getId(), rightCard);
|
||||||
addCard(rightCard);
|
addCard(rightCard);
|
||||||
}
|
}
|
||||||
|
if (copiedCard instanceof AdventureCard) {
|
||||||
|
Card spellCard = ((AdventureCard) copiedCard).getSpellCard();
|
||||||
|
copiedCards.put(spellCard.getId(), spellCard);
|
||||||
|
addCard(spellCard);
|
||||||
|
}
|
||||||
return copiedCard;
|
return copiedCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
import mage.abilities.keyword.RetraceAbility;
|
import mage.abilities.keyword.RetraceAbility;
|
||||||
|
import mage.cards.AdventureCard;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
@ -42,7 +43,14 @@ class WrennAndSixEmblemEffect extends ContinuousEffectImpl {
|
||||||
}
|
}
|
||||||
for (UUID cardId : controller.getGraveyard()) {
|
for (UUID cardId : controller.getGraveyard()) {
|
||||||
Card card = game.getCard(cardId);
|
Card card = game.getCard(cardId);
|
||||||
if (card == null || !card.isInstantOrSorcery()) {
|
if (card == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (card instanceof AdventureCard) {
|
||||||
|
// Adventure cards are castable per https://twitter.com/elishffrn/status/1179047911729946624
|
||||||
|
card = ((AdventureCard) card).getSpellCard();
|
||||||
|
}
|
||||||
|
if (!card.isInstantOrSorcery()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
Ability ability = new RetraceAbility(card);
|
Ability ability = new RetraceAbility(card);
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
|
|
||||||
package mage.game.permanent;
|
package mage.game.permanent;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.abilities.Abilities;
|
import mage.abilities.Abilities;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.SpellAbility;
|
||||||
import mage.abilities.costs.mana.ManaCost;
|
import mage.abilities.costs.mana.ManaCost;
|
||||||
import mage.abilities.costs.mana.ManaCosts;
|
import mage.abilities.costs.mana.ManaCosts;
|
||||||
import mage.abilities.keyword.TransformAbility;
|
import mage.abilities.keyword.TransformAbility;
|
||||||
|
import mage.cards.AdventureCard;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.LevelerCard;
|
import mage.cards.LevelerCard;
|
||||||
|
import mage.constants.SpellAbilityType;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
|
|
||||||
|
@ -87,6 +92,18 @@ public class PermanentCard extends PermanentImpl {
|
||||||
} else {
|
} else {
|
||||||
this.abilities = card.getAbilities().copy();
|
this.abilities = card.getAbilities().copy();
|
||||||
}
|
}
|
||||||
|
if (card instanceof AdventureCard) {
|
||||||
|
// Adventure card spell abilities should not appear on permanents.
|
||||||
|
List<Ability> toRemove = new ArrayList<Ability>();
|
||||||
|
for (Ability ability : this.abilities) {
|
||||||
|
if (ability instanceof SpellAbility) {
|
||||||
|
if (((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.ADVENTURE_SPELL) {
|
||||||
|
toRemove.add(ability);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toRemove.forEach(ability -> this.abilities.remove(ability));
|
||||||
|
}
|
||||||
this.abilities.setControllerId(this.controllerId);
|
this.abilities.setControllerId(this.controllerId);
|
||||||
this.abilities.setSourceId(objectId);
|
this.abilities.setSourceId(objectId);
|
||||||
this.cardType.clear();
|
this.cardType.clear();
|
||||||
|
|
|
@ -3215,6 +3215,37 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Ability> cardPlayableAbilities(Game game, Card card, boolean setControllerId) {
|
||||||
|
List<Ability> playable = new ArrayList();
|
||||||
|
if (card != null) {
|
||||||
|
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
|
||||||
|
if (!ability.canActivate(playerId, game).canActivate()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
UUID savedControllerId = null;
|
||||||
|
if (setControllerId) {
|
||||||
|
// For when owner != caster, e.g. with Psychic Intrusion and similar effects.
|
||||||
|
savedControllerId = getId();
|
||||||
|
ability.setControllerId(getId());
|
||||||
|
}
|
||||||
|
if (ability instanceof SpellAbility
|
||||||
|
&& null != game.getContinuousEffects().asThough(card.getId(),
|
||||||
|
AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, ability, getId(), game)) {
|
||||||
|
playable.add(ability);
|
||||||
|
} else if (ability instanceof PlayLandAbility
|
||||||
|
&& null != game.getContinuousEffects().asThough(card.getId(),
|
||||||
|
AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, card.getSpellAbility(), getId(), game)) {
|
||||||
|
playable.add(ability);
|
||||||
|
}
|
||||||
|
if (setControllerId) {
|
||||||
|
ability.setControllerId(savedControllerId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return playable;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Ability> getPlayable(Game game, boolean hidden) {
|
public List<Ability> getPlayable(Game game, boolean hidden) {
|
||||||
return getPlayable(game, hidden, Zone.ALL, true);
|
return getPlayable(game, hidden, Zone.ALL, true);
|
||||||
|
@ -3277,6 +3308,11 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
splitCard.getRightHalfCard().getAbilities(), availableMana, playable);
|
splitCard.getRightHalfCard().getAbilities(), availableMana, playable);
|
||||||
getPlayableFromGraveyardCard(game, splitCard, splitCard.getSharedAbilities(),
|
getPlayableFromGraveyardCard(game, splitCard, splitCard.getSharedAbilities(),
|
||||||
availableMana, playable);
|
availableMana, playable);
|
||||||
|
} else if (card instanceof AdventureCard) {
|
||||||
|
AdventureCard adventureCard = (AdventureCard) card;
|
||||||
|
getPlayableFromGraveyardCard(game, adventureCard.getSpellCard(),
|
||||||
|
adventureCard.getSpellCard().getAbilities(), availableMana, playable);
|
||||||
|
getPlayableFromGraveyardCard(game, adventureCard, adventureCard.getAbilities(), availableMana, playable);
|
||||||
} else {
|
} else {
|
||||||
getPlayableFromGraveyardCard(game, card, card.getAbilities(), availableMana, playable);
|
getPlayableFromGraveyardCard(game, card, card.getAbilities(), availableMana, playable);
|
||||||
}
|
}
|
||||||
|
@ -3291,20 +3327,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (fromAll || fromZone == Zone.EXILED) {
|
if (fromAll || fromZone == Zone.EXILED) {
|
||||||
for (ExileZone exile : game.getExile().getExileZones()) {
|
for (ExileZone exile : game.getExile().getExileZones()) {
|
||||||
for (Card card : exile.getCards(game)) {
|
for (Card card : exile.getCards(game)) {
|
||||||
if (null != game.getContinuousEffects().asThough(card.getId(),
|
playable.addAll(cardPlayableAbilities(game, card, true));
|
||||||
AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game)) {
|
|
||||||
for (Ability ability : card.getAbilities()) {
|
|
||||||
if (ability.getZone().match(Zone.HAND)) {
|
|
||||||
ability.setControllerId(this.getId()); // controller must be set for case owner != caster
|
|
||||||
if (ability instanceof ActivatedAbility) {
|
|
||||||
if (((ActivatedAbility) ability).canActivate(playerId, game).canActivate()) {
|
|
||||||
playable.add(ability);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ability.setControllerId(card.getOwnerId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3313,14 +3336,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (fromAll) {
|
if (fromAll) {
|
||||||
for (Cards revealedCards : game.getState().getRevealed().values()) {
|
for (Cards revealedCards : game.getState().getRevealed().values()) {
|
||||||
for (Card card : revealedCards.getCards(game)) {
|
for (Card card : revealedCards.getCards(game)) {
|
||||||
if (null != game.getContinuousEffects().asThough(card.getId(),
|
playable.addAll(cardPlayableAbilities(game, card, false));
|
||||||
AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, null, this.getId(), game)) {
|
|
||||||
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
|
|
||||||
if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) {
|
|
||||||
playable.add(ability);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3332,14 +3348,7 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
if (player != null) {
|
if (player != null) {
|
||||||
if (/*player.isTopCardRevealed() &&*/player.getLibrary().hasCards()) {
|
if (/*player.isTopCardRevealed() &&*/player.getLibrary().hasCards()) {
|
||||||
Card card = player.getLibrary().getFromTop(game);
|
Card card = player.getLibrary().getFromTop(game);
|
||||||
if (card != null && null != game.getContinuousEffects().asThough(card.getId(),
|
playable.addAll(cardPlayableAbilities(game, card, false));
|
||||||
AsThoughEffectType.PLAY_FROM_NOT_OWN_HAND_ZONE, card.getSpellAbility(), getId(), game)) {
|
|
||||||
for (ActivatedAbility ability : card.getAbilities().getActivatedAbilities(Zone.HAND)) {
|
|
||||||
if (ability instanceof SpellAbility || ability instanceof PlayLandAbility) {
|
|
||||||
playable.add(ability);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3413,10 +3422,10 @@ public abstract class PlayerImpl implements Player, Serializable {
|
||||||
playableObjects.add(ability.getSourceId());
|
playableObjects.add(ability.getSourceId());
|
||||||
|
|
||||||
// main card must be marked playable in GUI
|
// main card must be marked playable in GUI
|
||||||
MageObject object = game.getObject(ability.getSourceId());
|
Card card = game.getCard(ability.getSourceId());
|
||||||
if (object instanceof SplitCardHalf) {
|
if (card != null && card.getMainCard().getId() != card.getId()) {
|
||||||
UUID splitCardId = ((Card) object).getMainCard().getId();
|
UUID mainCardId = card.getMainCard().getId();
|
||||||
playableObjects.add(splitCardId);
|
playableObjects.add(mainCardId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue