mirror of
https://github.com/magefree/mage.git
synced 2025-12-20 02:30:08 -08:00
Merge pull request #14061
* move setPT to Card * Create DoubleFacedCard and DoubleFacedCardHalf to share code between … * Create Transforming Double Face Card class * allow putting either permanent side of a double faced card to the bat… * refactor exile and return transforming card * update ModalDoubleFacedCard references to DoubleFacedCard where relev… * update for GUI * refactor a disturb card * refactor more disturb cards for test coverage * refactor a transform card * refactor more transform cards for test coverage * fix Archangel Avacyn * fix cantPlayTDFCBackSide inconsistency * fix Double Faced Cards having triggers and static abilities when tran… * fix Double Faced Cards card view erroring when flipping in client * fix test_Copy_AsSpell_Backside inconsistency * enable Spider-Man MDFC * convert TDFC with saga as the front and add card references to Transf… * refactor More Than Meets the Eye Card * refactor a battle * refactor a craft card * update comment on PeterParkerTest * Merge branch 'master' into rework-dfc * fix Saga TDFC Azusa's Many Journeys * fix double faced cards adding permanent triggers / effects to game * move permanents entering map into Battlefield * convert Room cards for new Permanent structure * fix disturb not exiling * Merge branch 'master' into rework-dfc * fix Eddie Brock Power/Toughness * fix Miles Morales ability on main card * fix verify conditions for siege and day/night cards * change room characteristics to text effect to match game rules * update verify test to skip DoubleFacedCard in missing card test * accidentally removed transform condition * Merge branch 'master' into rework-dfc * fix verify * CardUtil - remove unnecessary line from castSingle method
This commit is contained in:
parent
29557f4334
commit
69e20b1061
121 changed files with 3020 additions and 2225 deletions
|
|
@ -940,8 +940,13 @@ public abstract class CardPanel extends MagePermanent implements ComponentListen
|
||||||
private void setGameCardSides(CardView gameCard) {
|
private void setGameCardSides(CardView gameCard) {
|
||||||
if (this.cardSideMain == null) {
|
if (this.cardSideMain == null) {
|
||||||
// new card
|
// new card
|
||||||
this.cardSideMain = gameCard;
|
if (gameCard instanceof PermanentView) {
|
||||||
this.cardSideOther = gameCard.getSecondCardFace();
|
this.cardSideMain = gameCard;
|
||||||
|
this.cardSideOther = gameCard.isTransformed() ? ((PermanentView) gameCard).getOriginal() : gameCard.getSecondCardFace();
|
||||||
|
} else {
|
||||||
|
this.cardSideMain = gameCard;
|
||||||
|
this.cardSideOther = gameCard.getSecondCardFace();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// updated card
|
// updated card
|
||||||
if (this.cardSideMain.getName().equals(gameCard.getName())) {
|
if (this.cardSideMain.getName().equals(gameCard.getName())) {
|
||||||
|
|
|
||||||
|
|
@ -558,12 +558,12 @@ public class DownloadPicturesService extends DefaultBoundedRangeModel implements
|
||||||
);
|
);
|
||||||
allCardsUrls.add(url);
|
allCardsUrls.add(url);
|
||||||
}
|
}
|
||||||
if (card.isModalDoubleFacedCard()) {
|
if (card.isDoubleFacedCard()) {
|
||||||
if (card.getModalDoubleFacedSecondSideName() == null || card.getModalDoubleFacedSecondSideName().trim().isEmpty()) {
|
if (card.getDoubleFacedSecondSideName() == null || card.getDoubleFacedSecondSideName().trim().isEmpty()) {
|
||||||
throw new IllegalStateException("MDF card can't have empty name.");
|
throw new IllegalStateException("MDF card can't have empty name.");
|
||||||
}
|
}
|
||||||
CardDownloadData cardDownloadData = new CardDownloadData(
|
CardDownloadData cardDownloadData = new CardDownloadData(
|
||||||
card.getModalDoubleFacedSecondSideName(),
|
card.getDoubleFacedSecondSideName(),
|
||||||
card.getSetCode(),
|
card.getSetCode(),
|
||||||
card.getCardNumber(),
|
card.getCardNumber(),
|
||||||
card.usesVariousArt(),
|
card.usesVariousArt(),
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import mage.game.command.Dungeon;
|
||||||
import mage.game.command.Emblem;
|
import mage.game.command.Emblem;
|
||||||
import mage.game.command.Plane;
|
import mage.game.command.Plane;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.permanent.PermanentCard;
|
||||||
import mage.game.permanent.PermanentToken;
|
import mage.game.permanent.PermanentToken;
|
||||||
import mage.game.permanent.token.Token;
|
import mage.game.permanent.token.Token;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
|
|
@ -116,7 +117,7 @@ public class CardView extends SimpleCardView {
|
||||||
protected List<String> rightSplitRules;
|
protected List<String> rightSplitRules;
|
||||||
protected String rightSplitTypeLine;
|
protected String rightSplitTypeLine;
|
||||||
|
|
||||||
protected boolean isModalDoubleFacedCard;
|
protected boolean isDoubleFacedCard;
|
||||||
|
|
||||||
protected ArtRect artRect = ArtRect.NORMAL;
|
protected ArtRect artRect = ArtRect.NORMAL;
|
||||||
|
|
||||||
|
|
@ -238,7 +239,7 @@ public class CardView extends SimpleCardView {
|
||||||
this.rightSplitRules = cardView.rightSplitRules == null ? null : new ArrayList<>(cardView.rightSplitRules);
|
this.rightSplitRules = cardView.rightSplitRules == null ? null : new ArrayList<>(cardView.rightSplitRules);
|
||||||
this.rightSplitTypeLine = cardView.rightSplitTypeLine;
|
this.rightSplitTypeLine = cardView.rightSplitTypeLine;
|
||||||
|
|
||||||
this.isModalDoubleFacedCard = cardView.isModalDoubleFacedCard;
|
this.isDoubleFacedCard = cardView.isDoubleFacedCard;
|
||||||
|
|
||||||
this.artRect = cardView.artRect;
|
this.artRect = cardView.artRect;
|
||||||
this.targets = cardView.targets == null ? null : new ArrayList<>(cardView.targets);
|
this.targets = cardView.targets == null ? null : new ArrayList<>(cardView.targets);
|
||||||
|
|
@ -428,12 +429,18 @@ public class CardView extends SimpleCardView {
|
||||||
this.manaCostLeftStr = splitCard.getLeftHalfCard().getManaCostSymbols();
|
this.manaCostLeftStr = splitCard.getLeftHalfCard().getManaCostSymbols();
|
||||||
this.manaCostRightStr = splitCard.getRightHalfCard().getManaCostSymbols();
|
this.manaCostRightStr = splitCard.getRightHalfCard().getManaCostSymbols();
|
||||||
} else if (card instanceof ModalDoubleFacedCard) {
|
} else if (card instanceof ModalDoubleFacedCard) {
|
||||||
this.isModalDoubleFacedCard = true;
|
this.isDoubleFacedCard = true;
|
||||||
ModalDoubleFacedCard mainCard = ((ModalDoubleFacedCard) card);
|
DoubleFacedCard mainCard = ((DoubleFacedCard) card);
|
||||||
fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName();
|
fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName();
|
||||||
this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols();
|
this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols();
|
||||||
this.manaCostRightStr = mainCard.getRightHalfCard().getManaCostSymbols();
|
this.manaCostRightStr = mainCard.getRightHalfCard().getManaCostSymbols();
|
||||||
} else if (card instanceof CardWithSpellOption) {
|
} else if (card instanceof TransformingDoubleFacedCard) {
|
||||||
|
this.isDoubleFacedCard = true;
|
||||||
|
DoubleFacedCard mainCard = ((DoubleFacedCard) card);
|
||||||
|
fullCardName = mainCard.getLeftHalfCard().getName() + MockCard.MODAL_DOUBLE_FACES_NAME_SEPARATOR + mainCard.getRightHalfCard().getName();
|
||||||
|
this.manaCostLeftStr = mainCard.getLeftHalfCard().getManaCostSymbols();
|
||||||
|
this.manaCostRightStr = new ArrayList<>();
|
||||||
|
} else if (card instanceof CardWithSpellOption) {
|
||||||
this.isSplitCard = true;
|
this.isSplitCard = true;
|
||||||
CardWithSpellOption mainCard = ((CardWithSpellOption) card);
|
CardWithSpellOption mainCard = ((CardWithSpellOption) card);
|
||||||
leftSplitName = mainCard.getName();
|
leftSplitName = mainCard.getName();
|
||||||
|
|
@ -531,13 +538,21 @@ public class CardView extends SimpleCardView {
|
||||||
|
|
||||||
this.extraDeckCard = card.isExtraDeckCard();
|
this.extraDeckCard = card.isExtraDeckCard();
|
||||||
|
|
||||||
|
// TODO: can probably remove this after tdfc rework
|
||||||
// transformable, double faces cards
|
// transformable, double faces cards
|
||||||
this.transformable = card.isTransformable();
|
if (!(sourceCard.getMainCard() instanceof DoubleFacedCard)) {
|
||||||
|
this.transformable = card.isTransformable();
|
||||||
|
|
||||||
Card secondSideCard = card.getSecondCardFace();
|
Card secondSideCard = card.getSecondCardFace();
|
||||||
if (secondSideCard != null) {
|
if (secondSideCard != null) {
|
||||||
|
this.secondCardFace = new CardView(secondSideCard, game);
|
||||||
|
this.alternateName = secondCardFace.getName();
|
||||||
|
}
|
||||||
|
} else if (card instanceof PermanentCard && card.isTransformable()) {
|
||||||
|
this.transformable = card.isTransformable();
|
||||||
|
Card secondSideCard = (Card) ((PermanentCard) card).getOtherFace();
|
||||||
this.secondCardFace = new CardView(secondSideCard, game);
|
this.secondCardFace = new CardView(secondSideCard, game);
|
||||||
this.alternateName = secondCardFace.getName();
|
this.alternateName = secondSideCard.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.flipCard = card.isFlipCard();
|
this.flipCard = card.isFlipCard();
|
||||||
|
|
@ -545,11 +560,11 @@ public class CardView extends SimpleCardView {
|
||||||
this.alternateName = card.getFlipCardName();
|
this.alternateName = card.getFlipCardName();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (card instanceof ModalDoubleFacedCard) {
|
if (card instanceof DoubleFacedCard) {
|
||||||
this.transformable = true; // enable GUI day/night button
|
this.transformable = true; // enable GUI day/night button
|
||||||
ModalDoubleFacedCard mdfCard = (ModalDoubleFacedCard) card;
|
DoubleFacedCard doubleFacedCard = (DoubleFacedCard) card;
|
||||||
this.secondCardFace = new CardView(mdfCard.getRightHalfCard(), game);
|
this.secondCardFace = new CardView(doubleFacedCard.getRightHalfCard(), game);
|
||||||
this.alternateName = mdfCard.getRightHalfCard().getName();
|
this.alternateName = doubleFacedCard.getRightHalfCard().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
Card meldsToCard = card.getMeldsToCard();
|
Card meldsToCard = card.getMeldsToCard();
|
||||||
|
|
|
||||||
|
|
@ -206,9 +206,9 @@ public class TinyLeaders extends Constructed {
|
||||||
if (card instanceof SplitCard) {
|
if (card instanceof SplitCard) {
|
||||||
costs.add(((SplitCard) card).getLeftHalfCard().getManaValue());
|
costs.add(((SplitCard) card).getLeftHalfCard().getManaValue());
|
||||||
costs.add(((SplitCard) card).getRightHalfCard().getManaValue());
|
costs.add(((SplitCard) card).getRightHalfCard().getManaValue());
|
||||||
} else if (card instanceof ModalDoubleFacedCard) {
|
} else if (card instanceof DoubleFacedCard) {
|
||||||
costs.add(((ModalDoubleFacedCard) card).getLeftHalfCard().getManaValue());
|
costs.add(((DoubleFacedCard) card).getLeftHalfCard().getManaValue());
|
||||||
costs.add(((ModalDoubleFacedCard) card).getRightHalfCard().getManaValue());
|
costs.add(((DoubleFacedCard) card).getRightHalfCard().getManaValue());
|
||||||
} else {
|
} else {
|
||||||
costs.add(card.getManaValue());
|
costs.add(card.getManaValue());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,66 +1,83 @@
|
||||||
package mage.cards.a;
|
package mage.cards.a;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.DiesCreatureTriggeredAbility;
|
import mage.abilities.common.DiesCreatureTriggeredAbility;
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
|
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
|
||||||
import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility;
|
import mage.abilities.common.delayed.AtTheBeginOfNextUpkeepDelayedTriggeredAbility;
|
||||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
||||||
|
import mage.abilities.effects.common.DamageAllEffect;
|
||||||
|
import mage.abilities.effects.common.DamagePlayersEffect;
|
||||||
import mage.abilities.effects.common.TransformSourceEffect;
|
import mage.abilities.effects.common.TransformSourceEffect;
|
||||||
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
|
import mage.abilities.effects.common.continuous.GainAbilityControlledEffect;
|
||||||
import mage.abilities.keyword.*;
|
import mage.abilities.keyword.*;
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
|
import mage.filter.FilterPermanent;
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
import mage.filter.common.FilterCreaturePermanent;
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
import mage.filter.predicate.Predicates;
|
import mage.filter.predicate.Predicates;
|
||||||
|
import mage.filter.predicate.mageobject.AnotherPredicate;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author fireshoes
|
* @author fireshoes
|
||||||
*/
|
*/
|
||||||
public final class ArchangelAvacyn extends CardImpl {
|
public final class ArchangelAvacyn extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
private static final FilterCreaturePermanent filter = new FilterCreaturePermanent("a non-Angel creature you control");
|
private static final FilterCreaturePermanent nonAngelFilter = new FilterCreaturePermanent("a non-Angel creature you control");
|
||||||
|
private static final FilterPermanent otherCreatureFilter = new FilterCreaturePermanent("other creature");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(Predicates.not(SubType.ANGEL.getPredicate()));
|
otherCreatureFilter.add(AnotherPredicate.instance);
|
||||||
filter.add(TargetController.YOU.getControllerPredicate());
|
nonAngelFilter.add(Predicates.not(SubType.ANGEL.getPredicate()));
|
||||||
|
nonAngelFilter.add(TargetController.YOU.getControllerPredicate());
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArchangelAvacyn(UUID ownerId, CardSetInfo setInfo) {
|
public ArchangelAvacyn(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{W}{W}");
|
super(ownerId, setInfo,
|
||||||
|
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "{3}{W}{W}",
|
||||||
|
"Avacyn, the Purifier",
|
||||||
|
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.ANGEL}, "R");
|
||||||
|
|
||||||
this.supertype.add(SuperType.LEGENDARY);
|
this.getLeftHalfCard().setPT(4, 4);
|
||||||
this.subtype.add(SubType.ANGEL);
|
this.getRightHalfCard().setPT(6, 5);
|
||||||
this.power = new MageInt(4);
|
|
||||||
this.toughness = new MageInt(4);
|
|
||||||
|
|
||||||
this.secondSideCardClazz = mage.cards.a.AvacynThePurifier.class;
|
|
||||||
|
|
||||||
// Flash
|
// Flash
|
||||||
this.addAbility(FlashAbility.getInstance());
|
this.addAbility(FlashAbility.getInstance());
|
||||||
|
|
||||||
// Flying
|
// Flying
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
// Vigilance
|
// Vigilance
|
||||||
this.addAbility(VigilanceAbility.getInstance());
|
this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance());
|
||||||
|
|
||||||
// When Archangel Avacyn enters the battlefield, creatures you control gain indestructible until end of turn.
|
// When Archangel Avacyn enters the battlefield, creatures you control gain indestructible until end of turn.
|
||||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect(
|
this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new GainAbilityControlledEffect(
|
||||||
IndestructibleAbility.getInstance(), Duration.EndOfTurn,
|
IndestructibleAbility.getInstance(), Duration.EndOfTurn,
|
||||||
StaticFilters.FILTER_PERMANENT_CREATURES
|
StaticFilters.FILTER_PERMANENT_CREATURES
|
||||||
), false));
|
), false));
|
||||||
|
|
||||||
// When a non-Angel creature you control dies, transform Archangel Avacyn at the beginning of the next upkeep.
|
// When a non-Angel creature you control dies, transform Archangel Avacyn at the beginning of the next upkeep.
|
||||||
this.addAbility(new TransformAbility());
|
this.getLeftHalfCard().addAbility(new DiesCreatureTriggeredAbility(
|
||||||
this.addAbility(new DiesCreatureTriggeredAbility(
|
|
||||||
new CreateDelayedTriggeredAbilityEffect(
|
new CreateDelayedTriggeredAbilityEffect(
|
||||||
new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new TransformSourceEffect())
|
new AtTheBeginOfNextUpkeepDelayedTriggeredAbility(new TransformSourceEffect())
|
||||||
).setText("transform {this} at the beginning of the next upkeep"), false, filter
|
).setText("transform {this} at the beginning of the next upkeep"), false, nonAngelFilter
|
||||||
).setTriggerPhrase("When a non-Angel creature you control dies, "));
|
).setTriggerPhrase("When a non-Angel creature you control dies, "));
|
||||||
|
|
||||||
|
// Avacyn, the Purifier
|
||||||
|
|
||||||
|
// Flying
|
||||||
|
this.getRightHalfCard().addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
|
// When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent.
|
||||||
|
Ability ability = new TransformIntoSourceTriggeredAbility(
|
||||||
|
new DamageAllEffect(3, "it", otherCreatureFilter)
|
||||||
|
);
|
||||||
|
ability.addEffect(new DamagePlayersEffect(3, TargetController.OPPONENT).setText("and each opponent"));
|
||||||
|
this.getRightHalfCard().addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArchangelAvacyn(final ArchangelAvacyn card) {
|
private ArchangelAvacyn(final ArchangelAvacyn card) {
|
||||||
|
|
|
||||||
|
|
@ -1,62 +0,0 @@
|
||||||
package mage.cards.a;
|
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
|
|
||||||
import mage.abilities.effects.common.DamageAllEffect;
|
|
||||||
import mage.abilities.effects.common.DamagePlayersEffect;
|
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.constants.SuperType;
|
|
||||||
import mage.constants.TargetController;
|
|
||||||
import mage.filter.FilterPermanent;
|
|
||||||
import mage.filter.common.FilterCreaturePermanent;
|
|
||||||
import mage.filter.predicate.mageobject.AnotherPredicate;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author fireshoes
|
|
||||||
*/
|
|
||||||
public final class AvacynThePurifier extends CardImpl {
|
|
||||||
|
|
||||||
private static final FilterPermanent filter = new FilterCreaturePermanent("other creature");
|
|
||||||
|
|
||||||
static {
|
|
||||||
filter.add(AnotherPredicate.instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AvacynThePurifier(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
|
|
||||||
this.supertype.add(SuperType.LEGENDARY);
|
|
||||||
this.subtype.add(SubType.ANGEL);
|
|
||||||
this.power = new MageInt(6);
|
|
||||||
this.toughness = new MageInt(5);
|
|
||||||
this.color.setRed(true);
|
|
||||||
|
|
||||||
// this card is the second face of double-faced card
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// Flying
|
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
|
||||||
|
|
||||||
// When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent.
|
|
||||||
Ability ability = new TransformIntoSourceTriggeredAbility(
|
|
||||||
new DamageAllEffect(3, "it", filter)
|
|
||||||
);
|
|
||||||
ability.addEffect(new DamagePlayersEffect(3, TargetController.OPPONENT).setText("and each opponent"));
|
|
||||||
this.addAbility(ability);
|
|
||||||
}
|
|
||||||
|
|
||||||
private AvacynThePurifier(final AvacynThePurifier card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AvacynThePurifier copy() {
|
|
||||||
return new AvacynThePurifier(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +1,51 @@
|
||||||
package mage.cards.a;
|
package mage.cards.a;
|
||||||
|
|
||||||
import java.util.UUID;
|
import mage.abilities.common.BecomesBlockedSourceTriggeredAbility;
|
||||||
|
|
||||||
import mage.abilities.common.SagaAbility;
|
import mage.abilities.common.SagaAbility;
|
||||||
import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect;
|
import mage.abilities.effects.common.ExileSagaAndReturnTransformedEffect;
|
||||||
import mage.abilities.effects.common.GainLifeEffect;
|
import mage.abilities.effects.common.GainLifeEffect;
|
||||||
|
import mage.abilities.effects.common.UntapLandsEffect;
|
||||||
import mage.abilities.effects.common.continuous.PlayAdditionalLandsControllerEffect;
|
import mage.abilities.effects.common.continuous.PlayAdditionalLandsControllerEffect;
|
||||||
import mage.abilities.keyword.TransformAbility;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
|
import mage.constants.CardType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.SagaChapter;
|
import mage.constants.SagaChapter;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import java.util.UUID;
|
||||||
import mage.constants.CardType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author weirddan455
|
* @author weirddan455
|
||||||
*/
|
*/
|
||||||
public final class AzusasManyJourneys extends CardImpl {
|
public final class AzusasManyJourneys extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
public AzusasManyJourneys(UUID ownerId, CardSetInfo setInfo) {
|
public AzusasManyJourneys(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "{1}{G}");
|
super(ownerId, setInfo,
|
||||||
|
new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.SAGA}, "{1}{G}",
|
||||||
|
"Likeness of the Seeker",
|
||||||
|
new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.MONK}, "G");
|
||||||
|
|
||||||
this.subtype.add(SubType.SAGA);
|
this.getRightHalfCard().setPT(3, 3);
|
||||||
this.secondSideCardClazz = mage.cards.l.LikenessOfTheSeeker.class;
|
|
||||||
|
|
||||||
// (As this Saga enters and after your draw step, add a lore counter.)
|
// (As this Saga enters and after your draw step, add a lore counter.)
|
||||||
SagaAbility sagaAbility = new SagaAbility(this);
|
SagaAbility sagaAbility = new SagaAbility(this.getLeftHalfCard());
|
||||||
|
|
||||||
// I — You may play an additional land this turn.
|
// I — You may play an additional land this turn.
|
||||||
sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_I, new PlayAdditionalLandsControllerEffect(1, Duration.EndOfTurn));
|
sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_I, new PlayAdditionalLandsControllerEffect(1, Duration.EndOfTurn));
|
||||||
|
|
||||||
// II — You gain 3 life.
|
// II — You gain 3 life.
|
||||||
sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_II, new GainLifeEffect(3));
|
sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_II, new GainLifeEffect(3));
|
||||||
|
|
||||||
// III — Exile this Saga, then return it to the battlefield transformed under your control.
|
// III — Exile this Saga, then return it to the battlefield transformed under your control.
|
||||||
this.addAbility(new TransformAbility());
|
sagaAbility.addChapterEffect(this.getLeftHalfCard(), SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect());
|
||||||
sagaAbility.addChapterEffect(this, SagaChapter.CHAPTER_III, new ExileSagaAndReturnTransformedEffect());
|
|
||||||
|
|
||||||
this.addAbility(sagaAbility);
|
this.getLeftHalfCard().addAbility(sagaAbility);
|
||||||
|
|
||||||
|
// Likeness of the Seeker
|
||||||
|
// Whenever Likeness of the Seeker becomes blocked, untap up to three lands you control.
|
||||||
|
this.getRightHalfCard().addAbility(new BecomesBlockedSourceTriggeredAbility(new UntapLandsEffect(3, true, true), false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private AzusasManyJourneys(final AzusasManyJourneys card) {
|
private AzusasManyJourneys(final AzusasManyJourneys card) {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
package mage.cards.b;
|
package mage.cards.b;
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
|
||||||
import mage.abilities.keyword.DisturbAbility;
|
import mage.abilities.keyword.DisturbAbility;
|
||||||
import mage.cards.CardImpl;
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
|
|
||||||
|
|
@ -13,19 +12,25 @@ import java.util.UUID;
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public final class BaithookAngler extends CardImpl {
|
public final class BaithookAngler extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
public BaithookAngler(UUID ownerId, CardSetInfo setInfo) {
|
public BaithookAngler(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{U}");
|
super(ownerId, setInfo,
|
||||||
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.PEASANT}, "{1}{U}",
|
||||||
this.subtype.add(SubType.HUMAN);
|
"Hook-Haunt Drifter",
|
||||||
this.subtype.add(SubType.PEASANT);
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U"
|
||||||
this.power = new MageInt(2);
|
);
|
||||||
this.toughness = new MageInt(1);
|
this.getLeftHalfCard().setPT(2, 1);
|
||||||
this.secondSideCardClazz = mage.cards.h.HookHauntDrifter.class;
|
this.getRightHalfCard().setPT(1, 2);
|
||||||
|
|
||||||
// Disturb {1}{U}
|
// Disturb {1}{U}
|
||||||
this.addAbility(new DisturbAbility(this, "{1}{U}"));
|
this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{1}{U}"));
|
||||||
|
|
||||||
|
// Flying
|
||||||
|
this.getRightHalfCard().addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
|
// If Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead.
|
||||||
|
this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
private BaithookAngler(final BaithookAngler card) {
|
private BaithookAngler(final BaithookAngler card) {
|
||||||
|
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
package mage.cards.b;
|
|
||||||
|
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
|
||||||
import mage.abilities.effects.common.continuous.BoostControlledEffect;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Duration;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author TheElk801
|
|
||||||
*/
|
|
||||||
public final class BelenonWarAnthem extends CardImpl {
|
|
||||||
|
|
||||||
public BelenonWarAnthem(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "");
|
|
||||||
|
|
||||||
this.color.setWhite(true);
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// Creatures you control get +1/+1.
|
|
||||||
this.addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield)));
|
|
||||||
}
|
|
||||||
|
|
||||||
private BelenonWarAnthem(final BelenonWarAnthem card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BelenonWarAnthem copy() {
|
|
||||||
return new BelenonWarAnthem(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,60 +0,0 @@
|
||||||
package mage.cards.b;
|
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.common.SimpleActivatedAbility;
|
|
||||||
import mage.abilities.costs.common.TapTargetCost;
|
|
||||||
import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect;
|
|
||||||
import mage.abilities.keyword.CrewAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Duration;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.filter.common.FilterControlledArtifactPermanent;
|
|
||||||
import mage.filter.common.FilterControlledPermanent;
|
|
||||||
import mage.filter.predicate.mageobject.AnotherPredicate;
|
|
||||||
import mage.filter.predicate.permanent.TappedPredicate;
|
|
||||||
import mage.target.common.TargetControlledPermanent;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author TheElk801
|
|
||||||
*/
|
|
||||||
public final class BladewheelChariot extends CardImpl {
|
|
||||||
|
|
||||||
private static final FilterControlledPermanent filter
|
|
||||||
= new FilterControlledArtifactPermanent("other untapped artifacts you control");
|
|
||||||
|
|
||||||
static {
|
|
||||||
filter.add(AnotherPredicate.instance);
|
|
||||||
filter.add(TappedPredicate.UNTAPPED);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BladewheelChariot(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "");
|
|
||||||
|
|
||||||
this.subtype.add(SubType.VEHICLE);
|
|
||||||
this.power = new MageInt(5);
|
|
||||||
this.toughness = new MageInt(5);
|
|
||||||
this.nightCard = true;
|
|
||||||
this.color.setWhite(true);
|
|
||||||
|
|
||||||
// Tap two other untapped artifacts you control: Bladewheel Chariot becomes an artifact creature until end of turn.
|
|
||||||
this.addAbility(new SimpleActivatedAbility(new AddCardTypeSourceEffect(
|
|
||||||
Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE
|
|
||||||
).setText("{this} becomes an artifact creature until end of turn"), new TapTargetCost(new TargetControlledPermanent(2, filter))));
|
|
||||||
|
|
||||||
// Crew 1
|
|
||||||
this.addAbility(new CrewAbility(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
private BladewheelChariot(final BladewheelChariot card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BladewheelChariot copy() {
|
|
||||||
return new BladewheelChariot(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +1,17 @@
|
||||||
package mage.cards.b;
|
package mage.cards.b;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
|
import mage.abilities.common.DealsDamageToAPlayerAllTriggeredAbility;
|
||||||
import mage.abilities.common.UnlockThisDoorTriggeredAbility;
|
import mage.abilities.common.UnlockThisDoorTriggeredAbility;
|
||||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
||||||
import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.cards.RoomCard;
|
import mage.cards.RoomCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.*;
|
||||||
import mage.constants.SetTargetPointer;
|
|
||||||
import mage.constants.SpellAbilityType;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.constants.TargetController;
|
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
import mage.target.common.TargetCreaturePermanent;
|
import mage.target.common.TargetCreaturePermanent;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author oscscull
|
* @author oscscull
|
||||||
*/
|
*/
|
||||||
|
|
@ -38,14 +34,14 @@ public final class BottomlessPoolLockerRoom extends RoomCard {
|
||||||
UnlockThisDoorTriggeredAbility left = new UnlockThisDoorTriggeredAbility(
|
UnlockThisDoorTriggeredAbility left = new UnlockThisDoorTriggeredAbility(
|
||||||
new ReturnToHandTargetEffect(), false, true);
|
new ReturnToHandTargetEffect(), false, true);
|
||||||
left.addTarget(new TargetCreaturePermanent(0, 1));
|
left.addTarget(new TargetCreaturePermanent(0, 1));
|
||||||
|
this.getLeftHalfCard().addAbility(left);
|
||||||
|
|
||||||
// Right half ability - "Whenever one or more creatures you control deal combat damage to a player, draw a card."
|
// Right half ability - "Whenever one or more creatures you control deal combat damage to a player, draw a card."
|
||||||
DealsDamageToAPlayerAllTriggeredAbility right = new DealsDamageToAPlayerAllTriggeredAbility(
|
DealsDamageToAPlayerAllTriggeredAbility right = new DealsDamageToAPlayerAllTriggeredAbility(
|
||||||
new DrawCardSourceControllerEffect(1),
|
new DrawCardSourceControllerEffect(1),
|
||||||
StaticFilters.FILTER_CONTROLLED_A_CREATURE,
|
StaticFilters.FILTER_CONTROLLED_A_CREATURE,
|
||||||
false, SetTargetPointer.PLAYER, true, true, TargetController.OPPONENT);
|
false, SetTargetPointer.PLAYER, true, true, TargetController.OPPONENT);
|
||||||
|
this.getRightHalfCard().addAbility(right);
|
||||||
this.addRoomAbilities(left, right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private BottomlessPoolLockerRoom(final BottomlessPoolLockerRoom card) {
|
private BottomlessPoolLockerRoom(final BottomlessPoolLockerRoom card) {
|
||||||
|
|
|
||||||
|
|
@ -35,11 +35,11 @@ public final class DazzlingTheaterPropRoom extends RoomCard {
|
||||||
|
|
||||||
// Dazzling Theater: Creature spells you cast have convoke.
|
// Dazzling Theater: Creature spells you cast have convoke.
|
||||||
Ability left = new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new ConvokeAbility(), filter));
|
Ability left = new SimpleStaticAbility(new GainAbilityControlledSpellsEffect(new ConvokeAbility(), filter));
|
||||||
|
this.getLeftHalfCard().addAbility(left);
|
||||||
|
|
||||||
// Prop Room: Untap each creature you control during each other player's untap step.
|
// Prop Room: Untap each creature you control during each other player's untap step.
|
||||||
Ability right = new SimpleStaticAbility(new UntapAllDuringEachOtherPlayersUntapStepEffect(StaticFilters.FILTER_CONTROLLED_CREATURES));
|
Ability right = new SimpleStaticAbility(new UntapAllDuringEachOtherPlayersUntapStepEffect(StaticFilters.FILTER_CONTROLLED_CREATURES));
|
||||||
|
this.getRightHalfCard().addAbility(right);
|
||||||
this.addRoomAbilities(left, right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DazzlingTheaterPropRoom(final DazzlingTheaterPropRoom card) {
|
private DazzlingTheaterPropRoom(final DazzlingTheaterPropRoom card) {
|
||||||
|
|
|
||||||
|
|
@ -34,13 +34,14 @@ public final class DollmakersShopPorcelainGallery extends RoomCard {
|
||||||
|
|
||||||
// Dollmaker's Shop: Whenever one or more non-Toy creatures you control attack a player, create a 1/1 white Toy artifact creature token.
|
// Dollmaker's Shop: Whenever one or more non-Toy creatures you control attack a player, create a 1/1 white Toy artifact creature token.
|
||||||
Ability left = new AttacksPlayerWithCreaturesTriggeredAbility(new CreateTokenEffect(new ToyToken()), filter, SetTargetPointer.NONE);
|
Ability left = new AttacksPlayerWithCreaturesTriggeredAbility(new CreateTokenEffect(new ToyToken()), filter, SetTargetPointer.NONE);
|
||||||
|
this.getLeftHalfCard().addAbility(left);
|
||||||
|
|
||||||
// Porcelain Gallery: Creatures you control have base power and toughness each equal to the number of creatures you control.
|
// Porcelain Gallery: Creatures you control have base power and toughness each equal to the number of creatures you control.
|
||||||
Ability right = new SimpleStaticAbility(new SetBasePowerToughnessAllEffect(
|
Ability right = new SimpleStaticAbility(new SetBasePowerToughnessAllEffect(
|
||||||
CreaturesYouControlCount.PLURAL, Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES
|
CreaturesYouControlCount.PLURAL, Duration.WhileOnBattlefield, StaticFilters.FILTER_CONTROLLED_CREATURES
|
||||||
).setText("Creatures you control have base power and toughness each equal to the number of creatures you control"));
|
).setText("Creatures you control have base power and toughness each equal to the number of creatures you control"));
|
||||||
|
right.addHint(new ValueHint("Creatures you control", CreaturesYouControlCount.PLURAL));
|
||||||
this.addRoomAbilities(left, right.addHint(new ValueHint("Creatures you control", CreaturesYouControlCount.PLURAL)));
|
this.getRightHalfCard().addAbility(right);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DollmakersShopPorcelainGallery (final DollmakersShopPorcelainGallery card) {
|
private DollmakersShopPorcelainGallery (final DollmakersShopPorcelainGallery card) {
|
||||||
|
|
|
||||||
|
|
@ -182,8 +182,8 @@ class DraugrNecromancerSpendAnyManaEffect extends AsThoughEffectImpl implements
|
||||||
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
||||||
} else if (card instanceof CardWithSpellOption) {
|
} else if (card instanceof CardWithSpellOption) {
|
||||||
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
||||||
} else if (card instanceof ModalDoubleFacedCard) {
|
} else if (card instanceof DoubleFacedCard) {
|
||||||
cardState = game.getLastKnownInformationCard(((ModalDoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED);
|
cardState = game.getLastKnownInformationCard(((DoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED);
|
||||||
} else {
|
} else {
|
||||||
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public final class EddieBrock extends ModalDoubleFacedCard {
|
||||||
"Venom, Lethal Protector",
|
"Venom, Lethal Protector",
|
||||||
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SYMBIOTE, SubType.HERO, SubType.VILLAIN}, "{3}{B}{R}{G}"
|
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SYMBIOTE, SubType.HERO, SubType.VILLAIN}, "{3}{B}{R}{G}"
|
||||||
);
|
);
|
||||||
this.getLeftHalfCard().setPT(5, 5);
|
this.getLeftHalfCard().setPT(3, 3);
|
||||||
this.getRightHalfCard().setPT(5, 5);
|
this.getRightHalfCard().setPT(5, 5);
|
||||||
|
|
||||||
// When Eddie Brock enters, return target creature card with mana value 1 or less from your graveyard to the battlefield.
|
// When Eddie Brock enters, return target creature card with mana value 1 or less from your graveyard to the battlefield.
|
||||||
|
|
|
||||||
|
|
@ -174,8 +174,8 @@ class EvelynTheCovetousManaEffect extends AsThoughEffectImpl implements AsThough
|
||||||
&& EvelynTheCovetousWatcher.checkExile(affectedControllerId, card, game, 0);
|
&& EvelynTheCovetousWatcher.checkExile(affectedControllerId, card, game, 0);
|
||||||
}
|
}
|
||||||
CardState cardState;
|
CardState cardState;
|
||||||
if (card instanceof ModalDoubleFacedCard) {
|
if (card instanceof DoubleFacedCard) {
|
||||||
cardState = game.getLastKnownInformationCard(((ModalDoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED);
|
cardState = game.getLastKnownInformationCard(((DoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED);
|
||||||
} else {
|
} else {
|
||||||
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,83 @@
|
||||||
package mage.cards.f;
|
package mage.cards.f;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.condition.Condition;
|
import mage.abilities.condition.Condition;
|
||||||
import mage.abilities.condition.common.SourceHasCounterCondition;
|
import mage.abilities.condition.common.SourceHasCounterCondition;
|
||||||
import mage.abilities.decorator.ConditionalAsThoughEffect;
|
import mage.abilities.decorator.ConditionalAsThoughEffect;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.AttachEffect;
|
||||||
import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect;
|
import mage.abilities.effects.common.combat.CanAttackAsThoughItDidntHaveDefenderSourceEffect;
|
||||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
||||||
import mage.abilities.keyword.DefenderAbility;
|
import mage.abilities.keyword.*;
|
||||||
import mage.abilities.keyword.DisturbAbility;
|
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
|
||||||
import mage.abilities.keyword.VigilanceAbility;
|
|
||||||
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
|
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.ComparisonType;
|
import mage.constants.*;
|
||||||
import mage.constants.Duration;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.target.TargetPlayer;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public final class FaithboundJudge extends CardImpl {
|
public final class FaithboundJudge extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
private static final Condition condition1 = new SourceHasCounterCondition(CounterType.JUDGMENT, ComparisonType.OR_LESS, 2);
|
private static final Condition condition1 = new SourceHasCounterCondition(CounterType.JUDGMENT, ComparisonType.OR_LESS, 2);
|
||||||
private static final Condition condition2 = new SourceHasCounterCondition(CounterType.JUDGMENT, 3);
|
private static final Condition condition2 = new SourceHasCounterCondition(CounterType.JUDGMENT, 3);
|
||||||
|
|
||||||
public FaithboundJudge(UUID ownerId, CardSetInfo setInfo) {
|
public FaithboundJudge(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{W}{W}");
|
super(ownerId, setInfo,
|
||||||
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT, SubType.SOLDIER}, "{1}{W}{W}",
|
||||||
|
"Sinner's Judgment",
|
||||||
|
new CardType[]{CardType.ENCHANTMENT}, new SubType[]{SubType.AURA, SubType.CURSE}, "W");
|
||||||
|
|
||||||
this.subtype.add(SubType.SPIRIT);
|
this.getLeftHalfCard().setPT(4, 4);
|
||||||
this.subtype.add(SubType.SOLDIER);
|
|
||||||
this.power = new MageInt(4);
|
|
||||||
this.toughness = new MageInt(4);
|
|
||||||
this.secondSideCardClazz = mage.cards.s.SinnersJudgment.class;
|
|
||||||
|
|
||||||
// Defender
|
// Defender
|
||||||
this.addAbility(DefenderAbility.getInstance());
|
this.getLeftHalfCard().addAbility(DefenderAbility.getInstance());
|
||||||
|
|
||||||
// Flying
|
// Flying
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
// Vigilance
|
// Vigilance
|
||||||
this.addAbility(VigilanceAbility.getInstance());
|
this.getLeftHalfCard().addAbility(VigilanceAbility.getInstance());
|
||||||
|
|
||||||
// At the beginning of your upkeep, if Faithbound Judge has two or fewer judgment counters on it, put a judgment counter on it.
|
// At the beginning of your upkeep, if Faithbound Judge has two or fewer judgment counters on it, put a judgment counter on it.
|
||||||
this.addAbility(new BeginningOfUpkeepTriggeredAbility(
|
this.getLeftHalfCard().addAbility(new BeginningOfUpkeepTriggeredAbility(
|
||||||
new AddCountersSourceEffect(CounterType.JUDGMENT.createInstance())
|
new AddCountersSourceEffect(CounterType.JUDGMENT.createInstance())
|
||||||
.setText("put a judgment counter on it"), false
|
.setText("put a judgment counter on it"), false
|
||||||
).withInterveningIf(condition1));
|
).withInterveningIf(condition1));
|
||||||
|
|
||||||
// As long as Faithbound Judge has three or more judgment counters on it, it can attack as though it didn't have defender.
|
// As long as Faithbound Judge has three or more judgment counters on it, it can attack as though it didn't have defender.
|
||||||
this.addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect(
|
this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new ConditionalAsThoughEffect(
|
||||||
new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.WhileOnBattlefield), condition2
|
new CanAttackAsThoughItDidntHaveDefenderSourceEffect(Duration.WhileOnBattlefield), condition2
|
||||||
).setText("as long as {this} has three or more judgment counters on it, " +
|
).setText("as long as {this} has three or more judgment counters on it, " +
|
||||||
"it can attack as though it didn't have defender")));
|
"it can attack as though it didn't have defender")));
|
||||||
|
|
||||||
// Disturb {5}{W}{W}
|
// Sinner's Judgement
|
||||||
this.addAbility(new DisturbAbility(this, "{5}{W}{W}"));
|
|
||||||
|
// Enchant player
|
||||||
|
TargetPlayer auraTarget = new TargetPlayer();
|
||||||
|
this.getRightHalfCard().getSpellAbility().addTarget(auraTarget);
|
||||||
|
this.getRightHalfCard().getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
|
||||||
|
this.getRightHalfCard().addAbility(new EnchantAbility(auraTarget));
|
||||||
|
|
||||||
|
// Faithbound Judge - Disturb {5}{W}{W}
|
||||||
|
// needs target from right half spell ability
|
||||||
|
this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{5}{W}{W}"));
|
||||||
|
|
||||||
|
// At the beginning of your upkeep, put a judgment counter on Sinner's Judgment. Then if there are three or more judgment counters on it, enchanted player loses the game.
|
||||||
|
Ability ability = new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.JUDGMENT.createInstance()));
|
||||||
|
ability.addEffect(new SinnersJudgmentEffect());
|
||||||
|
this.getRightHalfCard().addAbility(ability);
|
||||||
|
|
||||||
|
// If Sinner's Judgment would be put into a graveyard from anywhere, exile it instead.
|
||||||
|
this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
private FaithboundJudge(final FaithboundJudge card) {
|
private FaithboundJudge(final FaithboundJudge card) {
|
||||||
|
|
@ -73,3 +89,34 @@ public final class FaithboundJudge extends CardImpl {
|
||||||
return new FaithboundJudge(this);
|
return new FaithboundJudge(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SinnersJudgmentEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
SinnersJudgmentEffect() {
|
||||||
|
super(Outcome.Benefit);
|
||||||
|
staticText = "Then if there are three or more judgment counters on it, enchanted player loses the game";
|
||||||
|
}
|
||||||
|
|
||||||
|
private SinnersJudgmentEffect(final SinnersJudgmentEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SinnersJudgmentEffect copy() {
|
||||||
|
return new SinnersJudgmentEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
return Optional
|
||||||
|
.ofNullable(source.getSourcePermanentOrLKI(game))
|
||||||
|
.filter(permanent -> permanent.getCounters(game).getCount(CounterType.JUDGMENT) >= 3)
|
||||||
|
.map(Permanent::getAttachedTo)
|
||||||
|
.map(game::getPlayer)
|
||||||
|
.filter(player -> {
|
||||||
|
player.lost(game);
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.isPresent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,13 +30,13 @@ public final class FuneralRoomAwakeningHall extends RoomCard {
|
||||||
StaticFilters.FILTER_CONTROLLED_A_CREATURE
|
StaticFilters.FILTER_CONTROLLED_A_CREATURE
|
||||||
);
|
);
|
||||||
left.addEffect(new GainLifeEffect(1).concatBy("and"));
|
left.addEffect(new GainLifeEffect(1).concatBy("and"));
|
||||||
|
this.getLeftHalfCard().addAbility(left);
|
||||||
|
|
||||||
// Awakening Hall: When you unlock this door, return all creature cards from your graveyard to the battlefield.
|
// Awakening Hall: When you unlock this door, return all creature cards from your graveyard to the battlefield.
|
||||||
Ability right = new UnlockThisDoorTriggeredAbility(
|
Ability right = new UnlockThisDoorTriggeredAbility(
|
||||||
new ReturnFromYourGraveyardToBattlefieldAllEffect(StaticFilters.FILTER_CARD_CREATURES), false, false
|
new ReturnFromYourGraveyardToBattlefieldAllEffect(StaticFilters.FILTER_CARD_CREATURES), false, false
|
||||||
);
|
);
|
||||||
|
this.getRightHalfCard().addAbility(right);
|
||||||
this.addRoomAbilities(left, right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private FuneralRoomAwakeningHall(final FuneralRoomAwakeningHall card) {
|
private FuneralRoomAwakeningHall(final FuneralRoomAwakeningHall card) {
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
package mage.cards.g;
|
package mage.cards.g;
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
|
||||||
import mage.abilities.keyword.DisturbAbility;
|
import mage.abilities.keyword.DisturbAbility;
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
|
|
||||||
|
|
@ -14,21 +12,29 @@ import java.util.UUID;
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public final class Galedrifter extends CardImpl {
|
public final class Galedrifter extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
public Galedrifter(UUID ownerId, CardSetInfo setInfo) {
|
public Galedrifter(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{3}{U}");
|
super(ownerId, setInfo,
|
||||||
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HIPPOGRIFF}, "{3}{U}",
|
||||||
|
"Waildrifter",
|
||||||
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HIPPOGRIFF, SubType.SPIRIT}, "U");
|
||||||
|
|
||||||
this.subtype.add(SubType.HIPPOGRIFF);
|
this.getLeftHalfCard().setPT(3, 2);
|
||||||
this.power = new MageInt(3);
|
this.getRightHalfCard().setPT(2, 2);
|
||||||
this.toughness = new MageInt(2);
|
|
||||||
this.secondSideCardClazz = mage.cards.w.Waildrifter.class;
|
|
||||||
|
|
||||||
// Flying
|
// Flying
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
// Disturb {4}{U}
|
// Disturb {4}{U}
|
||||||
this.addAbility(new DisturbAbility(this, "{4}{U}"));
|
this.getLeftHalfCard().addAbility(new DisturbAbility(this, "{4}{U}"));
|
||||||
|
|
||||||
|
// Waildrifter
|
||||||
|
// Flying
|
||||||
|
this.getRightHalfCard().addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
|
// If Waildrifter would be put into a graveyard from anywhere, exile it instead.
|
||||||
|
this.getRightHalfCard().addAbility(DisturbAbility.makeBackAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Galedrifter(final Galedrifter card) {
|
private Galedrifter(final Galedrifter card) {
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
package mage.cards.h;
|
package mage.cards.h;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.abilities.common.WerewolfBackTriggeredAbility;
|
||||||
import mage.abilities.common.WerewolfFrontTriggeredAbility;
|
import mage.abilities.common.WerewolfFrontTriggeredAbility;
|
||||||
import mage.abilities.keyword.TransformAbility;
|
import mage.abilities.keyword.TrampleAbility;
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
|
|
||||||
|
|
@ -13,20 +13,30 @@ import java.util.UUID;
|
||||||
/**
|
/**
|
||||||
* @author fireshoes
|
* @author fireshoes
|
||||||
*/
|
*/
|
||||||
public final class HinterlandLogger extends CardImpl {
|
public final class HinterlandLogger extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
public HinterlandLogger(UUID ownerId, CardSetInfo setInfo) {
|
public HinterlandLogger(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
|
super(ownerId, setInfo,
|
||||||
this.subtype.add(SubType.HUMAN);
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{1}{G}",
|
||||||
this.subtype.add(SubType.WEREWOLF);
|
"Timber Shredder",
|
||||||
this.power = new MageInt(2);
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G");
|
||||||
this.toughness = new MageInt(1);
|
|
||||||
|
|
||||||
this.secondSideCardClazz = mage.cards.t.TimberShredder.class;
|
this.getLeftHalfCard().setPT(2, 1);
|
||||||
|
this.getRightHalfCard().setPT(4, 2);
|
||||||
|
|
||||||
// At the beginning of each upkeep, if no spells were cast last turn, transform Hinterland Logger.
|
// At the beginning of each upkeep, if no spells were cast last turn, transform Hinterland Logger.
|
||||||
this.addAbility(new TransformAbility());
|
// this.getLeftHalfCard().addAbility(new TransformAbility());
|
||||||
this.addAbility(new WerewolfFrontTriggeredAbility());
|
this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility());
|
||||||
|
|
||||||
|
// Timber Shredder
|
||||||
|
|
||||||
|
// Trample
|
||||||
|
this.getRightHalfCard().addAbility(TrampleAbility.getInstance());
|
||||||
|
|
||||||
|
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Timber Shredder.
|
||||||
|
this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private HinterlandLogger(final HinterlandLogger card) {
|
private HinterlandLogger(final HinterlandLogger card) {
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
package mage.cards.h;
|
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.keyword.DisturbAbility;
|
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author TheElk801
|
|
||||||
*/
|
|
||||||
public final class HookHauntDrifter extends CardImpl {
|
|
||||||
|
|
||||||
public HookHauntDrifter(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
|
|
||||||
|
|
||||||
this.subtype.add(SubType.SPIRIT);
|
|
||||||
this.power = new MageInt(1);
|
|
||||||
this.toughness = new MageInt(2);
|
|
||||||
this.color.setBlue(true);
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// Flying
|
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
|
||||||
|
|
||||||
// If Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead.
|
|
||||||
this.addAbility(DisturbAbility.makeBackAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
private HookHauntDrifter(final HookHauntDrifter card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public HookHauntDrifter copy() {
|
|
||||||
return new HookHauntDrifter(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +1,64 @@
|
||||||
package mage.cards.h;
|
package mage.cards.h;
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
|
||||||
import mage.abilities.common.TransformsOrEntersTriggeredAbility;
|
import mage.abilities.common.TransformsOrEntersTriggeredAbility;
|
||||||
|
import mage.abilities.common.WerewolfBackTriggeredAbility;
|
||||||
import mage.abilities.common.WerewolfFrontTriggeredAbility;
|
import mage.abilities.common.WerewolfFrontTriggeredAbility;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
import mage.abilities.effects.common.GainLifeEffect;
|
import mage.abilities.effects.common.GainLifeEffect;
|
||||||
import mage.abilities.keyword.TransformAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Outcome;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
|
import mage.filter.StaticFilters;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.token.WolfToken;
|
import mage.game.permanent.token.WolfToken;
|
||||||
|
import mage.players.Player;
|
||||||
|
import mage.target.TargetPermanent;
|
||||||
|
import mage.target.common.TargetOpponentOrPlaneswalker;
|
||||||
|
import mage.target.targetpointer.EachTargetPointer;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author BetaSteward
|
* @author BetaSteward
|
||||||
*/
|
*/
|
||||||
public final class HuntmasterOfTheFells extends CardImpl {
|
public final class HuntmasterOfTheFells extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
public HuntmasterOfTheFells(UUID ownerId, CardSetInfo setInfo) {
|
public HuntmasterOfTheFells(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{R}{G}");
|
super(ownerId, setInfo,
|
||||||
this.subtype.add(SubType.HUMAN);
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.WEREWOLF}, "{2}{R}{G}",
|
||||||
this.subtype.add(SubType.WEREWOLF);
|
"Ravager of the Fells",
|
||||||
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "RG"
|
||||||
|
);
|
||||||
|
|
||||||
this.secondSideCardClazz = mage.cards.r.RavagerOfTheFells.class;
|
this.getLeftHalfCard().setPT(2, 2);
|
||||||
|
this.getRightHalfCard().setPT(4, 4);
|
||||||
this.power = new MageInt(2);
|
|
||||||
this.toughness = new MageInt(2);
|
|
||||||
|
|
||||||
// Whenever this creature enters the battlefield or transforms into Huntmaster of the Fells, create a 2/2 green Wolf creature token and you gain 2 life.
|
// Whenever this creature enters the battlefield or transforms into Huntmaster of the Fells, create a 2/2 green Wolf creature token and you gain 2 life.
|
||||||
Ability ability = new TransformsOrEntersTriggeredAbility(new CreateTokenEffect(new WolfToken()), false);
|
Ability ability = new TransformsOrEntersTriggeredAbility(new CreateTokenEffect(new WolfToken()), false);
|
||||||
ability.addEffect(new GainLifeEffect(2).concatBy("and"));
|
ability.addEffect(new GainLifeEffect(2).concatBy("and"));
|
||||||
this.addAbility(ability);
|
this.getLeftHalfCard().addAbility(ability);
|
||||||
|
|
||||||
// At the beginning of each upkeep, if no spells were cast last turn, transform Huntmaster of the Fells.
|
// At the beginning of each upkeep, if no spells were cast last turn, transform Huntmaster of the Fells.
|
||||||
this.addAbility(new TransformAbility());
|
this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility());
|
||||||
this.addAbility(new WerewolfFrontTriggeredAbility());
|
|
||||||
|
|
||||||
|
// Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls.
|
||||||
|
Ability ravagerAbility = new TransformIntoSourceTriggeredAbility(
|
||||||
|
new RavagerOfTheFellsEffect(), false, true
|
||||||
|
);
|
||||||
|
ravagerAbility.addTarget(new TargetOpponentOrPlaneswalker());
|
||||||
|
ravagerAbility.addTarget(new RavagerOfTheFellsTarget());
|
||||||
|
this.getRightHalfCard().addAbility(ravagerAbility);
|
||||||
|
|
||||||
|
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells.
|
||||||
|
this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
private HuntmasterOfTheFells(final HuntmasterOfTheFells card) {
|
private HuntmasterOfTheFells(final HuntmasterOfTheFells card) {
|
||||||
|
|
@ -49,3 +70,70 @@ public final class HuntmasterOfTheFells extends CardImpl {
|
||||||
return new HuntmasterOfTheFells(this);
|
return new HuntmasterOfTheFells(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class RavagerOfTheFellsEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
RavagerOfTheFellsEffect() {
|
||||||
|
super(Outcome.Damage);
|
||||||
|
this.setTargetPointer(new EachTargetPointer());
|
||||||
|
staticText = "it deals 2 damage to target opponent or planeswalker and 2 damage " +
|
||||||
|
"to up to one target creature that player or that planeswalker's controller controls.";
|
||||||
|
}
|
||||||
|
|
||||||
|
private RavagerOfTheFellsEffect(final RavagerOfTheFellsEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RavagerOfTheFellsEffect copy() {
|
||||||
|
return new RavagerOfTheFellsEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
for (UUID targetId : getTargetPointer().getTargets(game, source)) {
|
||||||
|
game.damagePlayerOrPermanent(
|
||||||
|
targetId, 2, source.getSourceId(), source,
|
||||||
|
game, false, true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class RavagerOfTheFellsTarget extends TargetPermanent {
|
||||||
|
|
||||||
|
RavagerOfTheFellsTarget() {
|
||||||
|
super(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private RavagerOfTheFellsTarget(final RavagerOfTheFellsTarget target) {
|
||||||
|
super(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
||||||
|
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
||||||
|
|
||||||
|
Player needPlayer = game.getPlayerOrPlaneswalkerController(source.getFirstTarget());
|
||||||
|
if (needPlayer == null) {
|
||||||
|
// playable or not selected - use any
|
||||||
|
} else {
|
||||||
|
// filter by controller
|
||||||
|
possibleTargets.removeIf(id -> {
|
||||||
|
Permanent permanent = game.getPermanent(id);
|
||||||
|
return permanent == null
|
||||||
|
|| permanent.getId().equals(source.getFirstTarget())
|
||||||
|
|| !permanent.isControlledBy(needPlayer.getId());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return possibleTargets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RavagerOfTheFellsTarget copy() {
|
||||||
|
return new RavagerOfTheFellsTarget(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,13 @@ package mage.cards.i;
|
||||||
|
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
import mage.abilities.common.SiegeAbility;
|
import mage.abilities.common.SiegeAbility;
|
||||||
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
import mage.abilities.effects.common.CreateTokenEffect;
|
import mage.abilities.effects.common.CreateTokenEffect;
|
||||||
import mage.cards.CardImpl;
|
import mage.abilities.effects.common.continuous.BoostControlledEffect;
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Duration;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.game.permanent.token.KnightWhiteBlueToken;
|
import mage.game.permanent.token.KnightWhiteBlueToken;
|
||||||
|
|
||||||
|
|
@ -14,20 +17,27 @@ import java.util.UUID;
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public final class InvasionOfBelenon extends CardImpl {
|
public final class InvasionOfBelenon extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
public InvasionOfBelenon(UUID ownerId, CardSetInfo setInfo) {
|
public InvasionOfBelenon(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.BATTLE}, "{2}{W}");
|
super(ownerId, setInfo,
|
||||||
|
new CardType[]{CardType.BATTLE}, new SubType[]{SubType.SIEGE}, "{2}{W}",
|
||||||
|
"Belenon War Anthem",
|
||||||
|
new CardType[]{CardType.ENCHANTMENT}, new SubType[]{}, "W");
|
||||||
|
|
||||||
this.subtype.add(SubType.SIEGE);
|
this.getLeftHalfCard().setStartingDefense(5);
|
||||||
this.setStartingDefense(5);
|
|
||||||
this.secondSideCardClazz = mage.cards.b.BelenonWarAnthem.class;
|
|
||||||
|
|
||||||
// (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.)
|
// (As a Siege enters, choose an opponent to protect it. You and others can attack it. When it's defeated, exile it, then cast it transformed.)
|
||||||
this.addAbility(new SiegeAbility());
|
this.getLeftHalfCard().addAbility(new SiegeAbility());
|
||||||
|
|
||||||
// When Invasion of Belenon enters the battlefield, create a 2/2 white and blue Knight creature token with vigilance.
|
// When Invasion of Belenon enters the battlefield, create a 2/2 white and blue Knight creature token with vigilance.
|
||||||
this.addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightWhiteBlueToken())));
|
this.getLeftHalfCard().addAbility(new EntersBattlefieldTriggeredAbility(new CreateTokenEffect(new KnightWhiteBlueToken())));
|
||||||
|
|
||||||
|
// Belenon War Anthem
|
||||||
|
|
||||||
|
// Creatures you control get +1/+1.
|
||||||
|
this.getRightHalfCard().addAbility(new SimpleStaticAbility(new BoostControlledEffect(1, 1, Duration.WhileOnBattlefield)));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private InvasionOfBelenon(final InvasionOfBelenon card) {
|
private InvasionOfBelenon(final InvasionOfBelenon card) {
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,7 @@ class InvasionOfPyruleaEffect extends OneShotEffect {
|
||||||
player.scry(3, source, game);
|
player.scry(3, source, game);
|
||||||
Card card = player.getLibrary().getFromTop(game);
|
Card card = player.getLibrary().getFromTop(game);
|
||||||
player.revealCards(source, new CardsImpl(card), game);
|
player.revealCards(source, new CardsImpl(card), game);
|
||||||
if (card != null && (card.isLand(game) || card instanceof ModalDoubleFacedCard || card.getSecondCardFace() != null)) {
|
if (card != null && (card.isLand(game) || card instanceof DoubleFacedCard || card.getSecondCardFace() != null)) {
|
||||||
player.drawCards(1, source, game);
|
player.drawCards(1, source, game);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -165,9 +165,9 @@ class JestersScepterCost extends CostImpl {
|
||||||
if (card instanceof SplitCard) {
|
if (card instanceof SplitCard) {
|
||||||
game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((SplitCard) card).getLeftHalfCard().getName());
|
game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((SplitCard) card).getLeftHalfCard().getName());
|
||||||
game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((SplitCard) card).getRightHalfCard().getName());
|
game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((SplitCard) card).getRightHalfCard().getName());
|
||||||
} else if (card instanceof ModalDoubleFacedCard) {
|
} else if (card instanceof DoubleFacedCard) {
|
||||||
game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((ModalDoubleFacedCard) card).getLeftHalfCard().getName());
|
game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", ((DoubleFacedCard) card).getLeftHalfCard().getName());
|
||||||
game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((ModalDoubleFacedCard) card).getRightHalfCard().getName());
|
game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment2", ((DoubleFacedCard) card).getRightHalfCard().getName());
|
||||||
} else {
|
} else {
|
||||||
game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", card.getName());
|
game.getState().setValue(source.getSourceId() + "_nameOfExiledCardPayment", card.getName());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
package mage.cards.l;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.common.WerewolfBackTriggeredAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author fireshoes
|
|
||||||
*/
|
|
||||||
public final class LambholtButcher extends CardImpl {
|
|
||||||
|
|
||||||
public LambholtButcher(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"");
|
|
||||||
this.subtype.add(SubType.WEREWOLF);
|
|
||||||
this.power = new MageInt(4);
|
|
||||||
this.toughness = new MageInt(4);
|
|
||||||
this.color.setGreen(true);
|
|
||||||
|
|
||||||
// this card is the second face of double-faced card
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Lambholt Butcher.
|
|
||||||
this.addAbility(new WerewolfBackTriggeredAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
private LambholtButcher(final LambholtButcher card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LambholtButcher copy() {
|
|
||||||
return new LambholtButcher(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
package mage.cards.l;
|
package mage.cards.l;
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
import mage.abilities.common.SimpleStaticAbility;
|
||||||
|
import mage.abilities.common.WerewolfBackTriggeredAbility;
|
||||||
import mage.abilities.common.WerewolfFrontTriggeredAbility;
|
import mage.abilities.common.WerewolfFrontTriggeredAbility;
|
||||||
import mage.abilities.condition.Condition;
|
import mage.abilities.condition.Condition;
|
||||||
import mage.abilities.condition.InvertCondition;
|
import mage.abilities.condition.InvertCondition;
|
||||||
|
|
@ -9,9 +9,8 @@ import mage.abilities.condition.common.FerociousCondition;
|
||||||
import mage.abilities.decorator.ConditionalRestrictionEffect;
|
import mage.abilities.decorator.ConditionalRestrictionEffect;
|
||||||
import mage.abilities.effects.common.combat.CantAttackSourceEffect;
|
import mage.abilities.effects.common.combat.CantAttackSourceEffect;
|
||||||
import mage.abilities.hint.common.FerociousHint;
|
import mage.abilities.hint.common.FerociousHint;
|
||||||
import mage.abilities.keyword.TransformAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Duration;
|
import mage.constants.Duration;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
|
|
@ -21,29 +20,32 @@ import java.util.UUID;
|
||||||
/**
|
/**
|
||||||
* @author fireshoes
|
* @author fireshoes
|
||||||
*/
|
*/
|
||||||
public final class LambholtPacifist extends CardImpl {
|
public final class LambholtPacifist extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
private static final Condition condition = new InvertCondition(FerociousCondition.instance);
|
private static final Condition condition = new InvertCondition(FerociousCondition.instance);
|
||||||
|
|
||||||
public LambholtPacifist(UUID ownerId, CardSetInfo setInfo) {
|
public LambholtPacifist(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{1}{G}");
|
super(ownerId, setInfo,
|
||||||
this.subtype.add(SubType.HUMAN);
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.HUMAN, SubType.SHAMAN, SubType.WEREWOLF}, "{1}{G}",
|
||||||
this.subtype.add(SubType.SHAMAN);
|
"Lambholt Butcher",
|
||||||
this.subtype.add(SubType.WEREWOLF);
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.WEREWOLF}, "G");
|
||||||
this.power = new MageInt(3);
|
|
||||||
this.toughness = new MageInt(3);
|
|
||||||
|
|
||||||
this.secondSideCardClazz = mage.cards.l.LambholtButcher.class;
|
this.getLeftHalfCard().setPT(3, 3);
|
||||||
|
this.getRightHalfCard().setPT(4, 4);
|
||||||
|
|
||||||
// Lambholt Pacifist can't attack unless you control a creature with power 4 or greater.
|
// Lambholt Pacifist can't attack unless you control a creature with power 4 or greater.
|
||||||
this.addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect(
|
this.getLeftHalfCard().addAbility(new SimpleStaticAbility(new ConditionalRestrictionEffect(
|
||||||
new CantAttackSourceEffect(Duration.WhileOnBattlefield), condition,
|
new CantAttackSourceEffect(Duration.WhileOnBattlefield), condition,
|
||||||
"{this} can't attack unless you control a creature with power 4 or greater"
|
"{this} can't attack unless you control a creature with power 4 or greater"
|
||||||
)).addHint(FerociousHint.instance));
|
)).addHint(FerociousHint.instance));
|
||||||
|
|
||||||
// At the beginning of each upkeep, if no spells were cast last turn, transform Lambholt Pacifist.
|
// At the beginning of each upkeep, if no spells were cast last turn, transform Lambholt Pacifist.
|
||||||
this.addAbility(new TransformAbility());
|
this.getLeftHalfCard().addAbility(new WerewolfFrontTriggeredAbility());
|
||||||
this.addAbility(new WerewolfFrontTriggeredAbility());
|
|
||||||
|
// Lambholt Butcher
|
||||||
|
|
||||||
|
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Lambholt Butcher.
|
||||||
|
this.getRightHalfCard().addAbility(new WerewolfBackTriggeredAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
private LambholtPacifist(final LambholtPacifist card) {
|
private LambholtPacifist(final LambholtPacifist card) {
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
package mage.cards.l;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.common.BecomesBlockedSourceTriggeredAbility;
|
|
||||||
import mage.abilities.effects.common.UntapLandsEffect;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author weirddan455
|
|
||||||
*/
|
|
||||||
public final class LikenessOfTheSeeker extends CardImpl {
|
|
||||||
|
|
||||||
public LikenessOfTheSeeker(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT, CardType.CREATURE}, "");
|
|
||||||
|
|
||||||
this.subtype.add(SubType.HUMAN);
|
|
||||||
this.subtype.add(SubType.MONK);
|
|
||||||
this.power = new MageInt(3);
|
|
||||||
this.toughness = new MageInt(3);
|
|
||||||
this.color.setGreen(true);
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// Whenever Likeness of the Seeker becomes blocked, untap up to three lands you control.
|
|
||||||
this.addAbility(new BecomesBlockedSourceTriggeredAbility(new UntapLandsEffect(3, true, true), false));
|
|
||||||
}
|
|
||||||
|
|
||||||
private LikenessOfTheSeeker(final LikenessOfTheSeeker card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public LikenessOfTheSeeker copy() {
|
|
||||||
return new LikenessOfTheSeeker(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -60,7 +60,7 @@ public final class MilesMorales extends ModalDoubleFacedCard {
|
||||||
// When Miles Morales enters, put a +1/+1 counter on each of up to two target creatures.
|
// When Miles Morales enters, put a +1/+1 counter on each of up to two target creatures.
|
||||||
Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()));
|
Ability ability = new EntersBattlefieldTriggeredAbility(new AddCountersTargetEffect(CounterType.P1P1.createInstance()));
|
||||||
ability.addTarget(new TargetCreaturePermanent(0, 2));
|
ability.addTarget(new TargetCreaturePermanent(0, 2));
|
||||||
this.addAbility(ability);
|
this.getLeftHalfCard().addAbility(ability);
|
||||||
|
|
||||||
// {3}{R}{G}{W}: Transform Miles Morales. Activate only as a sorcery.
|
// {3}{R}{G}{W}: Transform Miles Morales. Activate only as a sorcery.
|
||||||
this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(
|
this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(
|
||||||
|
|
|
||||||
|
|
@ -134,10 +134,10 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl {
|
||||||
affectedCards.forEach(card -> {
|
affectedCards.forEach(card -> {
|
||||||
game.getState().getCreateMageObjectAttribute(card, game).getColor().setColor(colorless);
|
game.getState().getCreateMageObjectAttribute(card, game).getColor().setColor(colorless);
|
||||||
|
|
||||||
// mdf cards
|
// df cards
|
||||||
if (card instanceof ModalDoubleFacedCard) {
|
if (card instanceof DoubleFacedCard) {
|
||||||
ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard();
|
DoubleFacedCardHalf leftHalfCard = ((DoubleFacedCard) card).getLeftHalfCard();
|
||||||
ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard();
|
DoubleFacedCardHalf rightHalfCard = ((DoubleFacedCard) card).getRightHalfCard();
|
||||||
game.getState().getCreateMageObjectAttribute(leftHalfCard, game).getColor().setColor(colorless);
|
game.getState().getCreateMageObjectAttribute(leftHalfCard, game).getColor().setColor(colorless);
|
||||||
game.getState().getCreateMageObjectAttribute(rightHalfCard, game).getColor().setColor(colorless);
|
game.getState().getCreateMageObjectAttribute(rightHalfCard, game).getColor().setColor(colorless);
|
||||||
}
|
}
|
||||||
|
|
@ -151,6 +151,7 @@ class EverythingIsColorlessEffect extends ContinuousEffectImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
// double faces cards
|
// double faces cards
|
||||||
|
// TODO: can remove after tdfc rework
|
||||||
if (card.getSecondCardFace() != null) {
|
if (card.getSecondCardFace() != null) {
|
||||||
game.getState().getCreateMageObjectAttribute(card, game).getColor().setColor(colorless);
|
game.getState().getCreateMageObjectAttribute(card, game).getColor().setColor(colorless);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,130 +0,0 @@
|
||||||
package mage.cards.o;
|
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.MageObjectReference;
|
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.DelayedTriggeredAbility;
|
|
||||||
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.abilities.effects.common.TransformSourceEffect;
|
|
||||||
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
|
||||||
import mage.abilities.effects.keyword.BolsterEffect;
|
|
||||||
import mage.abilities.keyword.LivingMetalAbility;
|
|
||||||
import mage.abilities.keyword.TrampleAbility;
|
|
||||||
import mage.abilities.keyword.TransformAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.*;
|
|
||||||
import mage.game.Game;
|
|
||||||
import mage.game.events.DamagedPlayerEvent;
|
|
||||||
import mage.game.events.GameEvent;
|
|
||||||
import mage.game.permanent.Permanent;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author xenohedron
|
|
||||||
*/
|
|
||||||
public final class OptimusPrimeAutobotLeader extends CardImpl {
|
|
||||||
|
|
||||||
public OptimusPrimeAutobotLeader(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "");
|
|
||||||
|
|
||||||
this.addSuperType(SuperType.LEGENDARY);
|
|
||||||
this.subtype.add(SubType.VEHICLE);
|
|
||||||
this.power = new MageInt(6);
|
|
||||||
this.toughness = new MageInt(8);
|
|
||||||
this.color.setWhite(true);
|
|
||||||
this.color.setBlue(true);
|
|
||||||
this.color.setRed(true);
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// Living metal
|
|
||||||
this.addAbility(new LivingMetalAbility());
|
|
||||||
|
|
||||||
// Trample
|
|
||||||
this.addAbility(TrampleAbility.getInstance());
|
|
||||||
|
|
||||||
// Whenever you attack, bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert Optimus Prime.
|
|
||||||
this.addAbility(new AttacksWithCreaturesTriggeredAbility(new BolsterEffect(2)
|
|
||||||
.withAdditionalEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()))
|
|
||||||
.withAdditionalEffect(new OptimusPrimeAutobotLeaderEffect())
|
|
||||||
.setText("bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert {this}"),
|
|
||||||
1));
|
|
||||||
|
|
||||||
// Transform Ability
|
|
||||||
this.addAbility(new TransformAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
private OptimusPrimeAutobotLeader(final OptimusPrimeAutobotLeader card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OptimusPrimeAutobotLeader copy() {
|
|
||||||
return new OptimusPrimeAutobotLeader(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class OptimusPrimeAutobotLeaderEffect extends OneShotEffect {
|
|
||||||
|
|
||||||
OptimusPrimeAutobotLeaderEffect() {
|
|
||||||
super(Outcome.Transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
private OptimusPrimeAutobotLeaderEffect(final OptimusPrimeAutobotLeaderEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OptimusPrimeAutobotLeaderEffect copy() {
|
|
||||||
return new OptimusPrimeAutobotLeaderEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
|
|
||||||
if (creature == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
game.addDelayedTriggeredAbility(new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(new MageObjectReference(creature, game)), source);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class OptimusPrimeAutobotLeaderDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
|
||||||
|
|
||||||
private final MageObjectReference mor;
|
|
||||||
|
|
||||||
OptimusPrimeAutobotLeaderDelayedTriggeredAbility(MageObjectReference mor) {
|
|
||||||
super(new TransformSourceEffect().setText("convert {this}"), Duration.EndOfTurn);
|
|
||||||
this.mor = mor;
|
|
||||||
setTriggerPhrase("When that creature deals combat damage to a player this turn, ");
|
|
||||||
}
|
|
||||||
|
|
||||||
private OptimusPrimeAutobotLeaderDelayedTriggeredAbility(final OptimusPrimeAutobotLeaderDelayedTriggeredAbility ability) {
|
|
||||||
super(ability);
|
|
||||||
this.mor = ability.mor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public OptimusPrimeAutobotLeaderDelayedTriggeredAbility copy() {
|
|
||||||
return new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkEventType(GameEvent event, Game game) {
|
|
||||||
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean checkTrigger(GameEvent event, Game game) {
|
|
||||||
if (((DamagedPlayerEvent) event).isCombatDamage()) {
|
|
||||||
Permanent permanent = game.getPermanent(event.getSourceId());
|
|
||||||
return mor.refersTo(permanent, game);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
package mage.cards.o;
|
package mage.cards.o;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.MageObjectReference;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.DelayedTriggeredAbility;
|
||||||
|
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
|
||||||
|
import mage.abilities.effects.common.TransformSourceEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.GainAbilityTargetEffect;
|
||||||
|
import mage.abilities.keyword.LivingMetalAbility;
|
||||||
|
import mage.abilities.keyword.TrampleAbility;
|
||||||
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
|
import mage.abilities.triggers.BeginningOfEndStepTriggeredAbility;
|
||||||
import mage.abilities.common.DiesSourceTriggeredAbility;
|
import mage.abilities.common.DiesSourceTriggeredAbility;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
|
@ -9,10 +15,14 @@ import mage.abilities.effects.keyword.BolsterEffect;
|
||||||
import mage.abilities.keyword.MoreThanMeetsTheEyeAbility;
|
import mage.abilities.keyword.MoreThanMeetsTheEyeAbility;
|
||||||
import mage.abilities.keyword.TransformAbility;
|
import mage.abilities.keyword.TransformAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
|
import mage.cards.TransformingDoubleFacedCardHalf;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.game.events.DamagedPlayerEvent;
|
||||||
|
import mage.game.events.GameEvent;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
@ -20,25 +30,40 @@ import java.util.UUID;
|
||||||
/**
|
/**
|
||||||
* @author jbureau88
|
* @author jbureau88
|
||||||
*/
|
*/
|
||||||
public final class OptimusPrimeHero extends CardImpl {
|
public final class OptimusPrimeHero extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
public OptimusPrimeHero(UUID ownerId, CardSetInfo setInfo) {
|
public OptimusPrimeHero(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, "{3}{U}{R}{W}");
|
super(ownerId, setInfo,
|
||||||
|
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT, CardType.CREATURE}, new SubType[]{SubType.ROBOT}, "{3}{U}{R}{W}",
|
||||||
|
"Optimus Prime, Autobot Leader",
|
||||||
|
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "WUR");
|
||||||
|
|
||||||
this.addSuperType(SuperType.LEGENDARY);
|
this.getLeftHalfCard().setPT(4, 8);
|
||||||
this.subtype.add(SubType.ROBOT);
|
this.getRightHalfCard().setPT(6, 8);
|
||||||
this.power = new MageInt(4);
|
|
||||||
this.toughness = new MageInt(8);
|
|
||||||
this.secondSideCardClazz = mage.cards.o.OptimusPrimeAutobotLeader.class;
|
|
||||||
|
|
||||||
// More Than Meets the Eye {2}{U}{R}{W}
|
// More Than Meets the Eye {2}{U}{R}{W}
|
||||||
this.addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{U}{R}{W}"));
|
this.getLeftHalfCard().addAbility(new MoreThanMeetsTheEyeAbility(this, "{2}{U}{R}{W}"));
|
||||||
|
|
||||||
// At the beginning of each end step, bolster 1.
|
// At the beginning of each end step, bolster 1.
|
||||||
this.addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.ANY, new BolsterEffect(1), false));
|
this.getLeftHalfCard().addAbility(new BeginningOfEndStepTriggeredAbility(TargetController.ANY, new BolsterEffect(1), false));
|
||||||
|
|
||||||
// When Optimus Prime dies, return it to the battlefield converted under its owner’s control.
|
// When Optimus Prime dies, return it to the battlefield converted under its owner’s control.
|
||||||
this.addAbility(new DiesSourceTriggeredAbility(new OptimusPrimeHeroEffect()));
|
this.getLeftHalfCard().addAbility(new DiesSourceTriggeredAbility(new OptimusPrimeHeroEffect()));
|
||||||
|
|
||||||
|
// Optimus Prime, Autobot Leader
|
||||||
|
|
||||||
|
// Living metal
|
||||||
|
this.getRightHalfCard().addAbility(new LivingMetalAbility());
|
||||||
|
|
||||||
|
// Trample
|
||||||
|
this.getRightHalfCard().addAbility(TrampleAbility.getInstance());
|
||||||
|
|
||||||
|
// Whenever you attack, bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert Optimus Prime.
|
||||||
|
this.getRightHalfCard().addAbility(new AttacksWithCreaturesTriggeredAbility(new BolsterEffect(2)
|
||||||
|
.withAdditionalEffect(new GainAbilityTargetEffect(TrampleAbility.getInstance()))
|
||||||
|
.withAdditionalEffect(new OptimusPrimeAutobotLeaderEffect())
|
||||||
|
.setText("bolster 2. The chosen creature gains trample until end of turn. When that creature deals combat damage to a player this turn, convert {this}"),
|
||||||
|
1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private OptimusPrimeHero(final OptimusPrimeHero card) {
|
private OptimusPrimeHero(final OptimusPrimeHero card) {
|
||||||
|
|
@ -70,11 +95,81 @@ class OptimusPrimeHeroEffect extends OneShotEffect {
|
||||||
@Override
|
@Override
|
||||||
public boolean apply(Game game, Ability source) {
|
public boolean apply(Game game, Ability source) {
|
||||||
Player controller = game.getPlayer(source.getControllerId());
|
Player controller = game.getPlayer(source.getControllerId());
|
||||||
Card card = game.getCard(source.getSourceId());
|
Card card = source.getSourceCardIfItStillExists(game);
|
||||||
if (card == null || controller == null) {
|
if (controller == null || card == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), Boolean.TRUE);
|
if (game.getState().getZone(source.getSourceId()) != Zone.GRAVEYARD) {
|
||||||
return controller.moveCards(card, Zone.BATTLEFIELD, source, game);
|
return true;
|
||||||
|
}
|
||||||
|
Card backSide = ((TransformingDoubleFacedCardHalf) card).getOtherSide();
|
||||||
|
if (backSide == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + backSide.getId(), true);
|
||||||
|
controller.moveCards(backSide, Zone.BATTLEFIELD, source, game);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OptimusPrimeAutobotLeaderEffect extends OneShotEffect {
|
||||||
|
|
||||||
|
OptimusPrimeAutobotLeaderEffect() {
|
||||||
|
super(Outcome.Transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
private OptimusPrimeAutobotLeaderEffect(final OptimusPrimeAutobotLeaderEffect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OptimusPrimeAutobotLeaderEffect copy() {
|
||||||
|
return new OptimusPrimeAutobotLeaderEffect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Permanent creature = game.getPermanent(getTargetPointer().getFirst(game, source));
|
||||||
|
if (creature == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
game.addDelayedTriggeredAbility(new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(new MageObjectReference(creature, game)), source);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class OptimusPrimeAutobotLeaderDelayedTriggeredAbility extends DelayedTriggeredAbility {
|
||||||
|
|
||||||
|
private final MageObjectReference mor;
|
||||||
|
|
||||||
|
OptimusPrimeAutobotLeaderDelayedTriggeredAbility(MageObjectReference mor) {
|
||||||
|
super(new TransformSourceEffect().setText("convert {this}"), Duration.EndOfTurn);
|
||||||
|
this.mor = mor;
|
||||||
|
setTriggerPhrase("When that creature deals combat damage to a player this turn, ");
|
||||||
|
}
|
||||||
|
|
||||||
|
private OptimusPrimeAutobotLeaderDelayedTriggeredAbility(final OptimusPrimeAutobotLeaderDelayedTriggeredAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
this.mor = ability.mor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public OptimusPrimeAutobotLeaderDelayedTriggeredAbility copy() {
|
||||||
|
return new OptimusPrimeAutobotLeaderDelayedTriggeredAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkEventType(GameEvent event, Game game) {
|
||||||
|
return event.getType() == GameEvent.EventType.DAMAGED_PLAYER;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean checkTrigger(GameEvent event, Game game) {
|
||||||
|
if (((DamagedPlayerEvent) event).isCombatDamage()) {
|
||||||
|
Permanent permanent = game.getPermanent(event.getSourceId());
|
||||||
|
return mor.refersTo(permanent, game);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -107,10 +107,10 @@ class PaintersServantEffect extends ContinuousEffectImpl {
|
||||||
affectedCards.forEach(card -> {
|
affectedCards.forEach(card -> {
|
||||||
game.getState().getCreateMageObjectAttribute(card, game).getColor().addColor(color);
|
game.getState().getCreateMageObjectAttribute(card, game).getColor().addColor(color);
|
||||||
|
|
||||||
// mdf cards
|
// df cards
|
||||||
if (card instanceof ModalDoubleFacedCard) {
|
if (card instanceof DoubleFacedCard) {
|
||||||
ModalDoubleFacedCardHalf leftHalfCard = ((ModalDoubleFacedCard) card).getLeftHalfCard();
|
DoubleFacedCardHalf leftHalfCard = ((DoubleFacedCard) card).getLeftHalfCard();
|
||||||
ModalDoubleFacedCardHalf rightHalfCard = ((ModalDoubleFacedCard) card).getRightHalfCard();
|
DoubleFacedCardHalf rightHalfCard = ((DoubleFacedCard) card).getRightHalfCard();
|
||||||
game.getState().getCreateMageObjectAttribute(leftHalfCard, game).getColor().addColor(color);
|
game.getState().getCreateMageObjectAttribute(leftHalfCard, game).getColor().addColor(color);
|
||||||
game.getState().getCreateMageObjectAttribute(rightHalfCard, game).getColor().addColor(color);
|
game.getState().getCreateMageObjectAttribute(rightHalfCard, game).getColor().addColor(color);
|
||||||
}
|
}
|
||||||
|
|
@ -124,6 +124,7 @@ class PaintersServantEffect extends ContinuousEffectImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
// double faces cards
|
// double faces cards
|
||||||
|
// TODO: can remove after tdfc rework
|
||||||
if (card.getSecondCardFace() != null) {
|
if (card.getSecondCardFace() != null) {
|
||||||
game.getState().getCreateMageObjectAttribute(card.getSecondCardFace(), game).getColor().addColor(color);
|
game.getState().getCreateMageObjectAttribute(card.getSecondCardFace(), game).getColor().addColor(color);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
package mage.cards.p;
|
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
|
||||||
import mage.abilities.effects.common.ReturnToHandSourceEffect;
|
|
||||||
import mage.abilities.keyword.SkulkAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author LevelX2
|
|
||||||
*/
|
|
||||||
public final class PersistentNightmare extends CardImpl {
|
|
||||||
|
|
||||||
public PersistentNightmare(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
|
|
||||||
this.subtype.add(SubType.NIGHTMARE);
|
|
||||||
this.power = new MageInt(1);
|
|
||||||
this.toughness = new MageInt(1);
|
|
||||||
this.color.setBlue(true);
|
|
||||||
|
|
||||||
// this card is the second face of double-faced card
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// Skulk
|
|
||||||
this.addAbility(new SkulkAbility());
|
|
||||||
|
|
||||||
// When Persistent Nightmare deals combat damage to a player, return it to its owner's hand.
|
|
||||||
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(
|
|
||||||
new ReturnToHandSourceEffect(), false
|
|
||||||
).setTriggerPhrase("When {this} deals combat damage to a player, "));
|
|
||||||
}
|
|
||||||
|
|
||||||
private PersistentNightmare(final PersistentNightmare card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public PersistentNightmare copy() {
|
|
||||||
return new PersistentNightmare(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
||||||
package mage.cards.r;
|
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.common.TransformIntoSourceTriggeredAbility;
|
|
||||||
import mage.abilities.common.WerewolfBackTriggeredAbility;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.abilities.keyword.TrampleAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.filter.StaticFilters;
|
|
||||||
import mage.game.Game;
|
|
||||||
import mage.game.permanent.Permanent;
|
|
||||||
import mage.players.Player;
|
|
||||||
import mage.target.TargetPermanent;
|
|
||||||
import mage.target.common.TargetOpponentOrPlaneswalker;
|
|
||||||
import mage.target.targetpointer.EachTargetPointer;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author BetaSteward
|
|
||||||
*/
|
|
||||||
public final class RavagerOfTheFells extends CardImpl {
|
|
||||||
|
|
||||||
public RavagerOfTheFells(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
|
|
||||||
this.subtype.add(SubType.WEREWOLF);
|
|
||||||
this.color.setRed(true);
|
|
||||||
this.color.setGreen(true);
|
|
||||||
|
|
||||||
// this card is the second face of double-faced card
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
this.power = new MageInt(4);
|
|
||||||
this.toughness = new MageInt(4);
|
|
||||||
|
|
||||||
this.addAbility(TrampleAbility.getInstance());
|
|
||||||
|
|
||||||
// Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls.
|
|
||||||
Ability ability = new TransformIntoSourceTriggeredAbility(
|
|
||||||
new RavagerOfTheFellsEffect(), false, true
|
|
||||||
);
|
|
||||||
ability.addTarget(new TargetOpponentOrPlaneswalker());
|
|
||||||
ability.addTarget(new RavagerOfTheFellsTarget());
|
|
||||||
this.addAbility(ability);
|
|
||||||
|
|
||||||
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells.
|
|
||||||
this.addAbility(new WerewolfBackTriggeredAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
private RavagerOfTheFells(final RavagerOfTheFells card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RavagerOfTheFells copy() {
|
|
||||||
return new RavagerOfTheFells(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class RavagerOfTheFellsEffect extends OneShotEffect {
|
|
||||||
|
|
||||||
RavagerOfTheFellsEffect() {
|
|
||||||
super(Outcome.Damage);
|
|
||||||
this.setTargetPointer(new EachTargetPointer());
|
|
||||||
staticText = "it deals 2 damage to target opponent or planeswalker and 2 damage " +
|
|
||||||
"to up to one target creature that player or that planeswalker's controller controls.";
|
|
||||||
}
|
|
||||||
|
|
||||||
private RavagerOfTheFellsEffect(final RavagerOfTheFellsEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RavagerOfTheFellsEffect copy() {
|
|
||||||
return new RavagerOfTheFellsEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
for (UUID targetId : getTargetPointer().getTargets(game, source)) {
|
|
||||||
game.damagePlayerOrPermanent(
|
|
||||||
targetId, 2, source.getSourceId(), source,
|
|
||||||
game, false, true
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class RavagerOfTheFellsTarget extends TargetPermanent {
|
|
||||||
|
|
||||||
RavagerOfTheFellsTarget() {
|
|
||||||
super(0, 1, StaticFilters.FILTER_PERMANENT_CREATURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private RavagerOfTheFellsTarget(final RavagerOfTheFellsTarget target) {
|
|
||||||
super(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Set<UUID> possibleTargets(UUID sourceControllerId, Ability source, Game game) {
|
|
||||||
Set<UUID> possibleTargets = super.possibleTargets(sourceControllerId, source, game);
|
|
||||||
|
|
||||||
Player needPlayer = game.getPlayerOrPlaneswalkerController(source.getFirstTarget());
|
|
||||||
if (needPlayer == null) {
|
|
||||||
// playable or not selected - use any
|
|
||||||
} else {
|
|
||||||
// filter by controller
|
|
||||||
possibleTargets.removeIf(id -> {
|
|
||||||
Permanent permanent = game.getPermanent(id);
|
|
||||||
return permanent == null
|
|
||||||
|| permanent.getId().equals(source.getFirstTarget())
|
|
||||||
|| !permanent.isControlledBy(needPlayer.getId());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return possibleTargets;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RavagerOfTheFellsTarget copy() {
|
|
||||||
return new RavagerOfTheFellsTarget(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
package mage.cards.s;
|
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.abilities.effects.common.AttachEffect;
|
|
||||||
import mage.abilities.effects.common.counter.AddCountersSourceEffect;
|
|
||||||
import mage.abilities.keyword.DisturbAbility;
|
|
||||||
import mage.abilities.keyword.EnchantAbility;
|
|
||||||
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.Outcome;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
import mage.counters.CounterType;
|
|
||||||
import mage.game.Game;
|
|
||||||
import mage.game.permanent.Permanent;
|
|
||||||
import mage.target.TargetPlayer;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author TheElk801
|
|
||||||
*/
|
|
||||||
public final class SinnersJudgment extends CardImpl {
|
|
||||||
|
|
||||||
public SinnersJudgment(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ENCHANTMENT}, "");
|
|
||||||
|
|
||||||
this.subtype.add(SubType.AURA);
|
|
||||||
this.subtype.add(SubType.CURSE);
|
|
||||||
this.color.setWhite(true);
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// Enchant player
|
|
||||||
TargetPlayer auraTarget = new TargetPlayer();
|
|
||||||
this.getSpellAbility().addTarget(auraTarget);
|
|
||||||
this.getSpellAbility().addEffect(new AttachEffect(Outcome.BoostCreature));
|
|
||||||
this.addAbility(new EnchantAbility(auraTarget));
|
|
||||||
|
|
||||||
// At the beginning of your upkeep, put a judgment counter on Sinner's Judgment. Then if there are three or more judgment counters on it, enchanted player loses the game.
|
|
||||||
Ability ability = new BeginningOfUpkeepTriggeredAbility(new AddCountersSourceEffect(CounterType.JUDGMENT.createInstance()));
|
|
||||||
ability.addEffect(new SinnersJudgmentEffect());
|
|
||||||
this.addAbility(ability);
|
|
||||||
|
|
||||||
// If Sinner's Judgment would be put into a graveyard from anywhere, exile it instead.
|
|
||||||
this.addAbility(DisturbAbility.makeBackAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
private SinnersJudgment(final SinnersJudgment card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SinnersJudgment copy() {
|
|
||||||
return new SinnersJudgment(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SinnersJudgmentEffect extends OneShotEffect {
|
|
||||||
|
|
||||||
SinnersJudgmentEffect() {
|
|
||||||
super(Outcome.Benefit);
|
|
||||||
staticText = "Then if there are three or more judgment counters on it, enchanted player loses the game";
|
|
||||||
}
|
|
||||||
|
|
||||||
private SinnersJudgmentEffect(final SinnersJudgmentEffect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SinnersJudgmentEffect copy() {
|
|
||||||
return new SinnersJudgmentEffect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
return Optional
|
|
||||||
.ofNullable(source.getSourcePermanentOrLKI(game))
|
|
||||||
.filter(permanent -> permanent.getCounters(game).getCount(CounterType.JUDGMENT) >= 3)
|
|
||||||
.map(Permanent::getAttachedTo)
|
|
||||||
.map(game::getPlayer)
|
|
||||||
.filter(player -> {
|
|
||||||
player.lost(game);
|
|
||||||
return true;
|
|
||||||
})
|
|
||||||
.isPresent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,45 +2,73 @@ package mage.cards.s;
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
import mage.abilities.common.EntersBattlefieldTriggeredAbility;
|
||||||
|
import mage.abilities.common.SimpleActivatedAbility;
|
||||||
|
import mage.abilities.costs.common.TapTargetCost;
|
||||||
import mage.abilities.effects.common.DamageTargetEffect;
|
import mage.abilities.effects.common.DamageTargetEffect;
|
||||||
|
import mage.abilities.effects.common.continuous.AddCardTypeSourceEffect;
|
||||||
import mage.abilities.keyword.CraftAbility;
|
import mage.abilities.keyword.CraftAbility;
|
||||||
|
import mage.abilities.keyword.CrewAbility;
|
||||||
import mage.abilities.keyword.FlashAbility;
|
import mage.abilities.keyword.FlashAbility;
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.Duration;
|
||||||
|
import mage.constants.SubType;
|
||||||
import mage.filter.FilterPermanent;
|
import mage.filter.FilterPermanent;
|
||||||
|
import mage.filter.common.FilterControlledArtifactPermanent;
|
||||||
|
import mage.filter.common.FilterControlledPermanent;
|
||||||
import mage.filter.common.FilterOpponentsCreaturePermanent;
|
import mage.filter.common.FilterOpponentsCreaturePermanent;
|
||||||
|
import mage.filter.predicate.mageobject.AnotherPredicate;
|
||||||
import mage.filter.predicate.permanent.TappedPredicate;
|
import mage.filter.predicate.permanent.TappedPredicate;
|
||||||
import mage.target.TargetPermanent;
|
import mage.target.TargetPermanent;
|
||||||
|
import mage.target.common.TargetControlledPermanent;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public final class SpringLoadedSawblades extends CardImpl {
|
public final class SpringLoadedSawblades extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
|
private static final FilterControlledPermanent bladeWheelFilter
|
||||||
|
= new FilterControlledArtifactPermanent("other untapped artifacts you control");
|
||||||
private static final FilterPermanent filter
|
private static final FilterPermanent filter
|
||||||
= new FilterOpponentsCreaturePermanent("tapped creature an opponent controls");
|
= new FilterOpponentsCreaturePermanent("tapped creature an opponent controls");
|
||||||
|
|
||||||
static {
|
static {
|
||||||
filter.add(TappedPredicate.TAPPED);
|
filter.add(TappedPredicate.TAPPED);
|
||||||
|
bladeWheelFilter.add(AnotherPredicate.instance);
|
||||||
|
bladeWheelFilter.add(TappedPredicate.UNTAPPED);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpringLoadedSawblades(UUID ownerId, CardSetInfo setInfo) {
|
public SpringLoadedSawblades(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.ARTIFACT}, "{1}{W}");
|
super(ownerId, setInfo,
|
||||||
this.secondSideCardClazz = mage.cards.b.BladewheelChariot.class;
|
new CardType[]{CardType.ARTIFACT}, new SubType[]{}, "{1}{W}",
|
||||||
|
"Bladewheel Chariot",
|
||||||
|
new CardType[]{CardType.ARTIFACT}, new SubType[]{SubType.VEHICLE}, "W");
|
||||||
|
|
||||||
|
this.getRightHalfCard().setPT(5, 5);
|
||||||
|
|
||||||
// Flash
|
// Flash
|
||||||
this.addAbility(FlashAbility.getInstance());
|
this.getLeftHalfCard().addAbility(FlashAbility.getInstance());
|
||||||
|
|
||||||
// When Spring-Loaded Sawblades enters the battlefield, it deals 5 damage to target tapped creature an opponent controls.
|
// When Spring-Loaded Sawblades enters the battlefield, it deals 5 damage to target tapped creature an opponent controls.
|
||||||
Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(5, "it"));
|
Ability ability = new EntersBattlefieldTriggeredAbility(new DamageTargetEffect(5, "it"));
|
||||||
ability.addTarget(new TargetPermanent(filter));
|
ability.addTarget(new TargetPermanent(filter));
|
||||||
this.addAbility(ability);
|
this.getLeftHalfCard().addAbility(ability);
|
||||||
|
|
||||||
// Craft with artifact {3}{W}
|
// Craft with artifact {3}{W}
|
||||||
this.addAbility(new CraftAbility("{3}{W}"));
|
this.getLeftHalfCard().addAbility(new CraftAbility("{3}{W}"));
|
||||||
|
|
||||||
|
// Bladewheel Chariot
|
||||||
|
|
||||||
|
// Tap two other untapped artifacts you control: Bladewheel Chariot becomes an artifact creature until end of turn.
|
||||||
|
this.getRightHalfCard().addAbility(new SimpleActivatedAbility(new AddCardTypeSourceEffect(
|
||||||
|
Duration.EndOfTurn, CardType.ARTIFACT, CardType.CREATURE
|
||||||
|
).setText("{this} becomes an artifact creature until end of turn"), new TapTargetCost(new TargetControlledPermanent(2, bladeWheelFilter))));
|
||||||
|
|
||||||
|
// Crew 1
|
||||||
|
this.getRightHalfCard().addAbility(new CrewAbility(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private SpringLoadedSawblades(final SpringLoadedSawblades card) {
|
private SpringLoadedSawblades(final SpringLoadedSawblades card) {
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,21 @@
|
||||||
package mage.cards.s;
|
package mage.cards.s;
|
||||||
|
|
||||||
import mage.MageObject;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
|
import mage.abilities.common.ActivateAsSorceryActivatedAbility;
|
||||||
|
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.MillCardsTargetEffect;
|
import mage.abilities.effects.common.MillCardsTargetEffect;
|
||||||
|
import mage.abilities.effects.common.ReturnToHandSourceEffect;
|
||||||
|
import mage.abilities.keyword.SkulkAbility;
|
||||||
import mage.abilities.keyword.TransformAbility;
|
import mage.abilities.keyword.TransformAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
|
import mage.cards.TransformingDoubleFacedCardHalf;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
|
import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
@ -22,22 +26,34 @@ import java.util.UUID;
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public final class StartledAwake extends CardImpl {
|
public final class StartledAwake extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
public StartledAwake(UUID ownerId, CardSetInfo setInfo) {
|
public StartledAwake(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.SORCERY}, "{2}{U}{U}");
|
super(ownerId, setInfo,
|
||||||
|
new CardType[]{CardType.SORCERY}, new SubType[]{}, "{2}{U}{U}",
|
||||||
|
"Persistent Nightmare",
|
||||||
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.NIGHTMARE}, "U");
|
||||||
|
|
||||||
this.secondSideCardClazz = mage.cards.p.PersistentNightmare.class;
|
this.getRightHalfCard().setPT(1, 1);
|
||||||
|
|
||||||
// Target opponent puts the top thirteen cards of their library into their graveyard.
|
// Target opponent puts the top thirteen cards of their library into their graveyard.
|
||||||
this.getSpellAbility().addTarget(new TargetOpponent());
|
this.getLeftHalfCard().getSpellAbility().addTarget(new TargetOpponent());
|
||||||
this.getSpellAbility().addEffect(new MillCardsTargetEffect(13));
|
this.getLeftHalfCard().getSpellAbility().addEffect(new MillCardsTargetEffect(13));
|
||||||
|
|
||||||
// {3}{U}{U}: Put Startled Awake from your graveyard onto the battlefield transformed. Activate this ability only any time you could cast a sorcery.
|
// {3}{U}{U}: Put Startled Awake from your graveyard onto the battlefield transformed. Activate this ability only any time you could cast a sorcery.
|
||||||
this.addAbility(new TransformAbility());
|
this.getLeftHalfCard().addAbility(new ActivateAsSorceryActivatedAbility(
|
||||||
this.addAbility(new ActivateAsSorceryActivatedAbility(
|
|
||||||
Zone.GRAVEYARD, new StartledAwakeReturnTransformedEffect(), new ManaCostsImpl<>("{3}{U}{U}")
|
Zone.GRAVEYARD, new StartledAwakeReturnTransformedEffect(), new ManaCostsImpl<>("{3}{U}{U}")
|
||||||
));
|
));
|
||||||
|
|
||||||
|
// Persistent Nightmare
|
||||||
|
|
||||||
|
// Skulk
|
||||||
|
this.getRightHalfCard().addAbility(new SkulkAbility());
|
||||||
|
|
||||||
|
// When Persistent Nightmare deals combat damage to a player, return it to its owner's hand.
|
||||||
|
this.getRightHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(
|
||||||
|
new ReturnToHandSourceEffect(), false
|
||||||
|
).setTriggerPhrase("When {this} deals combat damage to a player, "));
|
||||||
}
|
}
|
||||||
|
|
||||||
private StartledAwake(final StartledAwake card) {
|
private StartledAwake(final StartledAwake card) {
|
||||||
|
|
@ -76,8 +92,12 @@ class StartledAwakeReturnTransformedEffect extends OneShotEffect {
|
||||||
if (game.getState().getZone(source.getSourceId()) != Zone.GRAVEYARD) {
|
if (game.getState().getZone(source.getSourceId()) != Zone.GRAVEYARD) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + source.getSourceId(), true);
|
Card backSide = ((TransformingDoubleFacedCardHalf) card).getOtherSide();
|
||||||
controller.moveCards(card, Zone.BATTLEFIELD, source, game);
|
if (backSide == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + backSide.getId(), true);
|
||||||
|
controller.moveCards(backSide, Zone.BATTLEFIELD, source, game);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
package mage.cards.s;
|
package mage.cards.s;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
|
import mage.abilities.common.AttacksWithCreaturesTriggeredAbility;
|
||||||
import mage.abilities.common.UnlockThisDoorTriggeredAbility;
|
import mage.abilities.common.UnlockThisDoorTriggeredAbility;
|
||||||
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
|
import mage.abilities.effects.common.ReturnFromGraveyardToBattlefieldTargetEffect;
|
||||||
|
|
@ -19,6 +17,8 @@ import mage.filter.predicate.mageobject.ManaValuePredicate;
|
||||||
import mage.target.common.TargetAttackingCreature;
|
import mage.target.common.TargetAttackingCreature;
|
||||||
import mage.target.common.TargetCardInYourGraveyard;
|
import mage.target.common.TargetCardInYourGraveyard;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author oscscull
|
* @author oscscull
|
||||||
|
|
@ -45,19 +45,19 @@ public final class SurgicalSuiteHospitalRoom extends RoomCard {
|
||||||
"{1}{W}", "{3}{W}", SpellAbilityType.SPLIT);
|
"{1}{W}", "{3}{W}", SpellAbilityType.SPLIT);
|
||||||
this.subtype.add(SubType.ROOM);
|
this.subtype.add(SubType.ROOM);
|
||||||
|
|
||||||
// Left half ability - "When you unlock this door, return target creature card with mana value 3 or
|
// Left half ability - "When you unlock this door, return target creature card with mana value 3 or less from your graveyard to the battlefield."
|
||||||
// less from your graveyard to the battlefield."
|
|
||||||
UnlockThisDoorTriggeredAbility left = new UnlockThisDoorTriggeredAbility(
|
UnlockThisDoorTriggeredAbility left = new UnlockThisDoorTriggeredAbility(
|
||||||
new ReturnFromGraveyardToBattlefieldTargetEffect(), false, true);
|
new ReturnFromGraveyardToBattlefieldTargetEffect(), false, true);
|
||||||
left.addTarget(new TargetCardInYourGraveyard(filter));
|
left.addTarget(new TargetCardInYourGraveyard(filter));
|
||||||
|
this.getLeftHalfCard().addAbility(left);
|
||||||
|
|
||||||
// Right half ability - "Whenever you attack, put a +1/+1 counter on target attacking creature."
|
// Right half ability - "Whenever you attack, put a +1/+1 counter on target attacking creature."
|
||||||
AttacksWithCreaturesTriggeredAbility right = new AttacksWithCreaturesTriggeredAbility(
|
AttacksWithCreaturesTriggeredAbility right = new AttacksWithCreaturesTriggeredAbility(
|
||||||
new AddCountersTargetEffect(CounterType.P1P1.createInstance()), 1
|
new AddCountersTargetEffect(CounterType.P1P1.createInstance()), 1
|
||||||
);
|
);
|
||||||
right.addTarget(new TargetAttackingCreature());
|
right.addTarget(new TargetAttackingCreature());
|
||||||
|
this.getRightHalfCard().addAbility(right);
|
||||||
|
|
||||||
this.addRoomAbilities(left, right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SurgicalSuiteHospitalRoom(final SurgicalSuiteHospitalRoom card) {
|
private SurgicalSuiteHospitalRoom(final SurgicalSuiteHospitalRoom card) {
|
||||||
|
|
|
||||||
|
|
@ -1,50 +1,89 @@
|
||||||
package mage.cards.t;
|
package mage.cards.t;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.abilities.Ability;
|
||||||
import mage.constants.Pronoun;
|
import mage.abilities.LoyaltyAbility;
|
||||||
|
import mage.abilities.common.AttacksAllTriggeredAbility;
|
||||||
|
import mage.abilities.common.delayed.UntilYourNextTurnDelayedTriggeredAbility;
|
||||||
|
import mage.abilities.dynamicvalue.DynamicValue;
|
||||||
|
import mage.abilities.dynamicvalue.common.CardsInControllerLibraryCount;
|
||||||
|
import mage.abilities.dynamicvalue.common.HalfValue;
|
||||||
|
import mage.abilities.effects.Effect;
|
||||||
|
import mage.abilities.effects.OneShotEffect;
|
||||||
|
import mage.abilities.effects.common.*;
|
||||||
|
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
||||||
|
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
|
||||||
|
import mage.cards.Card;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
|
import mage.constants.*;
|
||||||
import mage.abilities.common.AttacksTriggeredAbility;
|
import mage.abilities.common.AttacksTriggeredAbility;
|
||||||
import mage.abilities.common.DrawNthCardTriggeredAbility;
|
import mage.abilities.common.DrawNthCardTriggeredAbility;
|
||||||
import mage.abilities.effects.common.ExileAndReturnSourceEffect;
|
|
||||||
import mage.abilities.effects.keyword.InvestigateEffect;
|
import mage.abilities.effects.keyword.InvestigateEffect;
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
import mage.abilities.keyword.FlyingAbility;
|
||||||
import mage.abilities.keyword.TransformAbility;
|
import mage.abilities.keyword.TransformAbility;
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
import mage.constants.CardType;
|
import mage.filter.StaticFilters;
|
||||||
import mage.constants.PutCards;
|
import mage.game.Game;
|
||||||
import mage.constants.SubType;
|
import mage.game.command.emblems.TamiyoSeasonedScholarEmblem;
|
||||||
import mage.constants.SuperType;
|
import mage.target.common.TargetCardInYourGraveyard;
|
||||||
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Susucr
|
* @author Susucr
|
||||||
*/
|
*/
|
||||||
public final class TamiyoInquisitiveStudent extends CardImpl {
|
public final class TamiyoInquisitiveStudent extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
|
private static final DynamicValue xValue = new HalfValue(CardsInControllerLibraryCount.instance, true);
|
||||||
|
|
||||||
public TamiyoInquisitiveStudent(UUID ownerId, CardSetInfo setInfo) {
|
public TamiyoInquisitiveStudent(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{U}");
|
super(ownerId, setInfo,
|
||||||
|
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.CREATURE}, new SubType[]{SubType.MOONFOLK, SubType.WIZARD}, "{U}",
|
||||||
|
"Tamiyo, Seasoned Scholar",
|
||||||
|
new SuperType[]{SuperType.LEGENDARY}, new CardType[]{CardType.PLANESWALKER}, new SubType[]{SubType.TAMIYO}, "GU");
|
||||||
|
|
||||||
this.supertype.add(SuperType.LEGENDARY);
|
this.getLeftHalfCard().setPT(0, 3);
|
||||||
this.subtype.add(SubType.MOONFOLK);
|
this.getRightHalfCard().setStartingLoyalty(2);
|
||||||
this.subtype.add(SubType.WIZARD);
|
|
||||||
this.power = new MageInt(0);
|
|
||||||
this.toughness = new MageInt(3);
|
|
||||||
|
|
||||||
this.secondSideCardClazz = TamiyoSeasonedScholar.class;
|
|
||||||
|
|
||||||
// Flying
|
// Flying
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
this.getLeftHalfCard().addAbility(FlyingAbility.getInstance());
|
||||||
|
|
||||||
// Whenever Tamiyo, Inquisitive Student attacks, investigate.
|
// Whenever Tamiyo, Inquisitive Student attacks, investigate.
|
||||||
this.addAbility(new AttacksTriggeredAbility(new InvestigateEffect()));
|
this.getLeftHalfCard().addAbility(new AttacksTriggeredAbility(new InvestigateEffect()));
|
||||||
|
|
||||||
// When you draw your third card in a turn, exile Tamiyo, then return her to the battlefield transformed under her owner's control.
|
// When you draw your third card in a turn, exile Tamiyo, then return her to the battlefield transformed under her owner's control.
|
||||||
this.addAbility(new TransformAbility());
|
this.getLeftHalfCard().addAbility(new TransformAbility());
|
||||||
this.addAbility(new DrawNthCardTriggeredAbility(
|
this.getLeftHalfCard().addAbility(new DrawNthCardTriggeredAbility(
|
||||||
new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE),
|
new ExileAndReturnSourceEffect(PutCards.BATTLEFIELD_TRANSFORMED, Pronoun.SHE),
|
||||||
false, 3
|
false, 3
|
||||||
).setTriggerPhrase("When you draw your third card in a turn, "));
|
).setTriggerPhrase("When you draw your third card in a turn, "));
|
||||||
|
|
||||||
|
// Tamiyo, Seasoned Scholar
|
||||||
|
|
||||||
|
// +2: Until your next turn, whenever a creature attacks you or a planeswalker you control, it gets -1/-0 until end of turn.
|
||||||
|
this.getRightHalfCard().addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect(
|
||||||
|
new UntilYourNextTurnDelayedTriggeredAbility(
|
||||||
|
new AttacksAllTriggeredAbility(
|
||||||
|
new BoostTargetEffect(-1, 0, Duration.EndOfTurn)
|
||||||
|
.setText("it gets -1/-0 until end of turn"),
|
||||||
|
false, StaticFilters.FILTER_PERMANENT_CREATURE,
|
||||||
|
SetTargetPointer.PERMANENT, true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
), 2));
|
||||||
|
|
||||||
|
// -3: Return target instant or sorcery card from your graveyard to your hand. If it's a green card, add one mana of any color.
|
||||||
|
Ability ability = new LoyaltyAbility(new TamiyoSeasonedScholarMinus3Effect(), -3);
|
||||||
|
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD));
|
||||||
|
this.getRightHalfCard().addAbility(ability);
|
||||||
|
|
||||||
|
// -7: Draw cards equal to half the number of cards in your library, rounded up. You get an emblem with "You have no maximum hand size."
|
||||||
|
ability = new LoyaltyAbility(
|
||||||
|
new DrawCardSourceControllerEffect(xValue)
|
||||||
|
.setText("Draw cards equal to half the number of cards in your library, rounded up."),
|
||||||
|
-7
|
||||||
|
);
|
||||||
|
ability.addEffect(new GetEmblemEffect(new TamiyoSeasonedScholarEmblem()));
|
||||||
|
this.getRightHalfCard().addAbility(ability);
|
||||||
}
|
}
|
||||||
|
|
||||||
private TamiyoInquisitiveStudent(final TamiyoInquisitiveStudent card) {
|
private TamiyoInquisitiveStudent(final TamiyoInquisitiveStudent card) {
|
||||||
|
|
@ -56,3 +95,36 @@ public final class TamiyoInquisitiveStudent extends CardImpl {
|
||||||
return new TamiyoInquisitiveStudent(this);
|
return new TamiyoInquisitiveStudent(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TamiyoSeasonedScholarMinus3Effect extends OneShotEffect {
|
||||||
|
|
||||||
|
TamiyoSeasonedScholarMinus3Effect() {
|
||||||
|
super(Outcome.DrawCard);
|
||||||
|
this.staticText = "Return target instant or sorcery card from your graveyard to your hand. "
|
||||||
|
+ "If it's a green card, add one mana of any color";
|
||||||
|
}
|
||||||
|
|
||||||
|
private TamiyoSeasonedScholarMinus3Effect(final TamiyoSeasonedScholarMinus3Effect effect) {
|
||||||
|
super(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TamiyoSeasonedScholarMinus3Effect copy() {
|
||||||
|
return new TamiyoSeasonedScholarMinus3Effect(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean apply(Game game, Ability source) {
|
||||||
|
Card card = game.getCard(source.getFirstTarget());
|
||||||
|
if (card == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Effect effect = new ReturnToHandTargetEffect();
|
||||||
|
effect.setTargetPointer(getTargetPointer().copy());
|
||||||
|
effect.apply(game, source);
|
||||||
|
if (card.getColor(game).isGreen()) {
|
||||||
|
new AddManaOfAnyColorEffect().apply(game, source);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,115 +0,0 @@
|
||||||
package mage.cards.t;
|
|
||||||
|
|
||||||
import mage.abilities.Ability;
|
|
||||||
import mage.abilities.LoyaltyAbility;
|
|
||||||
import mage.abilities.common.AttacksAllTriggeredAbility;
|
|
||||||
import mage.abilities.common.delayed.UntilYourNextTurnDelayedTriggeredAbility;
|
|
||||||
import mage.abilities.dynamicvalue.DynamicValue;
|
|
||||||
import mage.abilities.dynamicvalue.common.CardsInControllerLibraryCount;
|
|
||||||
import mage.abilities.dynamicvalue.common.HalfValue;
|
|
||||||
import mage.abilities.effects.Effect;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
|
||||||
import mage.abilities.effects.common.CreateDelayedTriggeredAbilityEffect;
|
|
||||||
import mage.abilities.effects.common.DrawCardSourceControllerEffect;
|
|
||||||
import mage.abilities.effects.common.GetEmblemEffect;
|
|
||||||
import mage.abilities.effects.common.ReturnToHandTargetEffect;
|
|
||||||
import mage.abilities.effects.common.continuous.BoostTargetEffect;
|
|
||||||
import mage.abilities.effects.mana.AddManaOfAnyColorEffect;
|
|
||||||
import mage.cards.Card;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.*;
|
|
||||||
import mage.filter.StaticFilters;
|
|
||||||
import mage.game.Game;
|
|
||||||
import mage.game.command.emblems.TamiyoSeasonedScholarEmblem;
|
|
||||||
import mage.target.common.TargetCardInYourGraveyard;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Susucr
|
|
||||||
*/
|
|
||||||
public final class TamiyoSeasonedScholar extends CardImpl {
|
|
||||||
|
|
||||||
private static final DynamicValue xValue = new HalfValue(CardsInControllerLibraryCount.instance, true);
|
|
||||||
|
|
||||||
public TamiyoSeasonedScholar(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.PLANESWALKER}, "");
|
|
||||||
|
|
||||||
this.supertype.add(SuperType.LEGENDARY);
|
|
||||||
this.subtype.add(SubType.TAMIYO);
|
|
||||||
this.setStartingLoyalty(2);
|
|
||||||
|
|
||||||
this.color.setGreen(true);
|
|
||||||
this.color.setBlue(true);
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// +2: Until your next turn, whenever a creature attacks you or a planeswalker you control, it gets -1/-0 until end of turn.
|
|
||||||
this.addAbility(new LoyaltyAbility(new CreateDelayedTriggeredAbilityEffect(
|
|
||||||
new UntilYourNextTurnDelayedTriggeredAbility(
|
|
||||||
new AttacksAllTriggeredAbility(
|
|
||||||
new BoostTargetEffect(-1, 0, Duration.EndOfTurn)
|
|
||||||
.setText("it gets -1/-0 until end of turn"),
|
|
||||||
false, StaticFilters.FILTER_PERMANENT_CREATURE,
|
|
||||||
SetTargetPointer.PERMANENT, true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
), 2));
|
|
||||||
|
|
||||||
// -3: Return target instant or sorcery card from your graveyard to your hand. If it's a green card, add one mana of any color.
|
|
||||||
Ability ability = new LoyaltyAbility(new TamiyoSeasonedScholarMinus3Effect(), -3);
|
|
||||||
ability.addTarget(new TargetCardInYourGraveyard(StaticFilters.FILTER_CARD_INSTANT_OR_SORCERY_FROM_YOUR_GRAVEYARD));
|
|
||||||
this.addAbility(ability);
|
|
||||||
|
|
||||||
// -7: Draw cards equal to half the number of cards in your library, rounded up. You get an emblem with "You have no maximum hand size."
|
|
||||||
ability = new LoyaltyAbility(
|
|
||||||
new DrawCardSourceControllerEffect(xValue)
|
|
||||||
.setText("Draw cards equal to half the number of cards in your library, rounded up."),
|
|
||||||
-7
|
|
||||||
);
|
|
||||||
ability.addEffect(new GetEmblemEffect(new TamiyoSeasonedScholarEmblem()));
|
|
||||||
this.addAbility(ability);
|
|
||||||
}
|
|
||||||
|
|
||||||
private TamiyoSeasonedScholar(final TamiyoSeasonedScholar card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TamiyoSeasonedScholar copy() {
|
|
||||||
return new TamiyoSeasonedScholar(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class TamiyoSeasonedScholarMinus3Effect extends OneShotEffect {
|
|
||||||
|
|
||||||
TamiyoSeasonedScholarMinus3Effect() {
|
|
||||||
super(Outcome.DrawCard);
|
|
||||||
this.staticText = "Return target instant or sorcery card from your graveyard to your hand. "
|
|
||||||
+ "If it's a green card, add one mana of any color";
|
|
||||||
}
|
|
||||||
|
|
||||||
private TamiyoSeasonedScholarMinus3Effect(final TamiyoSeasonedScholarMinus3Effect effect) {
|
|
||||||
super(effect);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TamiyoSeasonedScholarMinus3Effect copy() {
|
|
||||||
return new TamiyoSeasonedScholarMinus3Effect(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean apply(Game game, Ability source) {
|
|
||||||
Card card = game.getCard(source.getFirstTarget());
|
|
||||||
if (card == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Effect effect = new ReturnToHandTargetEffect();
|
|
||||||
effect.setTargetPointer(getTargetPointer().copy());
|
|
||||||
effect.apply(game, source);
|
|
||||||
if (card.getColor(game).isGreen()) {
|
|
||||||
new AddManaOfAnyColorEffect().apply(game, source);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
package mage.cards.t;
|
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.common.WerewolfBackTriggeredAbility;
|
|
||||||
import mage.abilities.keyword.TrampleAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author fireshoes
|
|
||||||
*/
|
|
||||||
public final class TimberShredder extends CardImpl {
|
|
||||||
|
|
||||||
public TimberShredder(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
|
|
||||||
this.subtype.add(SubType.WEREWOLF);
|
|
||||||
this.power = new MageInt(4);
|
|
||||||
this.toughness = new MageInt(2);
|
|
||||||
this.color.setGreen(true);
|
|
||||||
|
|
||||||
// this card is the second face of double-faced card
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// Trample
|
|
||||||
this.addAbility(TrampleAbility.getInstance());
|
|
||||||
|
|
||||||
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Timber Shredder.
|
|
||||||
this.addAbility(new WerewolfBackTriggeredAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
private TimberShredder(final TimberShredder card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TimberShredder copy() {
|
|
||||||
return new TimberShredder(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -213,8 +213,8 @@ class TinybonesBaubleBurglarSpendAnyManaEffect extends AsThoughEffectImpl implem
|
||||||
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
||||||
} else if (card instanceof CardWithSpellOption) {
|
} else if (card instanceof CardWithSpellOption) {
|
||||||
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
||||||
} else if (card instanceof ModalDoubleFacedCard) {
|
} else if (card instanceof DoubleFacedCard) {
|
||||||
cardState = game.getLastKnownInformationCard(((ModalDoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED);
|
cardState = game.getLastKnownInformationCard(((DoubleFacedCard) card).getLeftHalfCard().getId(), Zone.EXILED);
|
||||||
} else {
|
} else {
|
||||||
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
cardState = game.getLastKnownInformationCard(card.getId(), Zone.EXILED);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,11 +45,11 @@ public final class UnholyAnnexRitualChamber extends RoomCard {
|
||||||
new PermanentsOnTheBattlefieldCondition(filter), "If you control a Demon, each opponent loses 2 life and you gain 2 life. Otherwise, you lose 2 life"
|
new PermanentsOnTheBattlefieldCondition(filter), "If you control a Demon, each opponent loses 2 life and you gain 2 life. Otherwise, you lose 2 life"
|
||||||
));
|
));
|
||||||
left.addHint(new ConditionHint(new PermanentsOnTheBattlefieldCondition(filter), "You control a Demon"));
|
left.addHint(new ConditionHint(new PermanentsOnTheBattlefieldCondition(filter), "You control a Demon"));
|
||||||
|
this.getLeftHalfCard().addAbility(left);
|
||||||
|
|
||||||
// Ritual Chamber: When you unlock this door, create a 6/6 black Demon creature token with flying.
|
// Ritual Chamber: When you unlock this door, create a 6/6 black Demon creature token with flying.
|
||||||
Ability right = new UnlockThisDoorTriggeredAbility(new CreateTokenEffect(new Demon66Token()), false, false);
|
Ability right = new UnlockThisDoorTriggeredAbility(new CreateTokenEffect(new Demon66Token()), false, false);
|
||||||
|
this.getRightHalfCard().addAbility(right);
|
||||||
this.addRoomAbilities(left, right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private UnholyAnnexRitualChamber(final UnholyAnnexRitualChamber card) {
|
private UnholyAnnexRitualChamber(final UnholyAnnexRitualChamber card) {
|
||||||
|
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
|
|
||||||
package mage.cards.u;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.keyword.CantBeBlockedSourceAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author fireshoes
|
|
||||||
*/
|
|
||||||
public final class UnimpededTrespasser extends CardImpl {
|
|
||||||
|
|
||||||
public UnimpededTrespasser(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId,setInfo,new CardType[]{CardType.CREATURE},"");
|
|
||||||
this.subtype.add(SubType.SPIRIT);
|
|
||||||
this.power = new MageInt(3);
|
|
||||||
this.toughness = new MageInt(3);
|
|
||||||
this.color.setBlue(true);
|
|
||||||
|
|
||||||
// this card is the second face of double-faced card
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// Unimpeded Trespasser can't be blocked.
|
|
||||||
this.addAbility(new CantBeBlockedSourceAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
private UnimpededTrespasser(final UnimpededTrespasser card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public UnimpededTrespasser copy() {
|
|
||||||
return new UnimpededTrespasser(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
|
|
||||||
package mage.cards.u;
|
package mage.cards.u;
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
import mage.abilities.common.DealsCombatDamageToAPlayerTriggeredAbility;
|
||||||
import mage.abilities.effects.common.TransformSourceEffect;
|
import mage.abilities.effects.common.TransformSourceEffect;
|
||||||
|
import mage.abilities.keyword.CantBeBlockedSourceAbility;
|
||||||
import mage.abilities.keyword.SkulkAbility;
|
import mage.abilities.keyword.SkulkAbility;
|
||||||
import mage.abilities.keyword.TransformAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
import mage.cards.CardSetInfo;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
|
|
||||||
|
|
@ -16,23 +15,27 @@ import java.util.UUID;
|
||||||
/**
|
/**
|
||||||
* @author fireshoes
|
* @author fireshoes
|
||||||
*/
|
*/
|
||||||
public final class UninvitedGeist extends CardImpl {
|
public final class UninvitedGeist extends TransformingDoubleFacedCard {
|
||||||
|
|
||||||
public UninvitedGeist(UUID ownerId, CardSetInfo setInfo) {
|
public UninvitedGeist(UUID ownerId, CardSetInfo setInfo) {
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "{2}{U}");
|
super(ownerId, setInfo,
|
||||||
this.subtype.add(SubType.SPIRIT);
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "{2}{U}",
|
||||||
this.power = new MageInt(2);
|
"Unimpeded Trespasser",
|
||||||
this.toughness = new MageInt(2);
|
new CardType[]{CardType.CREATURE}, new SubType[]{SubType.SPIRIT}, "U");
|
||||||
|
|
||||||
this.secondSideCardClazz = mage.cards.u.UnimpededTrespasser.class;
|
this.getLeftHalfCard().setPT(2, 2);
|
||||||
|
this.getRightHalfCard().setPT(3, 3);
|
||||||
|
|
||||||
// Skulk (This creature can't be blocked by creatures with greater power.)
|
// Skulk (This creature can't be blocked by creatures with greater power.)
|
||||||
this.addAbility(new SkulkAbility());
|
this.getLeftHalfCard().addAbility(new SkulkAbility());
|
||||||
|
|
||||||
// When Uninvited Geist deals combat damage to a player, transform it.
|
// When Uninvited Geist deals combat damage to a player, transform it.
|
||||||
this.addAbility(new TransformAbility());
|
this.getLeftHalfCard().addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new TransformSourceEffect(), false));
|
||||||
this.addAbility(new DealsCombatDamageToAPlayerTriggeredAbility(new TransformSourceEffect(), false));
|
|
||||||
|
|
||||||
|
// Unimpeded Trespasser
|
||||||
|
|
||||||
|
// Unimpeded Trespasser can't be blocked.
|
||||||
|
this.getRightHalfCard().addAbility(new CantBeBlockedSourceAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
private UninvitedGeist(final UninvitedGeist card) {
|
private UninvitedGeist(final UninvitedGeist card) {
|
||||||
|
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
package mage.cards.w;
|
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.keyword.DisturbAbility;
|
|
||||||
import mage.abilities.keyword.FlyingAbility;
|
|
||||||
import mage.cards.CardImpl;
|
|
||||||
import mage.cards.CardSetInfo;
|
|
||||||
import mage.constants.CardType;
|
|
||||||
import mage.constants.SubType;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author TheElk801
|
|
||||||
*/
|
|
||||||
public final class Waildrifter extends CardImpl {
|
|
||||||
|
|
||||||
public Waildrifter(UUID ownerId, CardSetInfo setInfo) {
|
|
||||||
super(ownerId, setInfo, new CardType[]{CardType.CREATURE}, "");
|
|
||||||
|
|
||||||
this.subtype.add(SubType.HIPPOGRIFF);
|
|
||||||
this.subtype.add(SubType.SPIRIT);
|
|
||||||
this.power = new MageInt(2);
|
|
||||||
this.toughness = new MageInt(2);
|
|
||||||
this.color.setBlue(true);
|
|
||||||
this.nightCard = true;
|
|
||||||
|
|
||||||
// Flying
|
|
||||||
this.addAbility(FlyingAbility.getInstance());
|
|
||||||
|
|
||||||
// If Waildrifter would be put into a graveyard from anywhere, exile it instead.
|
|
||||||
this.addAbility(DisturbAbility.makeBackAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Waildrifter(final Waildrifter card) {
|
|
||||||
super(card);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Waildrifter copy() {
|
|
||||||
return new Waildrifter(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -25,6 +25,7 @@ public final class WalkInClosetForgottenCellar extends RoomCard {
|
||||||
|
|
||||||
// Walk-In Closet: You may play lands from your graveyard.
|
// Walk-In Closet: You may play lands from your graveyard.
|
||||||
SimpleStaticAbility left = new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLands());
|
SimpleStaticAbility left = new SimpleStaticAbility(PlayFromGraveyardControllerEffect.playLands());
|
||||||
|
this.getLeftHalfCard().addAbility(left);
|
||||||
|
|
||||||
// Forgotten Cellar: When you unlock this door, you may cast spells from your graveyard this turn, and if a card would be put into your graveyard from anywhere this turn, exile it instead.
|
// Forgotten Cellar: When you unlock this door, you may cast spells from your graveyard this turn, and if a card would be put into your graveyard from anywhere this turn, exile it instead.
|
||||||
UnlockThisDoorTriggeredAbility right = new UnlockThisDoorTriggeredAbility(
|
UnlockThisDoorTriggeredAbility right = new UnlockThisDoorTriggeredAbility(
|
||||||
|
|
@ -34,8 +35,7 @@ public final class WalkInClosetForgottenCellar extends RoomCard {
|
||||||
right.addEffect(new GraveyardFromAnywhereExileReplacementEffect(Duration.EndOfTurn).concatBy(", and")
|
right.addEffect(new GraveyardFromAnywhereExileReplacementEffect(Duration.EndOfTurn).concatBy(", and")
|
||||||
.setText("if a card would be put into your graveyard from anywhere this turn, exile it instead")
|
.setText("if a card would be put into your graveyard from anywhere this turn, exile it instead")
|
||||||
);
|
);
|
||||||
|
this.getRightHalfCard().addAbility(right);
|
||||||
this.addRoomAbilities(left, right);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private WalkInClosetForgottenCellar(final WalkInClosetForgottenCellar card) {
|
private WalkInClosetForgottenCellar(final WalkInClosetForgottenCellar card) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ package mage.sets;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.ExpansionSet;
|
import mage.cards.ExpansionSet;
|
||||||
import mage.cards.repository.CardInfo;
|
import mage.cards.repository.CardInfo;
|
||||||
import mage.cards.repository.CardRepository;
|
|
||||||
import mage.collation.BoosterCollator;
|
import mage.collation.BoosterCollator;
|
||||||
import mage.collation.BoosterStructure;
|
import mage.collation.BoosterStructure;
|
||||||
import mage.collation.CardRun;
|
import mage.collation.CardRun;
|
||||||
|
|
@ -155,7 +154,6 @@ public final class DarkAscension extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Niblis of the Urn", 16, Rarity.UNCOMMON, mage.cards.n.NiblisOfTheUrn.class));
|
cards.add(new SetCardInfo("Niblis of the Urn", 16, Rarity.UNCOMMON, mage.cards.n.NiblisOfTheUrn.class));
|
||||||
cards.add(new SetCardInfo("Predator Ooze", 124, Rarity.RARE, mage.cards.p.PredatorOoze.class));
|
cards.add(new SetCardInfo("Predator Ooze", 124, Rarity.RARE, mage.cards.p.PredatorOoze.class));
|
||||||
cards.add(new SetCardInfo("Pyreheart Wolf", 101, Rarity.UNCOMMON, mage.cards.p.PyreheartWolf.class));
|
cards.add(new SetCardInfo("Pyreheart Wolf", 101, Rarity.UNCOMMON, mage.cards.p.PyreheartWolf.class));
|
||||||
cards.add(new SetCardInfo("Ravager of the Fells", 140, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class));
|
|
||||||
cards.add(new SetCardInfo("Ravenous Demon", 71, Rarity.RARE, mage.cards.r.RavenousDemon.class));
|
cards.add(new SetCardInfo("Ravenous Demon", 71, Rarity.RARE, mage.cards.r.RavenousDemon.class));
|
||||||
cards.add(new SetCardInfo("Ray of Revelation", 17, Rarity.COMMON, mage.cards.r.RayOfRevelation.class));
|
cards.add(new SetCardInfo("Ray of Revelation", 17, Rarity.COMMON, mage.cards.r.RayOfRevelation.class));
|
||||||
cards.add(new SetCardInfo("Reap the Seagraf", 72, Rarity.COMMON, mage.cards.r.ReapTheSeagraf.class));
|
cards.add(new SetCardInfo("Reap the Seagraf", 72, Rarity.COMMON, mage.cards.r.ReapTheSeagraf.class));
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ public final class FromTheVaultTransform extends ExpansionSet {
|
||||||
this.hasBasicLands = false;
|
this.hasBasicLands = false;
|
||||||
|
|
||||||
cards.add(new SetCardInfo("Archangel Avacyn", 1, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class));
|
cards.add(new SetCardInfo("Archangel Avacyn", 1, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class));
|
||||||
cards.add(new SetCardInfo("Avacyn, the Purifier", 1, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class));
|
|
||||||
cards.add(new SetCardInfo("Arguel's Blood Fast", 2, Rarity.MYTHIC, mage.cards.a.ArguelsBloodFast.class));
|
cards.add(new SetCardInfo("Arguel's Blood Fast", 2, Rarity.MYTHIC, mage.cards.a.ArguelsBloodFast.class));
|
||||||
cards.add(new SetCardInfo("Temple of Aclazotz", 2, Rarity.MYTHIC, mage.cards.t.TempleOfAclazotz.class));
|
cards.add(new SetCardInfo("Temple of Aclazotz", 2, Rarity.MYTHIC, mage.cards.t.TempleOfAclazotz.class));
|
||||||
cards.add(new SetCardInfo("Arlinn Kord", 3, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class));
|
cards.add(new SetCardInfo("Arlinn Kord", 3, Rarity.MYTHIC, mage.cards.a.ArlinnKord.class));
|
||||||
|
|
@ -40,7 +39,6 @@ public final class FromTheVaultTransform extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Garruk, the Veil-Cursed", 9, Rarity.MYTHIC, mage.cards.g.GarrukTheVeilCursed.class));
|
cards.add(new SetCardInfo("Garruk, the Veil-Cursed", 9, Rarity.MYTHIC, mage.cards.g.GarrukTheVeilCursed.class));
|
||||||
cards.add(new SetCardInfo("Gisela, the Broken Blade", 10, Rarity.MYTHIC, mage.cards.g.GiselaTheBrokenBlade.class));
|
cards.add(new SetCardInfo("Gisela, the Broken Blade", 10, Rarity.MYTHIC, mage.cards.g.GiselaTheBrokenBlade.class));
|
||||||
cards.add(new SetCardInfo("Huntmaster of the Fells", 11, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class));
|
cards.add(new SetCardInfo("Huntmaster of the Fells", 11, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class));
|
||||||
cards.add(new SetCardInfo("Ravager of the Fells", 11, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class));
|
|
||||||
cards.add(new SetCardInfo("Jace, Vryn's Prodigy", 12, Rarity.MYTHIC, mage.cards.j.JaceVrynsProdigy.class));
|
cards.add(new SetCardInfo("Jace, Vryn's Prodigy", 12, Rarity.MYTHIC, mage.cards.j.JaceVrynsProdigy.class));
|
||||||
cards.add(new SetCardInfo("Jace, Telepath Unbound", 12, Rarity.MYTHIC, mage.cards.j.JaceTelepathUnbound.class));
|
cards.add(new SetCardInfo("Jace, Telepath Unbound", 12, Rarity.MYTHIC, mage.cards.j.JaceTelepathUnbound.class));
|
||||||
cards.add(new SetCardInfo("Kytheon, Hero of Akros", 13, Rarity.MYTHIC, mage.cards.k.KytheonHeroOfAkros.class));
|
cards.add(new SetCardInfo("Kytheon, Hero of Akros", 13, Rarity.MYTHIC, mage.cards.k.KytheonHeroOfAkros.class));
|
||||||
|
|
|
||||||
|
|
@ -421,8 +421,6 @@ public final class InnistradCrimsonVow extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Sigarda's Summons", 36, Rarity.RARE, mage.cards.s.SigardasSummons.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Sigarda's Summons", 36, Rarity.RARE, mage.cards.s.SigardasSummons.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Sigarda's Summons", 404, Rarity.RARE, mage.cards.s.SigardasSummons.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Sigarda's Summons", 404, Rarity.RARE, mage.cards.s.SigardasSummons.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Sigardian Paladin", 247, Rarity.UNCOMMON, mage.cards.s.SigardianPaladin.class));
|
cards.add(new SetCardInfo("Sigardian Paladin", 247, Rarity.UNCOMMON, mage.cards.s.SigardianPaladin.class));
|
||||||
cards.add(new SetCardInfo("Sinner's Judgment", 12, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Sinner's Judgment", 348, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Skulking Killer", 130, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Skulking Killer", 130, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Skulking Killer", 296, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Skulking Killer", 296, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Skull Skaab", 248, Rarity.UNCOMMON, mage.cards.s.SkullSkaab.class));
|
cards.add(new SetCardInfo("Skull Skaab", 248, Rarity.UNCOMMON, mage.cards.s.SkullSkaab.class));
|
||||||
|
|
|
||||||
|
|
@ -324,7 +324,6 @@ public final class InnistradDoubleFeature extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Homestead Courage", 24, Rarity.COMMON, mage.cards.h.HomesteadCourage.class));
|
cards.add(new SetCardInfo("Homestead Courage", 24, Rarity.COMMON, mage.cards.h.HomesteadCourage.class));
|
||||||
cards.add(new SetCardInfo("Honeymoon Hearse", 427, Rarity.UNCOMMON, mage.cards.h.HoneymoonHearse.class));
|
cards.add(new SetCardInfo("Honeymoon Hearse", 427, Rarity.UNCOMMON, mage.cards.h.HoneymoonHearse.class));
|
||||||
cards.add(new SetCardInfo("Honored Heirloom", 524, Rarity.COMMON, mage.cards.h.HonoredHeirloom.class));
|
cards.add(new SetCardInfo("Honored Heirloom", 524, Rarity.COMMON, mage.cards.h.HonoredHeirloom.class));
|
||||||
cards.add(new SetCardInfo("Hook-Haunt Drifter", 42, Rarity.COMMON, mage.cards.h.HookHauntDrifter.class));
|
|
||||||
cards.add(new SetCardInfo("Hookhand Mariner", 470, Rarity.COMMON, mage.cards.h.HookhandMariner.class));
|
cards.add(new SetCardInfo("Hookhand Mariner", 470, Rarity.COMMON, mage.cards.h.HookhandMariner.class));
|
||||||
cards.add(new SetCardInfo("Hopeful Initiate", 287, Rarity.RARE, mage.cards.h.HopefulInitiate.class));
|
cards.add(new SetCardInfo("Hopeful Initiate", 287, Rarity.RARE, mage.cards.h.HopefulInitiate.class));
|
||||||
cards.add(new SetCardInfo("Hostile Hostel", 264, Rarity.MYTHIC, mage.cards.h.HostileHostel.class));
|
cards.add(new SetCardInfo("Hostile Hostel", 264, Rarity.MYTHIC, mage.cards.h.HostileHostel.class));
|
||||||
|
|
@ -526,7 +525,6 @@ public final class InnistradDoubleFeature extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Sigardian Paladin", 514, Rarity.UNCOMMON, mage.cards.s.SigardianPaladin.class));
|
cards.add(new SetCardInfo("Sigardian Paladin", 514, Rarity.UNCOMMON, mage.cards.s.SigardianPaladin.class));
|
||||||
cards.add(new SetCardInfo("Sigardian Savior", 34, Rarity.MYTHIC, mage.cards.s.SigardianSavior.class));
|
cards.add(new SetCardInfo("Sigardian Savior", 34, Rarity.MYTHIC, mage.cards.s.SigardianSavior.class));
|
||||||
cards.add(new SetCardInfo("Silver Bolt", 258, Rarity.COMMON, mage.cards.s.SilverBolt.class));
|
cards.add(new SetCardInfo("Silver Bolt", 258, Rarity.COMMON, mage.cards.s.SilverBolt.class));
|
||||||
cards.add(new SetCardInfo("Sinner's Judgment", 279, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class));
|
|
||||||
cards.add(new SetCardInfo("Siphon Insight", 241, Rarity.RARE, mage.cards.s.SiphonInsight.class));
|
cards.add(new SetCardInfo("Siphon Insight", 241, Rarity.RARE, mage.cards.s.SiphonInsight.class));
|
||||||
cards.add(new SetCardInfo("Skaab Wrangler", 75, Rarity.UNCOMMON, mage.cards.s.SkaabWrangler.class));
|
cards.add(new SetCardInfo("Skaab Wrangler", 75, Rarity.UNCOMMON, mage.cards.s.SkaabWrangler.class));
|
||||||
cards.add(new SetCardInfo("Skulking Killer", 397, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class));
|
cards.add(new SetCardInfo("Skulking Killer", 397, Rarity.UNCOMMON, mage.cards.s.SkulkingKiller.class));
|
||||||
|
|
@ -633,7 +631,6 @@ public final class InnistradDoubleFeature extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Voldaren Stinger", 167, Rarity.COMMON, mage.cards.v.VoldarenStinger.class));
|
cards.add(new SetCardInfo("Voldaren Stinger", 167, Rarity.COMMON, mage.cards.v.VoldarenStinger.class));
|
||||||
cards.add(new SetCardInfo("Volt-Charged Berserker", 450, Rarity.UNCOMMON, mage.cards.v.VoltChargedBerserker.class));
|
cards.add(new SetCardInfo("Volt-Charged Berserker", 450, Rarity.UNCOMMON, mage.cards.v.VoltChargedBerserker.class));
|
||||||
cards.add(new SetCardInfo("Voltaic Visionary", 450, Rarity.UNCOMMON, mage.cards.v.VoltaicVisionary.class));
|
cards.add(new SetCardInfo("Voltaic Visionary", 450, Rarity.UNCOMMON, mage.cards.v.VoltaicVisionary.class));
|
||||||
cards.add(new SetCardInfo("Waildrifter", 55, Rarity.COMMON, mage.cards.w.Waildrifter.class));
|
|
||||||
cards.add(new SetCardInfo("Wake to Slaughter", 250, Rarity.RARE, mage.cards.w.WakeToSlaughter.class));
|
cards.add(new SetCardInfo("Wake to Slaughter", 250, Rarity.RARE, mage.cards.w.WakeToSlaughter.class));
|
||||||
cards.add(new SetCardInfo("Wandering Mind", 518, Rarity.UNCOMMON, mage.cards.w.WanderingMind.class));
|
cards.add(new SetCardInfo("Wandering Mind", 518, Rarity.UNCOMMON, mage.cards.w.WanderingMind.class));
|
||||||
cards.add(new SetCardInfo("Wanderlight Spirit", 353, Rarity.COMMON, mage.cards.w.WanderlightSpirit.class));
|
cards.add(new SetCardInfo("Wanderlight Spirit", 353, Rarity.COMMON, mage.cards.w.WanderlightSpirit.class));
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,6 @@ public final class InnistradMidnightHunt extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Heirloom Mirror", 105, Rarity.UNCOMMON, mage.cards.h.HeirloomMirror.class));
|
cards.add(new SetCardInfo("Heirloom Mirror", 105, Rarity.UNCOMMON, mage.cards.h.HeirloomMirror.class));
|
||||||
cards.add(new SetCardInfo("Hobbling Zombie", 106, Rarity.COMMON, mage.cards.h.HobblingZombie.class));
|
cards.add(new SetCardInfo("Hobbling Zombie", 106, Rarity.COMMON, mage.cards.h.HobblingZombie.class));
|
||||||
cards.add(new SetCardInfo("Homestead Courage", 24, Rarity.COMMON, mage.cards.h.HomesteadCourage.class));
|
cards.add(new SetCardInfo("Homestead Courage", 24, Rarity.COMMON, mage.cards.h.HomesteadCourage.class));
|
||||||
cards.add(new SetCardInfo("Hook-Haunt Drifter", 42, Rarity.COMMON, mage.cards.h.HookHauntDrifter.class));
|
|
||||||
cards.add(new SetCardInfo("Hostile Hostel", 264, Rarity.MYTHIC, mage.cards.h.HostileHostel.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Hostile Hostel", 264, Rarity.MYTHIC, mage.cards.h.HostileHostel.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Hostile Hostel", 379, Rarity.MYTHIC, mage.cards.h.HostileHostel.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Hostile Hostel", 379, Rarity.MYTHIC, mage.cards.h.HostileHostel.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Hound Tamer", 187, Rarity.UNCOMMON, mage.cards.h.HoundTamer.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Hound Tamer", 187, Rarity.UNCOMMON, mage.cards.h.HoundTamer.class, NON_FULL_USE_VARIOUS));
|
||||||
|
|
@ -499,7 +498,6 @@ public final class InnistradMidnightHunt extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Vivisection", 83, Rarity.UNCOMMON, mage.cards.v.Vivisection.class));
|
cards.add(new SetCardInfo("Vivisection", 83, Rarity.UNCOMMON, mage.cards.v.Vivisection.class));
|
||||||
cards.add(new SetCardInfo("Voldaren Ambusher", 166, Rarity.UNCOMMON, mage.cards.v.VoldarenAmbusher.class));
|
cards.add(new SetCardInfo("Voldaren Ambusher", 166, Rarity.UNCOMMON, mage.cards.v.VoldarenAmbusher.class));
|
||||||
cards.add(new SetCardInfo("Voldaren Stinger", 167, Rarity.COMMON, mage.cards.v.VoldarenStinger.class));
|
cards.add(new SetCardInfo("Voldaren Stinger", 167, Rarity.COMMON, mage.cards.v.VoldarenStinger.class));
|
||||||
cards.add(new SetCardInfo("Waildrifter", 55, Rarity.COMMON, mage.cards.w.Waildrifter.class));
|
|
||||||
cards.add(new SetCardInfo("Wake to Slaughter", 250, Rarity.RARE, mage.cards.w.WakeToSlaughter.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Wake to Slaughter", 250, Rarity.RARE, mage.cards.w.WakeToSlaughter.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Wake to Slaughter", 376, Rarity.RARE, mage.cards.w.WakeToSlaughter.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Wake to Slaughter", 376, Rarity.RARE, mage.cards.w.WakeToSlaughter.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Willow Geist", 207, Rarity.RARE, mage.cards.w.WillowGeist.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Willow Geist", 207, Rarity.RARE, mage.cards.w.WillowGeist.class, NON_FULL_USE_VARIOUS));
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,6 @@ public class InnistradRemastered extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Aurora of Emrakul", 472, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class, RETRO_ART_USE_VARIOUS));
|
cards.add(new SetCardInfo("Aurora of Emrakul", 472, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class, RETRO_ART_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Avacyn, Angel of Hope", 477, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class, RETRO_ART_USE_VARIOUS));
|
cards.add(new SetCardInfo("Avacyn, Angel of Hope", 477, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class, RETRO_ART_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Avacyn, Angel of Hope", 482, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class, FULL_ART_USE_VARIOUS));
|
cards.add(new SetCardInfo("Avacyn, Angel of Hope", 482, Rarity.MYTHIC, mage.cards.a.AvacynAngelOfHope.class, FULL_ART_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Avacyn, the Purifier", 11, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Avacyn, the Purifier", 449, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, RETRO_ART_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Avacynian Priest", 12, Rarity.COMMON, mage.cards.a.AvacynianPriest.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Avacynian Priest", 12, Rarity.COMMON, mage.cards.a.AvacynianPriest.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Avacynian Priest", 334, Rarity.COMMON, mage.cards.a.AvacynianPriest.class, RETRO_ART_USE_VARIOUS));
|
cards.add(new SetCardInfo("Avacynian Priest", 334, Rarity.COMMON, mage.cards.a.AvacynianPriest.class, RETRO_ART_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Awoken Demon", 107, Rarity.COMMON, mage.cards.a.AwokenDemon.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Awoken Demon", 107, Rarity.COMMON, mage.cards.a.AwokenDemon.class, NON_FULL_USE_VARIOUS));
|
||||||
|
|
@ -417,9 +415,6 @@ public class InnistradRemastered extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Plains", 289, Rarity.LAND, mage.cards.basiclands.Plains.class, RETRO_ART_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 289, Rarity.LAND, mage.cards.basiclands.Plains.class, RETRO_ART_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Rally the Peasants", 347, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class, RETRO_ART_USE_VARIOUS));
|
cards.add(new SetCardInfo("Rally the Peasants", 347, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class, RETRO_ART_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Rally the Peasants", 37, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Rally the Peasants", 37, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Ravager of the Fells", 241, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Ravager of the Fells", 325, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Ravager of the Fells", 470, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class, RETRO_ART_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Reckless Scholar", 81, Rarity.COMMON, mage.cards.r.RecklessScholar.class));
|
cards.add(new SetCardInfo("Reckless Scholar", 81, Rarity.COMMON, mage.cards.r.RecklessScholar.class));
|
||||||
cards.add(new SetCardInfo("Reforge the Soul", 167, Rarity.RARE, mage.cards.r.ReforgeTheSoul.class));
|
cards.add(new SetCardInfo("Reforge the Soul", 167, Rarity.RARE, mage.cards.r.ReforgeTheSoul.class));
|
||||||
cards.add(new SetCardInfo("Restless Bloodseeker", 128, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Restless Bloodseeker", 128, Rarity.UNCOMMON, mage.cards.r.RestlessBloodseeker.class, NON_FULL_USE_VARIOUS));
|
||||||
|
|
@ -521,7 +516,6 @@ public class InnistradRemastered extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Through the Breach", 175, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Through the Breach", 175, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Through the Breach", 404, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, RETRO_ART_USE_VARIOUS));
|
cards.add(new SetCardInfo("Through the Breach", 404, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, RETRO_ART_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Through the Breach", 487, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, FULL_ART_USE_VARIOUS));
|
cards.add(new SetCardInfo("Through the Breach", 487, Rarity.MYTHIC, mage.cards.t.ThroughTheBreach.class, FULL_ART_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Timber Shredder", 203, Rarity.COMMON, mage.cards.t.TimberShredder.class));
|
|
||||||
cards.add(new SetCardInfo("Tireless Tracker", 219, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Tireless Tracker", 219, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Tireless Tracker", 318, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Tireless Tracker", 318, Rarity.RARE, mage.cards.t.TirelessTracker.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Torens, Fist of the Angels", 250, Rarity.RARE, mage.cards.t.TorensFistOfTheAngels.class));
|
cards.add(new SetCardInfo("Torens, Fist of the Angels", 250, Rarity.RARE, mage.cards.t.TorensFistOfTheAngels.class));
|
||||||
|
|
|
||||||
|
|
@ -312,7 +312,6 @@ public final class KamigawaNeonDynasty extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 25, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 25, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 367, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 367, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 439, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Light-Paws, Emperor's Voice", 439, Rarity.RARE, mage.cards.l.LightPawsEmperorsVoice.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Likeness of the Seeker", 172, Rarity.UNCOMMON, mage.cards.l.LikenessOfTheSeeker.class));
|
|
||||||
cards.add(new SetCardInfo("Lion Sash", 26, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Lion Sash", 26, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Lion Sash", 368, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Lion Sash", 368, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Lion Sash", 440, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Lion Sash", 440, Rarity.RARE, mage.cards.l.LionSash.class, NON_FULL_USE_VARIOUS));
|
||||||
|
|
|
||||||
|
|
@ -2458,7 +2458,6 @@ public class MagicOnlinePromos extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Simic Signet", 62391, Rarity.COMMON, mage.cards.s.SimicSignet.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Simic Signet", 62391, Rarity.COMMON, mage.cards.s.SimicSignet.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Sin Collector", 50112, Rarity.UNCOMMON, mage.cards.s.SinCollector.class));
|
cards.add(new SetCardInfo("Sin Collector", 50112, Rarity.UNCOMMON, mage.cards.s.SinCollector.class));
|
||||||
cards.add(new SetCardInfo("Sinkhole", 43566, Rarity.RARE, mage.cards.s.Sinkhole.class));
|
cards.add(new SetCardInfo("Sinkhole", 43566, Rarity.RARE, mage.cards.s.Sinkhole.class));
|
||||||
cards.add(new SetCardInfo("Sinner's Judgment", 95279, Rarity.MYTHIC, mage.cards.s.SinnersJudgment.class));
|
|
||||||
cards.add(new SetCardInfo("Siphon Insight", 94066, Rarity.RARE, mage.cards.s.SiphonInsight.class));
|
cards.add(new SetCardInfo("Siphon Insight", 94066, Rarity.RARE, mage.cards.s.SiphonInsight.class));
|
||||||
cards.add(new SetCardInfo("Sisay, Weatherlight Captain", 91211, Rarity.RARE, mage.cards.s.SisayWeatherlightCaptain.class, RETRO_ART));
|
cards.add(new SetCardInfo("Sisay, Weatherlight Captain", 91211, Rarity.RARE, mage.cards.s.SisayWeatherlightCaptain.class, RETRO_ART));
|
||||||
cards.add(new SetCardInfo("Skarrg Goliath", 47989, Rarity.RARE, mage.cards.s.SkarrgGoliath.class));
|
cards.add(new SetCardInfo("Skarrg Goliath", 47989, Rarity.RARE, mage.cards.s.SkarrgGoliath.class));
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,6 @@ public final class MarchOfTheMachine extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Baral and Kari Zev", 218, Rarity.RARE, mage.cards.b.BaralAndKariZev.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Baral and Kari Zev", 218, Rarity.RARE, mage.cards.b.BaralAndKariZev.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Baral and Kari Zev", 302, Rarity.RARE, mage.cards.b.BaralAndKariZev.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Baral and Kari Zev", 302, Rarity.RARE, mage.cards.b.BaralAndKariZev.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Beamtown Beatstick", 131, Rarity.COMMON, mage.cards.b.BeamtownBeatstick.class));
|
cards.add(new SetCardInfo("Beamtown Beatstick", 131, Rarity.COMMON, mage.cards.b.BeamtownBeatstick.class));
|
||||||
cards.add(new SetCardInfo("Belenon War Anthem", 20, Rarity.UNCOMMON, mage.cards.b.BelenonWarAnthem.class));
|
|
||||||
cards.add(new SetCardInfo("Belligerent Regisaur", 191, Rarity.RARE, mage.cards.b.BelligerentRegisaur.class));
|
cards.add(new SetCardInfo("Belligerent Regisaur", 191, Rarity.RARE, mage.cards.b.BelligerentRegisaur.class));
|
||||||
cards.add(new SetCardInfo("Bladed Battle-Fan", 91, Rarity.COMMON, mage.cards.b.BladedBattleFan.class));
|
cards.add(new SetCardInfo("Bladed Battle-Fan", 91, Rarity.COMMON, mage.cards.b.BladedBattleFan.class));
|
||||||
cards.add(new SetCardInfo("Blighted Burgeoning", 177, Rarity.COMMON, mage.cards.b.BlightedBurgeoning.class));
|
cards.add(new SetCardInfo("Blighted Burgeoning", 177, Rarity.COMMON, mage.cards.b.BlightedBurgeoning.class));
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ public class MarvelLegendsSeriesInserts extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Anti-Venom, Horrifying Healer", 1, Rarity.MYTHIC, mage.cards.a.AntiVenomHorrifyingHealer.class));
|
cards.add(new SetCardInfo("Anti-Venom, Horrifying Healer", 1, Rarity.MYTHIC, mage.cards.a.AntiVenomHorrifyingHealer.class));
|
||||||
cards.add(new SetCardInfo("Huntmaster of the Fells", 3, Rarity.RARE, mage.cards.h.HuntmasterOfTheFells.class));
|
cards.add(new SetCardInfo("Huntmaster of the Fells", 3, Rarity.RARE, mage.cards.h.HuntmasterOfTheFells.class));
|
||||||
cards.add(new SetCardInfo("Iron Spider, Stark Upgrade", 4, Rarity.RARE, mage.cards.i.IronSpiderStarkUpgrade.class));
|
cards.add(new SetCardInfo("Iron Spider, Stark Upgrade", 4, Rarity.RARE, mage.cards.i.IronSpiderStarkUpgrade.class));
|
||||||
cards.add(new SetCardInfo("Ravager of the Fells", 3, Rarity.RARE, mage.cards.r.RavagerOfTheFells.class));
|
|
||||||
cards.add(new SetCardInfo("Spectacular Spider-Man", 2, Rarity.RARE, mage.cards.s.SpectacularSpiderMan.class));
|
cards.add(new SetCardInfo("Spectacular Spider-Man", 2, Rarity.RARE, mage.cards.s.SpectacularSpiderMan.class));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,11 @@ import mage.cards.ExpansionSet;
|
||||||
import mage.constants.Rarity;
|
import mage.constants.Rarity;
|
||||||
import mage.constants.SetType;
|
import mage.constants.SetType;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author TheElk801
|
* @author TheElk801
|
||||||
*/
|
*/
|
||||||
public final class MarvelsSpiderMan extends ExpansionSet {
|
public final class MarvelsSpiderMan extends ExpansionSet {
|
||||||
|
|
||||||
private static final List<String> unfinished = Arrays.asList("Eddie Brock", "Gwen Stacy", "Miles Morales", "Norman Osborn", "Peter Parker");
|
|
||||||
private static final MarvelsSpiderMan instance = new MarvelsSpiderMan();
|
private static final MarvelsSpiderMan instance = new MarvelsSpiderMan();
|
||||||
|
|
||||||
public static MarvelsSpiderMan getInstance() {
|
public static MarvelsSpiderMan getInstance() {
|
||||||
|
|
@ -310,7 +306,5 @@ public final class MarvelsSpiderMan extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("With Great Power...", 24, Rarity.RARE, mage.cards.w.WithGreatPower.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("With Great Power...", 24, Rarity.RARE, mage.cards.w.WithGreatPower.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("With Great Power...", 248, Rarity.RARE, mage.cards.w.WithGreatPower.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("With Great Power...", 248, Rarity.RARE, mage.cards.w.WithGreatPower.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Wraith, Vicious Vigilante", 160, Rarity.UNCOMMON, mage.cards.w.WraithViciousVigilante.class));
|
cards.add(new SetCardInfo("Wraith, Vicious Vigilante", 160, Rarity.UNCOMMON, mage.cards.w.WraithViciousVigilante.class));
|
||||||
|
|
||||||
cards.removeIf(setCardInfo -> unfinished.contains(setCardInfo.getName()));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -482,9 +482,6 @@ public final class ModernHorizons3 extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 242, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 242, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 443, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 443, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 469, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Tamiyo, Inquisitive Student", 469, Rarity.MYTHIC, mage.cards.t.TamiyoInquisitiveStudent.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Tamiyo, Seasoned Scholar", 242, Rarity.MYTHIC, mage.cards.t.TamiyoSeasonedScholar.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Tamiyo, Seasoned Scholar", 443, Rarity.MYTHIC, mage.cards.t.TamiyoSeasonedScholar.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Tamiyo, Seasoned Scholar", 469, Rarity.MYTHIC, mage.cards.t.TamiyoSeasonedScholar.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Temperamental Oozewagg", 172, Rarity.COMMON, mage.cards.t.TemperamentalOozewagg.class));
|
cards.add(new SetCardInfo("Temperamental Oozewagg", 172, Rarity.COMMON, mage.cards.t.TemperamentalOozewagg.class));
|
||||||
cards.add(new SetCardInfo("Tempest Harvester", 73, Rarity.COMMON, mage.cards.t.TempestHarvester.class));
|
cards.add(new SetCardInfo("Tempest Harvester", 73, Rarity.COMMON, mage.cards.t.TempestHarvester.class));
|
||||||
cards.add(new SetCardInfo("Territory Culler", 173, Rarity.UNCOMMON, mage.cards.t.TerritoryCuller.class));
|
cards.add(new SetCardInfo("Territory Culler", 173, Rarity.UNCOMMON, mage.cards.t.TerritoryCuller.class));
|
||||||
|
|
|
||||||
|
|
@ -507,7 +507,6 @@ public class SecretLairDrop extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Kozilek, the Great Distortion", 493, Rarity.MYTHIC, mage.cards.k.KozilekTheGreatDistortion.class));
|
cards.add(new SetCardInfo("Kozilek, the Great Distortion", 493, Rarity.MYTHIC, mage.cards.k.KozilekTheGreatDistortion.class));
|
||||||
cards.add(new SetCardInfo("Primeval Titan", 494, Rarity.MYTHIC, mage.cards.p.PrimevalTitan.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Primeval Titan", 494, Rarity.MYTHIC, mage.cards.p.PrimevalTitan.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Huntmaster of the Fells", 495, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Huntmaster of the Fells", 495, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Ravager of the Fells", 495, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Platinum Angel", 496, Rarity.RARE, mage.cards.p.PlatinumAngel.class));
|
cards.add(new SetCardInfo("Platinum Angel", 496, Rarity.RARE, mage.cards.p.PlatinumAngel.class));
|
||||||
cards.add(new SetCardInfo("Brimaz, King of Oreskos", 497, Rarity.MYTHIC, mage.cards.b.BrimazKingOfOreskos.class));
|
cards.add(new SetCardInfo("Brimaz, King of Oreskos", 497, Rarity.MYTHIC, mage.cards.b.BrimazKingOfOreskos.class));
|
||||||
cards.add(new SetCardInfo("Arcanis the Omnipotent", 498, Rarity.RARE, mage.cards.a.ArcanisTheOmnipotent.class));
|
cards.add(new SetCardInfo("Arcanis the Omnipotent", 498, Rarity.RARE, mage.cards.a.ArcanisTheOmnipotent.class));
|
||||||
|
|
@ -706,7 +705,6 @@ public class SecretLairDrop extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Dakkon Blackblade", 698, Rarity.RARE, mage.cards.d.DakkonBlackblade.class));
|
cards.add(new SetCardInfo("Dakkon Blackblade", 698, Rarity.RARE, mage.cards.d.DakkonBlackblade.class));
|
||||||
cards.add(new SetCardInfo("Olivia, Mobilized for War", 699, Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Olivia, Mobilized for War", 699, Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Huntmaster of the Fells", 700, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Huntmaster of the Fells", 700, Rarity.MYTHIC, mage.cards.h.HuntmasterOfTheFells.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Ravager of the Fells", 700, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Elspeth, Knight-Errant", 701, Rarity.MYTHIC, mage.cards.e.ElspethKnightErrant.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Elspeth, Knight-Errant", 701, Rarity.MYTHIC, mage.cards.e.ElspethKnightErrant.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Wastes", 704, Rarity.RARE, mage.cards.w.Wastes.class, FULL_ART_BFZ_VARIOUS));
|
cards.add(new SetCardInfo("Wastes", 704, Rarity.RARE, mage.cards.w.Wastes.class, FULL_ART_BFZ_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Wastes", 705, Rarity.RARE, mage.cards.w.Wastes.class, FULL_ART_BFZ_VARIOUS));
|
cards.add(new SetCardInfo("Wastes", 705, Rarity.RARE, mage.cards.w.Wastes.class, FULL_ART_BFZ_VARIOUS));
|
||||||
|
|
@ -1063,7 +1061,6 @@ public class SecretLairDrop extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Eldrazi Temple", 1154, Rarity.RARE, mage.cards.e.EldraziTemple.class));
|
cards.add(new SetCardInfo("Eldrazi Temple", 1154, Rarity.RARE, mage.cards.e.EldraziTemple.class));
|
||||||
cards.add(new SetCardInfo("Esika, God of the Tree", 1155, Rarity.MYTHIC, mage.cards.e.EsikaGodOfTheTree.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Esika, God of the Tree", 1155, Rarity.MYTHIC, mage.cards.e.EsikaGodOfTheTree.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Archangel Avacyn", 1156, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Archangel Avacyn", 1156, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Avacyn, the Purifier", 1156, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Bloodline Keeper", 1157, Rarity.RARE, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Bloodline Keeper", 1157, Rarity.RARE, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Lord of Lineage", 1157, Rarity.RARE, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Lord of Lineage", 1157, Rarity.RARE, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Nicol Bolas, the Ravager", 1158, Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Nicol Bolas, the Ravager", 1158, Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class, NON_FULL_USE_VARIOUS));
|
||||||
|
|
@ -1120,7 +1117,6 @@ public class SecretLairDrop extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Inkmoth Nexus", 1207, Rarity.RARE, mage.cards.i.InkmothNexus.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Inkmoth Nexus", 1207, Rarity.RARE, mage.cards.i.InkmothNexus.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Esika, God of the Tree", 1208, Rarity.MYTHIC, mage.cards.e.EsikaGodOfTheTree.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Esika, God of the Tree", 1208, Rarity.MYTHIC, mage.cards.e.EsikaGodOfTheTree.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Archangel Avacyn", 1209, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Archangel Avacyn", 1209, Rarity.MYTHIC, mage.cards.a.ArchangelAvacyn.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Avacyn, the Purifier", 1209, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Bloodline Keeper", 1210, Rarity.RARE, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Bloodline Keeper", 1210, Rarity.RARE, mage.cards.b.BloodlineKeeper.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Lord of Lineage", 1210, Rarity.RARE, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Lord of Lineage", 1210, Rarity.RARE, mage.cards.l.LordOfLineage.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Nicol Bolas, the Ravager", 1211, Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Nicol Bolas, the Ravager", 1211, Rarity.MYTHIC, mage.cards.n.NicolBolasTheRavager.class, NON_FULL_USE_VARIOUS));
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,6 @@ public class ShadowsOfThePast extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Mystic Retrieval", 20, Rarity.UNCOMMON, mage.cards.m.MysticRetrieval.class));
|
cards.add(new SetCardInfo("Mystic Retrieval", 20, Rarity.UNCOMMON, mage.cards.m.MysticRetrieval.class));
|
||||||
cards.add(new SetCardInfo("Past in Flames", 43, Rarity.MYTHIC, mage.cards.p.PastInFlames.class));
|
cards.add(new SetCardInfo("Past in Flames", 43, Rarity.MYTHIC, mage.cards.p.PastInFlames.class));
|
||||||
cards.add(new SetCardInfo("Rally the Peasants", 10, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class));
|
cards.add(new SetCardInfo("Rally the Peasants", 10, Rarity.UNCOMMON, mage.cards.r.RallyThePeasants.class));
|
||||||
cards.add(new SetCardInfo("Ravager of the Fells", 64, Rarity.MYTHIC, mage.cards.r.RavagerOfTheFells.class));
|
|
||||||
cards.add(new SetCardInfo("Requiem Angel", 11, Rarity.RARE, mage.cards.r.RequiemAngel.class));
|
cards.add(new SetCardInfo("Requiem Angel", 11, Rarity.RARE, mage.cards.r.RequiemAngel.class));
|
||||||
cards.add(new SetCardInfo("Seance", 12, Rarity.UNCOMMON, mage.cards.s.Seance.class));
|
cards.add(new SetCardInfo("Seance", 12, Rarity.UNCOMMON, mage.cards.s.Seance.class));
|
||||||
cards.add(new SetCardInfo("Selhoff Occultist", 21, Rarity.COMMON, mage.cards.s.SelhoffOccultist.class));
|
cards.add(new SetCardInfo("Selhoff Occultist", 21, Rarity.COMMON, mage.cards.s.SelhoffOccultist.class));
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Asylum Visitor", 99, Rarity.RARE, mage.cards.a.AsylumVisitor.class));
|
cards.add(new SetCardInfo("Asylum Visitor", 99, Rarity.RARE, mage.cards.a.AsylumVisitor.class));
|
||||||
cards.add(new SetCardInfo("Autumnal Gloom", 194, Rarity.UNCOMMON, mage.cards.a.AutumnalGloom.class));
|
cards.add(new SetCardInfo("Autumnal Gloom", 194, Rarity.UNCOMMON, mage.cards.a.AutumnalGloom.class));
|
||||||
cards.add(new SetCardInfo("Avacyn's Judgment", 145, Rarity.RARE, mage.cards.a.AvacynsJudgment.class));
|
cards.add(new SetCardInfo("Avacyn's Judgment", 145, Rarity.RARE, mage.cards.a.AvacynsJudgment.class));
|
||||||
cards.add(new SetCardInfo("Avacyn, the Purifier", 5, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class));
|
|
||||||
cards.add(new SetCardInfo("Avacynian Missionaries", 6, Rarity.UNCOMMON, mage.cards.a.AvacynianMissionaries.class));
|
cards.add(new SetCardInfo("Avacynian Missionaries", 6, Rarity.UNCOMMON, mage.cards.a.AvacynianMissionaries.class));
|
||||||
cards.add(new SetCardInfo("Awoken Horror", 92, Rarity.RARE, mage.cards.a.AwokenHorror.class));
|
cards.add(new SetCardInfo("Awoken Horror", 92, Rarity.RARE, mage.cards.a.AwokenHorror.class));
|
||||||
cards.add(new SetCardInfo("Bearer of Overwhelming Truths", 54, Rarity.UNCOMMON, mage.cards.b.BearerOfOverwhelmingTruths.class));
|
cards.add(new SetCardInfo("Bearer of Overwhelming Truths", 54, Rarity.UNCOMMON, mage.cards.b.BearerOfOverwhelmingTruths.class));
|
||||||
|
|
@ -195,7 +194,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Kessig Forgemaster", 169, Rarity.UNCOMMON, mage.cards.k.KessigForgemaster.class));
|
cards.add(new SetCardInfo("Kessig Forgemaster", 169, Rarity.UNCOMMON, mage.cards.k.KessigForgemaster.class));
|
||||||
cards.add(new SetCardInfo("Kindly Stranger", 119, Rarity.UNCOMMON, mage.cards.k.KindlyStranger.class));
|
cards.add(new SetCardInfo("Kindly Stranger", 119, Rarity.UNCOMMON, mage.cards.k.KindlyStranger.class));
|
||||||
cards.add(new SetCardInfo("Krallenhorde Howler", 203, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class));
|
cards.add(new SetCardInfo("Krallenhorde Howler", 203, Rarity.UNCOMMON, mage.cards.k.KrallenhordeHowler.class));
|
||||||
cards.add(new SetCardInfo("Lambholt Butcher", 215, Rarity.UNCOMMON, mage.cards.l.LambholtButcher.class));
|
|
||||||
cards.add(new SetCardInfo("Lambholt Pacifist", 215, Rarity.UNCOMMON, mage.cards.l.LambholtPacifist.class));
|
cards.add(new SetCardInfo("Lambholt Pacifist", 215, Rarity.UNCOMMON, mage.cards.l.LambholtPacifist.class));
|
||||||
cards.add(new SetCardInfo("Lamplighter of Selhoff", 72, Rarity.COMMON, mage.cards.l.LamplighterOfSelhoff.class));
|
cards.add(new SetCardInfo("Lamplighter of Selhoff", 72, Rarity.COMMON, mage.cards.l.LamplighterOfSelhoff.class));
|
||||||
cards.add(new SetCardInfo("Lightning Axe", 170, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class));
|
cards.add(new SetCardInfo("Lightning Axe", 170, Rarity.UNCOMMON, mage.cards.l.LightningAxe.class));
|
||||||
|
|
@ -245,7 +243,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Pale Rider of Trostad", 128, Rarity.UNCOMMON, mage.cards.p.PaleRiderOfTrostad.class));
|
cards.add(new SetCardInfo("Pale Rider of Trostad", 128, Rarity.UNCOMMON, mage.cards.p.PaleRiderOfTrostad.class));
|
||||||
cards.add(new SetCardInfo("Paranoid Parish-Blade", 33, Rarity.UNCOMMON, mage.cards.p.ParanoidParishBlade.class));
|
cards.add(new SetCardInfo("Paranoid Parish-Blade", 33, Rarity.UNCOMMON, mage.cards.p.ParanoidParishBlade.class));
|
||||||
cards.add(new SetCardInfo("Perfected Form", 49, Rarity.UNCOMMON, mage.cards.p.PerfectedForm.class));
|
cards.add(new SetCardInfo("Perfected Form", 49, Rarity.UNCOMMON, mage.cards.p.PerfectedForm.class));
|
||||||
cards.add(new SetCardInfo("Persistent Nightmare", 88, Rarity.MYTHIC, mage.cards.p.PersistentNightmare.class));
|
|
||||||
cards.add(new SetCardInfo("Pick the Brain", 129, Rarity.UNCOMMON, mage.cards.p.PickTheBrain.class));
|
cards.add(new SetCardInfo("Pick the Brain", 129, Rarity.UNCOMMON, mage.cards.p.PickTheBrain.class));
|
||||||
cards.add(new SetCardInfo("Pieces of the Puzzle", 78, Rarity.COMMON, mage.cards.p.PiecesOfThePuzzle.class));
|
cards.add(new SetCardInfo("Pieces of the Puzzle", 78, Rarity.COMMON, mage.cards.p.PiecesOfThePuzzle.class));
|
||||||
cards.add(new SetCardInfo("Pious Evangel", 34, Rarity.UNCOMMON, mage.cards.p.PiousEvangel.class));
|
cards.add(new SetCardInfo("Pious Evangel", 34, Rarity.UNCOMMON, mage.cards.p.PiousEvangel.class));
|
||||||
|
|
@ -331,7 +328,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Thraben Gargoyle", 266, Rarity.UNCOMMON, mage.cards.t.ThrabenGargoyle.class));
|
cards.add(new SetCardInfo("Thraben Gargoyle", 266, Rarity.UNCOMMON, mage.cards.t.ThrabenGargoyle.class));
|
||||||
cards.add(new SetCardInfo("Thraben Inspector", 44, Rarity.COMMON, mage.cards.t.ThrabenInspector.class));
|
cards.add(new SetCardInfo("Thraben Inspector", 44, Rarity.COMMON, mage.cards.t.ThrabenInspector.class));
|
||||||
cards.add(new SetCardInfo("Throttle", 138, Rarity.COMMON, mage.cards.t.Throttle.class));
|
cards.add(new SetCardInfo("Throttle", 138, Rarity.COMMON, mage.cards.t.Throttle.class));
|
||||||
cards.add(new SetCardInfo("Timber Shredder", 210, Rarity.COMMON, mage.cards.t.TimberShredder.class));
|
|
||||||
cards.add(new SetCardInfo("Tireless Tracker", 233, Rarity.RARE, mage.cards.t.TirelessTracker.class));
|
cards.add(new SetCardInfo("Tireless Tracker", 233, Rarity.RARE, mage.cards.t.TirelessTracker.class));
|
||||||
cards.add(new SetCardInfo("To the Slaughter", 139, Rarity.RARE, mage.cards.t.ToTheSlaughter.class));
|
cards.add(new SetCardInfo("To the Slaughter", 139, Rarity.RARE, mage.cards.t.ToTheSlaughter.class));
|
||||||
cards.add(new SetCardInfo("Tooth Collector", 140, Rarity.UNCOMMON, mage.cards.t.ToothCollector.class));
|
cards.add(new SetCardInfo("Tooth Collector", 140, Rarity.UNCOMMON, mage.cards.t.ToothCollector.class));
|
||||||
|
|
@ -347,7 +343,6 @@ public final class ShadowsOverInnistrad extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Ulvenwald Hydra", 235, Rarity.MYTHIC, mage.cards.u.UlvenwaldHydra.class));
|
cards.add(new SetCardInfo("Ulvenwald Hydra", 235, Rarity.MYTHIC, mage.cards.u.UlvenwaldHydra.class));
|
||||||
cards.add(new SetCardInfo("Ulvenwald Mysteries", 236, Rarity.UNCOMMON, mage.cards.u.UlvenwaldMysteries.class));
|
cards.add(new SetCardInfo("Ulvenwald Mysteries", 236, Rarity.UNCOMMON, mage.cards.u.UlvenwaldMysteries.class));
|
||||||
cards.add(new SetCardInfo("Uncaged Fury", 188, Rarity.COMMON, mage.cards.u.UncagedFury.class));
|
cards.add(new SetCardInfo("Uncaged Fury", 188, Rarity.COMMON, mage.cards.u.UncagedFury.class));
|
||||||
cards.add(new SetCardInfo("Unimpeded Trespasser", 94, Rarity.UNCOMMON, mage.cards.u.UnimpededTrespasser.class));
|
|
||||||
cards.add(new SetCardInfo("Uninvited Geist", 94, Rarity.UNCOMMON, mage.cards.u.UninvitedGeist.class));
|
cards.add(new SetCardInfo("Uninvited Geist", 94, Rarity.UNCOMMON, mage.cards.u.UninvitedGeist.class));
|
||||||
cards.add(new SetCardInfo("Unruly Mob", 47, Rarity.COMMON, mage.cards.u.UnrulyMob.class));
|
cards.add(new SetCardInfo("Unruly Mob", 47, Rarity.COMMON, mage.cards.u.UnrulyMob.class));
|
||||||
cards.add(new SetCardInfo("Vampire Noble", 143, Rarity.COMMON, mage.cards.v.VampireNoble.class));
|
cards.add(new SetCardInfo("Vampire Noble", 143, Rarity.COMMON, mage.cards.v.VampireNoble.class));
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ public class ShadowsOverInnistradPromos extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", "243s", Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class));
|
cards.add(new SetCardInfo("Arlinn, Embraced by the Moon", "243s", Rarity.MYTHIC, mage.cards.a.ArlinnEmbracedByTheMoon.class));
|
||||||
cards.add(new SetCardInfo("Asylum Visitor", "99s", Rarity.RARE, mage.cards.a.AsylumVisitor.class));
|
cards.add(new SetCardInfo("Asylum Visitor", "99s", Rarity.RARE, mage.cards.a.AsylumVisitor.class));
|
||||||
cards.add(new SetCardInfo("Avacyn's Judgment", "145s", Rarity.RARE, mage.cards.a.AvacynsJudgment.class));
|
cards.add(new SetCardInfo("Avacyn's Judgment", "145s", Rarity.RARE, mage.cards.a.AvacynsJudgment.class));
|
||||||
cards.add(new SetCardInfo("Avacyn, the Purifier", "5s", Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class));
|
|
||||||
cards.add(new SetCardInfo("Awoken Horror", "92s", Rarity.RARE, mage.cards.a.AwokenHorror.class));
|
cards.add(new SetCardInfo("Awoken Horror", "92s", Rarity.RARE, mage.cards.a.AwokenHorror.class));
|
||||||
cards.add(new SetCardInfo("Behold the Beyond", "101s", Rarity.MYTHIC, mage.cards.b.BeholdTheBeyond.class));
|
cards.add(new SetCardInfo("Behold the Beyond", "101s", Rarity.MYTHIC, mage.cards.b.BeholdTheBeyond.class));
|
||||||
cards.add(new SetCardInfo("Brain in a Jar", "252s", Rarity.RARE, mage.cards.b.BrainInAJar.class));
|
cards.add(new SetCardInfo("Brain in a Jar", "252s", Rarity.RARE, mage.cards.b.BrainInAJar.class));
|
||||||
|
|
@ -86,7 +85,6 @@ public class ShadowsOverInnistradPromos extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Odric, Lunarch Marshal", "31s", Rarity.RARE, mage.cards.o.OdricLunarchMarshal.class));
|
cards.add(new SetCardInfo("Odric, Lunarch Marshal", "31s", Rarity.RARE, mage.cards.o.OdricLunarchMarshal.class));
|
||||||
cards.add(new SetCardInfo("Olivia, Mobilized for War", "248s", Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class));
|
cards.add(new SetCardInfo("Olivia, Mobilized for War", "248s", Rarity.MYTHIC, mage.cards.o.OliviaMobilizedForWar.class));
|
||||||
cards.add(new SetCardInfo("Ormendahl, Profane Prince", "281s", Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class));
|
cards.add(new SetCardInfo("Ormendahl, Profane Prince", "281s", Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class));
|
||||||
cards.add(new SetCardInfo("Persistent Nightmare", "88s", Rarity.MYTHIC, mage.cards.p.PersistentNightmare.class));
|
|
||||||
cards.add(new SetCardInfo("Port Town", "278s", Rarity.RARE, mage.cards.p.PortTown.class));
|
cards.add(new SetCardInfo("Port Town", "278s", Rarity.RARE, mage.cards.p.PortTown.class));
|
||||||
cards.add(new SetCardInfo("Prized Amalgam", "249s", Rarity.RARE, mage.cards.p.PrizedAmalgam.class));
|
cards.add(new SetCardInfo("Prized Amalgam", "249s", Rarity.RARE, mage.cards.p.PrizedAmalgam.class));
|
||||||
cards.add(new SetCardInfo("Rattlechains", "81s", Rarity.RARE, mage.cards.r.Rattlechains.class));
|
cards.add(new SetCardInfo("Rattlechains", "81s", Rarity.RARE, mage.cards.r.Rattlechains.class));
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Assembled Alphas", 141, Rarity.RARE, mage.cards.a.AssembledAlphas.class));
|
cards.add(new SetCardInfo("Assembled Alphas", 141, Rarity.RARE, mage.cards.a.AssembledAlphas.class));
|
||||||
cards.add(new SetCardInfo("Aurora of Emrakul", 248, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class));
|
cards.add(new SetCardInfo("Aurora of Emrakul", 248, Rarity.UNCOMMON, mage.cards.a.AuroraOfEmrakul.class));
|
||||||
cards.add(new SetCardInfo("Avacyn's Judgment", 142, Rarity.RARE, mage.cards.a.AvacynsJudgment.class));
|
cards.add(new SetCardInfo("Avacyn's Judgment", 142, Rarity.RARE, mage.cards.a.AvacynsJudgment.class));
|
||||||
cards.add(new SetCardInfo("Avacyn, the Purifier", 13, Rarity.MYTHIC, mage.cards.a.AvacynThePurifier.class));
|
|
||||||
cards.add(new SetCardInfo("Awoken Horror", 95, Rarity.RARE, mage.cards.a.AwokenHorror.class));
|
cards.add(new SetCardInfo("Awoken Horror", 95, Rarity.RARE, mage.cards.a.AwokenHorror.class));
|
||||||
cards.add(new SetCardInfo("Bearer of Overwhelming Truths", 59, Rarity.UNCOMMON, mage.cards.b.BearerOfOverwhelmingTruths.class));
|
cards.add(new SetCardInfo("Bearer of Overwhelming Truths", 59, Rarity.UNCOMMON, mage.cards.b.BearerOfOverwhelmingTruths.class));
|
||||||
cards.add(new SetCardInfo("Bedlam Reveler", 143, Rarity.RARE, mage.cards.b.BedlamReveler.class));
|
cards.add(new SetCardInfo("Bedlam Reveler", 143, Rarity.RARE, mage.cards.b.BedlamReveler.class));
|
||||||
|
|
@ -244,7 +243,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Ormendahl, Profane Prince", 275, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class));
|
cards.add(new SetCardInfo("Ormendahl, Profane Prince", 275, Rarity.RARE, mage.cards.o.OrmendahlProfanePrince.class));
|
||||||
cards.add(new SetCardInfo("Pack Guardian", 208, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class));
|
cards.add(new SetCardInfo("Pack Guardian", 208, Rarity.UNCOMMON, mage.cards.p.PackGuardian.class));
|
||||||
cards.add(new SetCardInfo("Permeating Mass", 209, Rarity.RARE, mage.cards.p.PermeatingMass.class));
|
cards.add(new SetCardInfo("Permeating Mass", 209, Rarity.RARE, mage.cards.p.PermeatingMass.class));
|
||||||
cards.add(new SetCardInfo("Persistent Nightmare", 90, Rarity.MYTHIC, mage.cards.p.PersistentNightmare.class));
|
|
||||||
cards.add(new SetCardInfo("Pick the Brain", 129, Rarity.UNCOMMON, mage.cards.p.PickTheBrain.class));
|
cards.add(new SetCardInfo("Pick the Brain", 129, Rarity.UNCOMMON, mage.cards.p.PickTheBrain.class));
|
||||||
cards.add(new SetCardInfo("Pieces of the Puzzle", 85, Rarity.UNCOMMON, mage.cards.p.PiecesOfThePuzzle.class));
|
cards.add(new SetCardInfo("Pieces of the Puzzle", 85, Rarity.UNCOMMON, mage.cards.p.PiecesOfThePuzzle.class));
|
||||||
cards.add(new SetCardInfo("Plains", 277, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Plains", 277, Rarity.LAND, mage.cards.basiclands.Plains.class, NON_FULL_USE_VARIOUS));
|
||||||
|
|
@ -313,7 +311,6 @@ public class ShadowsOverInnistradRemastered extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Thornhide Wolves", 218, Rarity.COMMON, mage.cards.t.ThornhideWolves.class));
|
cards.add(new SetCardInfo("Thornhide Wolves", 218, Rarity.COMMON, mage.cards.t.ThornhideWolves.class));
|
||||||
cards.add(new SetCardInfo("Thraben Foulbloods", 135, Rarity.COMMON, mage.cards.t.ThrabenFoulbloods.class));
|
cards.add(new SetCardInfo("Thraben Foulbloods", 135, Rarity.COMMON, mage.cards.t.ThrabenFoulbloods.class));
|
||||||
cards.add(new SetCardInfo("Thraben Inspector", 51, Rarity.COMMON, mage.cards.t.ThrabenInspector.class));
|
cards.add(new SetCardInfo("Thraben Inspector", 51, Rarity.COMMON, mage.cards.t.ThrabenInspector.class));
|
||||||
cards.add(new SetCardInfo("Timber Shredder", 201, Rarity.COMMON, mage.cards.t.TimberShredder.class));
|
|
||||||
cards.add(new SetCardInfo("Tireless Tracker", 219, Rarity.RARE, mage.cards.t.TirelessTracker.class));
|
cards.add(new SetCardInfo("Tireless Tracker", 219, Rarity.RARE, mage.cards.t.TirelessTracker.class));
|
||||||
cards.add(new SetCardInfo("Topplegeist", 52, Rarity.UNCOMMON, mage.cards.t.Topplegeist.class));
|
cards.add(new SetCardInfo("Topplegeist", 52, Rarity.UNCOMMON, mage.cards.t.Topplegeist.class));
|
||||||
cards.add(new SetCardInfo("Tormenting Voice", 181, Rarity.COMMON, mage.cards.t.TormentingVoice.class));
|
cards.add(new SetCardInfo("Tormenting Voice", 181, Rarity.COMMON, mage.cards.t.TormentingVoice.class));
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,8 @@
|
||||||
package mage.sets;
|
package mage.sets;
|
||||||
|
|
||||||
import mage.cards.Card;
|
|
||||||
import mage.cards.ExpansionSet;
|
import mage.cards.ExpansionSet;
|
||||||
import mage.cards.repository.CardInfo;
|
|
||||||
import mage.constants.Rarity;
|
import mage.constants.Rarity;
|
||||||
import mage.constants.SetType;
|
import mage.constants.SetType;
|
||||||
import mage.util.RandomUtil;
|
|
||||||
import mage.collation.BoosterCollator;
|
import mage.collation.BoosterCollator;
|
||||||
import mage.collation.BoosterStructure;
|
import mage.collation.BoosterStructure;
|
||||||
import mage.collation.CardRun;
|
import mage.collation.CardRun;
|
||||||
|
|
@ -77,7 +74,6 @@ public final class TheLostCavernsOfIxalan extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Belligerent Yearling", 133, Rarity.UNCOMMON, mage.cards.b.BelligerentYearling.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Belligerent Yearling", 133, Rarity.UNCOMMON, mage.cards.b.BelligerentYearling.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Belligerent Yearling", 320, Rarity.UNCOMMON, mage.cards.b.BelligerentYearling.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Belligerent Yearling", 320, Rarity.UNCOMMON, mage.cards.b.BelligerentYearling.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Bitter Triumph", 91, Rarity.UNCOMMON, mage.cards.b.BitterTriumph.class));
|
cards.add(new SetCardInfo("Bitter Triumph", 91, Rarity.UNCOMMON, mage.cards.b.BitterTriumph.class));
|
||||||
cards.add(new SetCardInfo("Bladewheel Chariot", 36, Rarity.UNCOMMON, mage.cards.b.BladewheelChariot.class));
|
|
||||||
cards.add(new SetCardInfo("Bloodletter of Aclazotz", 336, Rarity.MYTHIC, mage.cards.b.BloodletterOfAclazotz.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Bloodletter of Aclazotz", 336, Rarity.MYTHIC, mage.cards.b.BloodletterOfAclazotz.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Bloodletter of Aclazotz", 92, Rarity.MYTHIC, mage.cards.b.BloodletterOfAclazotz.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Bloodletter of Aclazotz", 92, Rarity.MYTHIC, mage.cards.b.BloodletterOfAclazotz.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Bloodthorn Flail", 93, Rarity.UNCOMMON, mage.cards.b.BloodthornFlail.class));
|
cards.add(new SetCardInfo("Bloodthorn Flail", 93, Rarity.UNCOMMON, mage.cards.b.BloodthornFlail.class));
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,7 @@ public final class Transformers extends ExpansionSet {
|
||||||
cards.add(new SetCardInfo("Jetfire, Ingenious Scientist", 3, Rarity.MYTHIC, mage.cards.j.JetfireIngeniousScientist.class));
|
cards.add(new SetCardInfo("Jetfire, Ingenious Scientist", 3, Rarity.MYTHIC, mage.cards.j.JetfireIngeniousScientist.class));
|
||||||
cards.add(new SetCardInfo("Megatron, Destructive Force", 12, Rarity.MYTHIC, mage.cards.m.MegatronDestructiveForce.class));
|
cards.add(new SetCardInfo("Megatron, Destructive Force", 12, Rarity.MYTHIC, mage.cards.m.MegatronDestructiveForce.class));
|
||||||
cards.add(new SetCardInfo("Megatron, Tyrant", 12, Rarity.MYTHIC, mage.cards.m.MegatronTyrant.class));
|
cards.add(new SetCardInfo("Megatron, Tyrant", 12, Rarity.MYTHIC, mage.cards.m.MegatronTyrant.class));
|
||||||
cards.add(new SetCardInfo("Optimus Prime, Autobot Leader", 13, Rarity.MYTHIC, mage.cards.o.OptimusPrimeAutobotLeader.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Optimus Prime, Hero", 13, Rarity.MYTHIC, mage.cards.o.OptimusPrimeHero.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Optimus Prime, Hero", 13, Rarity.MYTHIC, mage.cards.o.OptimusPrimeHero.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Optimus Prime, Autobot Leader", 27, Rarity.MYTHIC, mage.cards.o.OptimusPrimeAutobotLeader.class, NON_FULL_USE_VARIOUS));
|
|
||||||
cards.add(new SetCardInfo("Optimus Prime, Hero", 27, Rarity.MYTHIC, mage.cards.o.OptimusPrimeHero.class, NON_FULL_USE_VARIOUS));
|
cards.add(new SetCardInfo("Optimus Prime, Hero", 27, Rarity.MYTHIC, mage.cards.o.OptimusPrimeHero.class, NON_FULL_USE_VARIOUS));
|
||||||
cards.add(new SetCardInfo("Ratchet, Field Medic", 2, Rarity.MYTHIC, mage.cards.r.RatchetFieldMedic.class));
|
cards.add(new SetCardInfo("Ratchet, Field Medic", 2, Rarity.MYTHIC, mage.cards.r.RatchetFieldMedic.class));
|
||||||
cards.add(new SetCardInfo("Ratchet, Rescue Racer", 2, Rarity.MYTHIC, mage.cards.r.RatchetRescueRacer.class));
|
cards.add(new SetCardInfo("Ratchet, Rescue Racer", 2, Rarity.MYTHIC, mage.cards.r.RatchetRescueRacer.class));
|
||||||
|
|
|
||||||
|
|
@ -200,23 +200,8 @@ public class IncubateTest extends CardTestPlayerBase {
|
||||||
setChoice(playerA, true); // use copy
|
setChoice(playerA, true); // use copy
|
||||||
setChoice(playerA, "Phyrexian Token");
|
setChoice(playerA, "Phyrexian Token");
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
checkPermanentCount("after copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 2);
|
checkPermanentCount("after copy", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 1);
|
||||||
|
// copy dies to state based actions
|
||||||
// kill original token
|
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target destroy");
|
|
||||||
addTarget(playerA, "Phyrexian Token[no copy]");
|
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
|
||||||
checkPermanentCount("after kill", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 1);
|
|
||||||
showBattlefield("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA);
|
|
||||||
|
|
||||||
// try to transform back side (nothing happen)
|
|
||||||
// 701.28c
|
|
||||||
// If a spell or ability instructs a player to transform a permanent that isn’t represented by a
|
|
||||||
// transforming token or a transforming double-faced card, nothing happens.
|
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target transform", "Phyrexian Token");
|
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
|
||||||
checkPermanentCount("after transform", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Incubator Token", 0);
|
|
||||||
checkPermanentCount("after transform", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Phyrexian Token", 1);
|
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,290 @@
|
||||||
package org.mage.test.cards.abilities.keywords;
|
package org.mage.test.cards.abilities.keywords;
|
||||||
|
|
||||||
|
import mage.ObjectColor;
|
||||||
|
import mage.abilities.common.SagaAbility;
|
||||||
|
import mage.abilities.common.WerewolfFrontTriggeredAbility;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
|
import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.permanent.PermanentToken;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
*/
|
*/
|
||||||
public class TransformTest extends CardTestPlayerBase {
|
public class TransformTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Silvercoat Lion
|
||||||
|
{1}{W}
|
||||||
|
Creature - Cat
|
||||||
|
|
||||||
|
2/2
|
||||||
|
*/
|
||||||
|
private static final String silvercoatLion = "Silvercoat Lion";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Lightning Bolt
|
||||||
|
{R}
|
||||||
|
Instant
|
||||||
|
Lightning Bolt deals 3 damage to any target.
|
||||||
|
*/
|
||||||
|
private static final String lightningBolt = "Lightning Bolt";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Azusa's Many Journeys
|
||||||
|
{1}{G}
|
||||||
|
Enchantment - Saga
|
||||||
|
(As this Saga enters and after your draw step, add a lore counter.)
|
||||||
|
I - You may play an additional land this turn.
|
||||||
|
II - You gain 3 life.
|
||||||
|
III - Exile this Saga, then return it to the battlefield transformed under your control.
|
||||||
|
Likeness of the Seeker
|
||||||
|
|
||||||
|
Enchantment Creature - Human Monk
|
||||||
|
Whenever Likeness of the Seeker becomes blocked, untap up to three lands you control.
|
||||||
|
3/3
|
||||||
|
*/
|
||||||
|
private static final String azusasManyJourneys = "Azusa's Many Journeys";
|
||||||
|
private static final String likenessOfTheSeeker = "Likeness of the Seeker";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Liliana, Heretical Healer
|
||||||
|
{1}{B}{B}
|
||||||
|
Legendary Creature - Human Cleric
|
||||||
|
Lifelink
|
||||||
|
Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield.
|
||||||
|
2/3
|
||||||
|
|
||||||
|
Liliana, Defiant Necromancer
|
||||||
|
Legendary Planeswalker - Liliana
|
||||||
|
+2: Each player discards a card.
|
||||||
|
-X: Return target nonlegendary creature with converted mana cost X from your graveyard to the battlefield.
|
||||||
|
-8: You get an emblem with "Whenever a creature you control dies, return it to the battlefield under your control at the beginning of the next end step."
|
||||||
|
*/
|
||||||
|
private static final String lilianaHereticalHealer = "Liliana, Heretical Healer";
|
||||||
|
private static final String lilianaDefiantNecromancer = "Liliana, Defiant Necromancer";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Languish
|
||||||
|
{2}{B}{B}
|
||||||
|
Sorcery
|
||||||
|
All creatures get -4/-4 until end of turn.
|
||||||
|
*/
|
||||||
|
private static final String languish = "Languish";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Nissa, Vastwood Seer
|
||||||
|
{2}{G}
|
||||||
|
Legendary Creature - Elf Scout
|
||||||
|
When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library.
|
||||||
|
Whenever a land enters the battlefield under your control, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control.
|
||||||
|
2/2
|
||||||
|
|
||||||
|
Nissa, Sage Animist
|
||||||
|
Legendary Planeswalker - Nissa
|
||||||
|
+1: Reveal the top card of your library. If it's a land card, put it onto the battlefield. Otherwise, put it into your hand.
|
||||||
|
-2: Put a legendary 4/4 green Elemental creature token named Ashaya, the Awoken World onto the battlefield.
|
||||||
|
-7: Untap up to six target lands. They become 6/6 Elemental creatures. They're still lands.
|
||||||
|
*/
|
||||||
|
private static final String nissaVastwoodSeer = "Nissa, Vastwood Seer";
|
||||||
|
private static final String nissaSageAnimist = "Nissa, Sage Animist";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Fireball
|
||||||
|
{X}{R}
|
||||||
|
Sorcery
|
||||||
|
Fireball deals X damage divided evenly, rounded down, among any number of target creatures and/or players.
|
||||||
|
Fireball costs {1} more to cast for each target beyond the first.
|
||||||
|
*/
|
||||||
|
private static final String fireball = "Fireball";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Infernal Scarring
|
||||||
|
{1}{B}
|
||||||
|
Enchantment - Aura
|
||||||
|
Enchant creature
|
||||||
|
Enchanted creature gets +2/+0 and has "When this creature dies, draw a card."
|
||||||
|
*/
|
||||||
|
private static final String infernalScarring = "Infernal Scarring";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Autumnal Gloom
|
||||||
|
{2}{G}
|
||||||
|
Enchantment
|
||||||
|
{B}: Put the top card of your library into your graveyard.
|
||||||
|
Delirium - At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom.
|
||||||
|
|
||||||
|
Ancient of the Equinox
|
||||||
|
Creature - Treefolk
|
||||||
|
Trample, hexproof
|
||||||
|
4/4
|
||||||
|
*/
|
||||||
|
private static final String autumnalGloom = "Autumnal Gloom";
|
||||||
|
private static final String ancientOfTheEquinox = "Ancient of the Equinox";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Huntmaster of the Fells
|
||||||
|
{2}{R}{G}
|
||||||
|
Creature - Human Werewolf
|
||||||
|
Whenever this creature enters the battlefield or transforms into Huntmaster of the Fells, put a 2/2 green Wolf creature token onto the battlefield and you gain 2 life.
|
||||||
|
At the beginning of each upkeep, if no spells were cast last turn, transform Huntmaster of the Fells.
|
||||||
|
2/2
|
||||||
|
|
||||||
|
Ravager of the Fells
|
||||||
|
Creature - Werewolf
|
||||||
|
Trample
|
||||||
|
Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls.
|
||||||
|
At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells.
|
||||||
|
4/4
|
||||||
|
*/
|
||||||
|
private static final String huntmasterOfTheFells = "Huntmaster of the Fells";
|
||||||
|
private static final String ravagerOfTheFells = "Ravager of the Fells";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Eldrazi Displacer
|
||||||
|
{2}{W}
|
||||||
|
Creature - Eldrazi
|
||||||
|
Devoid
|
||||||
|
{2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control.
|
||||||
|
3/3
|
||||||
|
*/
|
||||||
|
private static final String eldraziDisplacer = "Eldrazi Displacer";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Howlpack Piper
|
||||||
|
{3}{G}
|
||||||
|
Creature - Human Werewolf
|
||||||
|
This spell can't be countered.
|
||||||
|
{1}{G}, {T}: You may put a creature card from your hand onto the battlefield. If it's a Wolf or Werewolf, untap Howlpack Piper. Activate only as a sorcery.
|
||||||
|
Daybound
|
||||||
|
2/2
|
||||||
|
|
||||||
|
Wildsong Howler
|
||||||
|
Creature - Werewolf
|
||||||
|
Whenever this creature enters the battlefield or transforms into Wildsong Howler, look at the top six cards of your library. You may reveal a creature card from among them and put it into your hand. Put the rest on the bottom of your library in a random order.
|
||||||
|
Nightbound
|
||||||
|
4/4
|
||||||
|
*/
|
||||||
|
private static final String howlpackPiper = "Howlpack Piper";
|
||||||
|
private static final String wildsongHowler = "Wildsong Howler";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Thing in the Ice
|
||||||
|
{1}{U}
|
||||||
|
Creature - Horror
|
||||||
|
Defender
|
||||||
|
Thing in the Ice enters the battlefield with four ice counters on it.
|
||||||
|
Whenever you cast an instant or sorcery spell, remove an ice counter from Thing in the Ice. Then if it has no ice counters on it, transform it.
|
||||||
|
|
||||||
|
Awoken Horror
|
||||||
|
Creature - Kraken Horror
|
||||||
|
When this creature transforms into Awoken Horrow, return all non-Horror creatures to their owners' hands.
|
||||||
|
7/8
|
||||||
|
*/
|
||||||
|
private static final String thingInTheIce = "Thing in the Ice";
|
||||||
|
private static final String awokenHorror = "Awoken Horror";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Banners Raised
|
||||||
|
{R}
|
||||||
|
Instant
|
||||||
|
Creatures you control get +1/+0 until end of turn.
|
||||||
|
*/
|
||||||
|
private static final String bannersRaised = "Banners Raised";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Phantasmal Image
|
||||||
|
{1}{U}
|
||||||
|
Creature - Illusion
|
||||||
|
You may have Phantasmal Image enter the battlefield as a copy of any creature on the battlefield, except it's an Illusion in addition to its other types and it gains "When this creature becomes the target of a spell or ability, sacrifice it."
|
||||||
|
*/
|
||||||
|
private static final String phantasmalImage = "Phantasmal Image";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Delver of Secrets
|
||||||
|
{U}
|
||||||
|
Creature - Human Wizard
|
||||||
|
At the beginning of your upkeep, look at the top card of your library. You may reveal that card. If an instant or sorcery card is revealed this way, transform Delver of Secrets.
|
||||||
|
1/1
|
||||||
|
|
||||||
|
Insectile Aberration
|
||||||
|
Creature - Human Insect
|
||||||
|
Flying
|
||||||
|
3/2
|
||||||
|
*/
|
||||||
|
private static final String delverOfSecrets = "Delver of Secrets";
|
||||||
|
private static final String insectileAberration = "Insectile Aberration";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Moonmist
|
||||||
|
{1}{G}
|
||||||
|
Instant
|
||||||
|
Transform all Humans. Prevent all combat damage that would be dealt this turn by creatures other than Werewolves and Wolves. <i>(Only double-faced cards can be transformed.)</i>
|
||||||
|
*/
|
||||||
|
private static final String moonmist = "Moonmist";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Maskwood Nexus
|
||||||
|
{4}
|
||||||
|
Artifact
|
||||||
|
Creatures you control are every creature type. The same is true for creature spells you control and creature cards you own that aren't on the battlefield.
|
||||||
|
{3}, {T}: Create a 2/2 blue Shapeshifter creature token with changeling.
|
||||||
|
*/
|
||||||
|
private static final String maskwoodNexus = "Maskwood Nexus";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dress Down
|
||||||
|
{1}{U}
|
||||||
|
Enchantment
|
||||||
|
Flash
|
||||||
|
When Dress Down enters the battlefield, draw a card.
|
||||||
|
Creatures lose all abilities.
|
||||||
|
At the beginning of the end step, sacrifice Dress Down.
|
||||||
|
*/
|
||||||
|
private static final String dressDown = "Dress Down";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Baithook Angler
|
||||||
|
{1}{U}
|
||||||
|
Creature - Human Peasant
|
||||||
|
Disturb {1}{U}
|
||||||
|
2/1
|
||||||
|
|
||||||
|
Hook-Haunt Drifter
|
||||||
|
Creature - Spirit
|
||||||
|
Flying
|
||||||
|
If Hook-Haunt Drifter would be put into a graveyard from anywhere, exile it instead.
|
||||||
|
1/2
|
||||||
|
*/
|
||||||
|
private static final String baithookAngler = "Baithook Angler";
|
||||||
|
private static final String hookHauntDrifter = "Hook-Haunt Drifter";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Croaking Counterpart
|
||||||
|
{1}{G}{U}
|
||||||
|
Sorcery
|
||||||
|
Create a token that's a copy of target non-Frog creature, except it's a 1/1 green Frog.
|
||||||
|
Flashback {3}{G}{U}
|
||||||
|
*/
|
||||||
|
private static final String croakingCounterpart = "Croaking Counterpart";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Abnormal Endurance
|
||||||
|
{1}{B}
|
||||||
|
Instant
|
||||||
|
Until end of turn, target creature gets +2/+0 and gains "When this creature dies, return it to the battlefield tapped under its owner's control."
|
||||||
|
*/
|
||||||
|
private static final String abnormalEndurance = "Abnormal Endurance";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void NissaVastwoodSeerTest() {
|
public void NissaVastwoodSeerTest() {
|
||||||
|
|
||||||
|
|
@ -22,13 +295,13 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
// When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library.
|
// When Nissa, Vastwood Seer enters the battlefield, you may search your library for a basic Forest card, reveal it, put it into your hand, then shuffle your library.
|
||||||
// Whenever a land you control enters, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control.
|
// Whenever a land you control enters, if you control seven or more lands, exile Nissa, then return her to the battlefield transformed under her owner's control.
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Nissa, Vastwood Seer");
|
addCard(Zone.HAND, playerA, nissaVastwoodSeer);
|
||||||
|
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Forest", 2);
|
addCard(Zone.BATTLEFIELD, playerB, "Forest", 2);
|
||||||
// {G}{G}, Sacrifice Rootrunner: Put target land on top of its owner's library.
|
// {G}{G}, Sacrifice Rootrunner: Put target land on top of its owner's library.
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Rootrunner"); // {2}{G}{G}
|
addCard(Zone.BATTLEFIELD, playerB, "Rootrunner"); // {2}{G}{G}
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Nissa, Vastwood Seer", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, nissaVastwoodSeer, true);
|
||||||
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest");
|
playLand(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Forest");
|
||||||
|
|
||||||
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "{G}{G}", "Swamp");
|
activateAbility(1, PhaseStep.POSTCOMBAT_MAIN, playerB, "{G}{G}", "Swamp");
|
||||||
|
|
@ -40,38 +313,38 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
assertGraveyardCount(playerB, "Rootrunner", 1);
|
assertGraveyardCount(playerB, "Rootrunner", 1);
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Nissa, Vastwood Seer", 0);
|
assertPermanentCount(playerA, nissaVastwoodSeer, 0);
|
||||||
assertPermanentCount(playerA, "Nissa, Sage Animist", 1);
|
assertPermanentCount(playerA, nissaSageAnimist, 1);
|
||||||
|
|
||||||
assertCounterCount("Nissa, Sage Animist", CounterType.LOYALTY, 4);
|
assertCounterCount(nissaSageAnimist, CounterType.LOYALTY, 4);
|
||||||
assertPermanentCount(playerA, "Forest", 6);
|
assertPermanentCount(playerA, "Forest", 6);
|
||||||
assertPermanentCount(playerA, "Swamp", 1);
|
assertPermanentCount(playerA, "Swamp", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void LilianaHereticalHealer() {
|
public void LilianaHereticalHealer() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
|
addCard(Zone.BATTLEFIELD, playerA, silvercoatLion, 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||||
|
|
||||||
// Lifelink
|
// Lifelink
|
||||||
// Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield.
|
// Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield.
|
||||||
addCard(Zone.HAND, playerA, "Liliana, Heretical Healer");
|
addCard(Zone.HAND, playerA, lilianaHereticalHealer);
|
||||||
|
|
||||||
addCard(Zone.HAND, playerB, "Lightning Bolt");
|
addCard(Zone.HAND, playerB, lightningBolt);
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
|
addCard(Zone.BATTLEFIELD, playerB, "Mountain", 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Liliana, Heretical Healer");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lilianaHereticalHealer);
|
||||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, "Lightning Bolt", "Silvercoat Lion");
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, lightningBolt, silvercoatLion);
|
||||||
|
|
||||||
setStopAt(1, PhaseStep.DECLARE_ATTACKERS);
|
setStopAt(1, PhaseStep.DECLARE_ATTACKERS);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertGraveyardCount(playerA, "Silvercoat Lion", 1);
|
assertGraveyardCount(playerA, silvercoatLion, 1);
|
||||||
assertGraveyardCount(playerB, "Lightning Bolt", 1);
|
assertGraveyardCount(playerB, lightningBolt, 1);
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Liliana, Heretical Healer", 0);
|
assertPermanentCount(playerA, lilianaHereticalHealer, 0);
|
||||||
assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 1);
|
assertPermanentCount(playerA, lilianaDefiantNecromancer, 1);
|
||||||
assertCounterCount("Liliana, Defiant Necromancer", CounterType.LOYALTY, 3);
|
assertCounterCount(lilianaDefiantNecromancer, CounterType.LOYALTY, 3);
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Zombie Token", 1);
|
assertPermanentCount(playerA, "Zombie Token", 1);
|
||||||
}
|
}
|
||||||
|
|
@ -84,45 +357,45 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void LilianaHereticalHealer2() {
|
public void LilianaHereticalHealer2() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion", 1);
|
addCard(Zone.BATTLEFIELD, playerA, silvercoatLion, 1);
|
||||||
|
|
||||||
// Lifelink
|
// Lifelink
|
||||||
// Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield.
|
// Whenever another nontoken creature you control dies, exile Liliana Heretical Healer, then return her to the battlefield transformed under her owner's control. If you do, put a 2/2 black Zombie creature token onto the battlefield.
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Liliana, Heretical Healer");
|
addCard(Zone.BATTLEFIELD, playerA, lilianaHereticalHealer);
|
||||||
|
|
||||||
// All creatures get -4/-4 until end of turn.
|
// All creatures get -4/-4 until end of turn.
|
||||||
addCard(Zone.HAND, playerB, "Languish");
|
addCard(Zone.HAND, playerB, languish);
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 4);
|
addCard(Zone.BATTLEFIELD, playerB, "Swamp", 4);
|
||||||
|
|
||||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Languish");
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, languish);
|
||||||
|
|
||||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertGraveyardCount(playerB, "Languish", 1);
|
assertGraveyardCount(playerB, languish, 1);
|
||||||
assertPermanentCount(playerA, "Liliana, Defiant Necromancer", 0);
|
assertPermanentCount(playerA, lilianaDefiantNecromancer, 0);
|
||||||
assertPermanentCount(playerA, "Zombie Token", 0);
|
assertPermanentCount(playerA, "Zombie Token", 0);
|
||||||
|
|
||||||
assertGraveyardCount(playerA, "Silvercoat Lion", 1);
|
assertGraveyardCount(playerA, silvercoatLion, 1);
|
||||||
assertGraveyardCount(playerA, "Liliana, Heretical Healer", 1);
|
assertGraveyardCount(playerA, lilianaHereticalHealer, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void TestEnchantmentToCreature() {
|
public void TestEnchantmentToCreature() {
|
||||||
addCard(Zone.GRAVEYARD, playerA, "Silvercoat Lion", 1);
|
addCard(Zone.GRAVEYARD, playerA, silvercoatLion, 1);
|
||||||
addCard(Zone.GRAVEYARD, playerA, "Lightning Bolt", 1);
|
addCard(Zone.GRAVEYARD, playerA, lightningBolt, 1);
|
||||||
addCard(Zone.GRAVEYARD, playerA, "Fireball", 1);
|
addCard(Zone.GRAVEYARD, playerA, fireball, 1);
|
||||||
addCard(Zone.GRAVEYARD, playerA, "Infernal Scarring", 1);
|
addCard(Zone.GRAVEYARD, playerA, infernalScarring, 1);
|
||||||
|
|
||||||
// {B}: Put the top card of your library into your graveyard.
|
// {B}: Put the top card of your library into your graveyard.
|
||||||
// <i>Delirium</i> &mdash At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom.
|
// <i>Delirium</i> &mdash At the beginning of your end step, if there are four or more card types among cards in your graveyard, transform Autumnal Gloom.
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Autumnal Gloom");
|
addCard(Zone.BATTLEFIELD, playerA, autumnalGloom);
|
||||||
|
|
||||||
setStopAt(2, PhaseStep.PRECOMBAT_MAIN);
|
setStopAt(2, PhaseStep.PRECOMBAT_MAIN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Autumnal Gloom", 0);
|
assertPermanentCount(playerA, autumnalGloom, 0);
|
||||||
assertPermanentCount(playerA, "Ancient of the Equinox", 1);
|
assertPermanentCount(playerA, ancientOfTheEquinox, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -138,6 +411,7 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCultOfTheWaxingMoon() {
|
public void testCultOfTheWaxingMoon() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
// Whenever a permanent you control transforms into a non-Human creature, put a 2/2 green Wolf creature token onto the battlefield.
|
// Whenever a permanent you control transforms into a non-Human creature, put a 2/2 green Wolf creature token onto the battlefield.
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Cult of the Waxing Moon");
|
addCard(Zone.BATTLEFIELD, playerA, "Cult of the Waxing Moon");
|
||||||
// {1}{G} - Human Werewolf
|
// {1}{G} - Human Werewolf
|
||||||
|
|
@ -151,6 +425,7 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
assertPermanentCount(playerA, "Cult of the Waxing Moon", 1);
|
assertPermanentCount(playerA, "Cult of the Waxing Moon", 1);
|
||||||
assertPermanentCount(playerA, "Timber Shredder", 1); // Night-side card of Hinterland Logger, Werewolf (non-human)
|
assertPermanentCount(playerA, "Timber Shredder", 1); // Night-side card of Hinterland Logger, Werewolf (non-human)
|
||||||
assertPermanentCount(playerA, "Wolf Token", 1); // wolf token created
|
assertPermanentCount(playerA, "Wolf Token", 1); // wolf token created
|
||||||
|
assertAbilityCount(playerA, "Timber Shredder", WerewolfFrontTriggeredAbility.class, 0); // no front face ability
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -184,18 +459,42 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStartledAwakeMoonmist() {
|
public void testPersistentNightmareTrigger() {
|
||||||
addCard(Zone.HAND, playerA, "Startled Awake");
|
// Target opponent puts the top thirteen cards of their library into their graveyard.
|
||||||
addCard(Zone.HAND, playerA, "Moonmist");
|
// {3}{U}{U}: Put Startled Awake from your graveyard onto the battlefield transformed. Activate this ability only any time you could cast a sorcery.
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 11);
|
addCard(Zone.HAND, playerA, "Startled Awake"); // SORCERY {2}{U}{U}"
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Maskwood Nexus");
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 9);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Startled Awake", playerB);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Startled Awake", playerB);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{U}{U}");
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{U}{U}");
|
||||||
|
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Moonmist");
|
attack(3, playerA, "Persistent Nightmare");
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(3, PhaseStep.COMBAT_DAMAGE);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerB, 13);
|
||||||
|
assertGraveyardCount(playerA, "Startled Awake", 0);
|
||||||
|
assertPermanentCount(playerA, "Persistent Nightmare", 0); // Night-side card of Startled Awake
|
||||||
|
assertHandCount(playerA, "Startled Awake", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testStartledAwakeMoonmist() {
|
||||||
|
addCard(Zone.HAND, playerA, "Startled Awake");
|
||||||
|
addCard(Zone.HAND, playerA, moonmist);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 11);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, maskwoodNexus);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Startled Awake", playerB);
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{3}{U}{U}");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, moonmist);
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
|
@ -241,6 +540,25 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
assertPermanentCount(playerB, "Lambholt Pacifist", 1);
|
assertPermanentCount(playerB, "Lambholt Pacifist", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisturbExile() {
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, baithookAngler);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Mountain");
|
||||||
|
addCard(Zone.HAND, playerB, lightningBolt);
|
||||||
|
|
||||||
|
// Disturb {1}{U}
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, hookHauntDrifter + " using Disturb");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerB, lightningBolt, hookHauntDrifter);
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, hookHauntDrifter, 0);
|
||||||
|
assertExileCount(playerA, baithookAngler, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mirror Mockery copies the front face of a Transformed card rather than
|
* Mirror Mockery copies the front face of a Transformed card rather than
|
||||||
* the current face.
|
* the current face.
|
||||||
|
|
@ -251,7 +569,7 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
* Trespasser.
|
* Trespasser.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testTransformCopyrnansformed() {
|
public void testTransformCopyTransformed() {
|
||||||
// Skulk (This creature can't be blocked by creatures with greater power.)
|
// Skulk (This creature can't be blocked by creatures with greater power.)
|
||||||
// When Uninvited Geist deals combat damage to a player, transform it.
|
// When Uninvited Geist deals combat damage to a player, transform it.
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Uninvited Geist"); // Creature 2/2 {2}{U}
|
addCard(Zone.BATTLEFIELD, playerA, "Uninvited Geist"); // Creature 2/2 {2}{U}
|
||||||
|
|
@ -272,7 +590,7 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
setStopAt(3, PhaseStep.COMBAT_DAMAGE);
|
setStopAt(3, PhaseStep.COMBAT_DAMAGE);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertLife(playerB, 15);
|
assertLife(playerB, 20 - 2 - 3);
|
||||||
|
|
||||||
assertPermanentCount(playerB, "Mirror Mockery", 1);
|
assertPermanentCount(playerB, "Mirror Mockery", 1);
|
||||||
assertPermanentCount(playerA, "Unimpeded Trespasser", 1);
|
assertPermanentCount(playerA, "Unimpeded Trespasser", 1);
|
||||||
|
|
@ -293,16 +611,16 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
// Transformed side: Avacyn, the Purifier - Creature 6/5
|
// Transformed side: Avacyn, the Purifier - Creature 6/5
|
||||||
// Flying
|
// Flying
|
||||||
// When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent.
|
// When this creature transforms into Avacyn, the Purifier, it deals 3 damage to each other creature and each opponent.
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Silvercoat Lion");
|
addCard(Zone.BATTLEFIELD, playerA, silvercoatLion);
|
||||||
addCard(Zone.HAND, playerA, "Lightning Bolt");
|
addCard(Zone.HAND, playerA, lightningBolt);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain");
|
||||||
|
|
||||||
// Devoid
|
// Devoid
|
||||||
// {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control.
|
// {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control.
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Eldrazi Displacer", 1);
|
addCard(Zone.BATTLEFIELD, playerB, eldraziDisplacer, 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Wastes", 3);
|
addCard(Zone.BATTLEFIELD, playerB, "Wastes", 3);
|
||||||
|
|
||||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, "Lightning Bolt", "Silvercoat Lion");
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerA, lightningBolt, silvercoatLion);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, true);
|
||||||
|
|
||||||
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{2}{C}", "Archangel Avacyn");
|
activateAbility(2, PhaseStep.PRECOMBAT_MAIN, playerB, "{2}{C}", "Archangel Avacyn");
|
||||||
|
|
@ -310,10 +628,10 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
|
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertGraveyardCount(playerA, "Lightning Bolt", 1);
|
assertGraveyardCount(playerA, lightningBolt, 1);
|
||||||
assertGraveyardCount(playerA, "Silvercoat Lion", 1);
|
assertGraveyardCount(playerA, silvercoatLion, 1);
|
||||||
|
|
||||||
assertPermanentCount(playerB, "Eldrazi Displacer", 1);
|
assertPermanentCount(playerB, eldraziDisplacer, 1);
|
||||||
assertPermanentCount(playerA, "Avacyn, the Purifier", 0);
|
assertPermanentCount(playerA, "Avacyn, the Purifier", 0);
|
||||||
assertPermanentCount(playerA, "Archangel Avacyn", 1);
|
assertPermanentCount(playerA, "Archangel Avacyn", 1);
|
||||||
}
|
}
|
||||||
|
|
@ -355,20 +673,20 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
// Ravager of the Fells
|
// Ravager of the Fells
|
||||||
// Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls.
|
// Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls.
|
||||||
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells.
|
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells.
|
||||||
addCard(Zone.HAND, playerA, "Huntmaster of the Fells"); // Creature {2}{R}{G}
|
addCard(Zone.HAND, playerA, huntmasterOfTheFells); // Creature {2}{R}{G}
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
|
||||||
|
|
||||||
// Devoid
|
// Devoid
|
||||||
// {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control.
|
// {2}{C}: Exile another target creature, then return it to the battlefield tapped under its owner's control.
|
||||||
addCard(Zone.HAND, playerB, "Eldrazi Displacer", 1); // Creature {2}{W}
|
addCard(Zone.HAND, playerB, eldraziDisplacer, 1); // Creature {2}{W}
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
|
addCard(Zone.BATTLEFIELD, playerB, "Plains", 2);
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Wastes", 1);
|
addCard(Zone.BATTLEFIELD, playerB, "Wastes", 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Huntmaster of the Fells");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, huntmasterOfTheFells);
|
||||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Eldrazi Displacer");
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, eldraziDisplacer);
|
||||||
|
|
||||||
activateAbility(4, PhaseStep.UPKEEP, playerB, "{2}{C}", "Huntmaster of the Fells", "At the beginning of each upkeep");
|
activateAbility(4, PhaseStep.UPKEEP, playerB, "{2}{C}", huntmasterOfTheFells, "At the beginning of each upkeep");
|
||||||
|
|
||||||
setStopAt(4, PhaseStep.PRECOMBAT_MAIN);
|
setStopAt(4, PhaseStep.PRECOMBAT_MAIN);
|
||||||
execute();
|
execute();
|
||||||
|
|
@ -376,11 +694,11 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
assertLife(playerA, 24);
|
assertLife(playerA, 24);
|
||||||
assertPermanentCount(playerA, "Wolf Token", 2);
|
assertPermanentCount(playerA, "Wolf Token", 2);
|
||||||
|
|
||||||
assertPermanentCount(playerB, "Eldrazi Displacer", 1);
|
assertPermanentCount(playerB, eldraziDisplacer, 1);
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Ravager of the Fells", 0);
|
assertPermanentCount(playerA, ravagerOfTheFells, 0);
|
||||||
assertPermanentCount(playerA, "Huntmaster of the Fells", 1);
|
assertPermanentCount(playerA, huntmasterOfTheFells, 1);
|
||||||
assertPowerToughness(playerA, "Huntmaster of the Fells", 2, 2);
|
assertPowerToughness(playerA, huntmasterOfTheFells, 2, 2);
|
||||||
assertTappedCount("Plains", true, 2);
|
assertTappedCount("Plains", true, 2);
|
||||||
assertTappedCount("Wastes", true, 1);
|
assertTappedCount("Wastes", true, 1);
|
||||||
}
|
}
|
||||||
|
|
@ -392,50 +710,50 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
// Ravager of the Fells
|
// Ravager of the Fells
|
||||||
// Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls.
|
// Whenever this creature transforms into Ravager of the Fells, it deals 2 damage to target opponent and 2 damage to up to one target creature that player controls.
|
||||||
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells.
|
// At the beginning of each upkeep, if a player cast two or more spells last turn, transform Ravager of the Fells.
|
||||||
addCard(Zone.HAND, playerA, "Huntmaster of the Fells"); // Creature {2}{R}{G}
|
addCard(Zone.HAND, playerA, huntmasterOfTheFells); // Creature {2}{R}{G}
|
||||||
addCard(Zone.HAND, playerA, "Silvercoat Lion", 2);
|
addCard(Zone.HAND, playerA, silvercoatLion, 2);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 2);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 2);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 3);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Huntmaster of the Fells", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, huntmasterOfTheFells, true);
|
||||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion", true);
|
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, silvercoatLion, true);
|
||||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Silvercoat Lion");
|
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, silvercoatLion);
|
||||||
setStopAt(4, PhaseStep.PRECOMBAT_MAIN);
|
setStopAt(4, PhaseStep.PRECOMBAT_MAIN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertLife(playerA, 24);
|
assertLife(playerA, 24);
|
||||||
assertLife(playerB, 18);
|
assertLife(playerB, 18);
|
||||||
assertPermanentCount(playerA, "Wolf Token", 2);
|
assertPermanentCount(playerA, "Wolf Token", 2);
|
||||||
assertPermanentCount(playerA, "Silvercoat Lion", 2);
|
assertPermanentCount(playerA, silvercoatLion, 2);
|
||||||
assertPermanentCount(playerA, "Ravager of the Fells", 0);
|
assertPermanentCount(playerA, ravagerOfTheFells, 0);
|
||||||
assertPermanentCount(playerA, "Huntmaster of the Fells", 1);
|
assertPermanentCount(playerA, huntmasterOfTheFells, 1);
|
||||||
assertPowerToughness(playerA, "Huntmaster of the Fells", 2, 2);
|
assertPowerToughness(playerA, huntmasterOfTheFells, 2, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWildsongHowlerTrigger() {
|
public void testWildsongHowlerTrigger() {
|
||||||
// The only Daybound/Nightbound card with a Transforms trigger on the back side
|
// The only Daybound/Nightbound card with a Transforms trigger on the back side
|
||||||
removeAllCardsFromLibrary(playerA);
|
removeAllCardsFromLibrary(playerA);
|
||||||
addCard(Zone.HAND, playerA, "Howlpack Piper", 2); // Creature {2}{R}{G}
|
addCard(Zone.HAND, playerA, howlpackPiper, 2); // Creature {2}{R}{G}
|
||||||
addCard(Zone.LIBRARY, playerA, "Silvercoat Lion", 50);
|
addCard(Zone.LIBRARY, playerA, silvercoatLion, 50);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Howlpack Piper");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, howlpackPiper);
|
||||||
setChoice(playerA, true); //Transform trigger
|
setChoice(playerA, true); //Transform trigger
|
||||||
addTarget(playerA, "Silvercoat Lion");
|
addTarget(playerA, silvercoatLion);
|
||||||
|
|
||||||
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Howlpack Piper");
|
castSpell(3, PhaseStep.PRECOMBAT_MAIN, playerA, howlpackPiper);
|
||||||
setChoice(playerA, true); //ETB trigger
|
setChoice(playerA, true); //ETB trigger
|
||||||
addTarget(playerA, "Silvercoat Lion");
|
addTarget(playerA, silvercoatLion);
|
||||||
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
|
setStopAt(3, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Wildsong Howler", 2);
|
assertPermanentCount(playerA, wildsongHowler, 2);
|
||||||
assertPermanentCount(playerA, "Howlpack Piper", 0); // They should be both transformed
|
assertPermanentCount(playerA, howlpackPiper, 0); // They should be both transformed
|
||||||
assertHandCount(playerA, "Silvercoat Lion", 3);
|
assertHandCount(playerA, silvercoatLion, 3);
|
||||||
assertHandCount(playerA, 3); //The two Silvercoat Lions from triggers and 1 from natural card draw
|
assertHandCount(playerA, 3); //The two Silvercoat Lions from triggers and 1 from natural card draw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -455,37 +773,37 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
// Thing in the Ice enters the battlefield with four ice counters on it.
|
// Thing in the Ice enters the battlefield with four ice counters on it.
|
||||||
// Whenever you cast an instant or sorcery spell, remove an ice counter from Thing in the Ice.
|
// Whenever you cast an instant or sorcery spell, remove an ice counter from Thing in the Ice.
|
||||||
// Then if it has no ice counters on it, transform it.
|
// Then if it has no ice counters on it, transform it.
|
||||||
addCard(Zone.HAND, playerA, "Thing in the Ice"); // Creature {1}{U}
|
addCard(Zone.HAND, playerA, thingInTheIce); // Creature {1}{U}
|
||||||
// Creatures you control get +1/+0 until end of turn.
|
// Creatures you control get +1/+0 until end of turn.
|
||||||
addCard(Zone.HAND, playerA, "Banners Raised", 4); // Creature {R}
|
addCard(Zone.HAND, playerA, bannersRaised, 4); // Creature {R}
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6);
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 6);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
|
|
||||||
// You may have Phantasmal Image enter the battlefield as a copy of any creature
|
// You may have Phantasmal Image enter the battlefield as a copy of any creature
|
||||||
// on the battlefield, except it's an Illusion in addition to its other types and
|
// on the battlefield, except it's an Illusion in addition to its other types and
|
||||||
// it has "When this creature becomes the target of a spell or ability, sacrifice it."
|
// it has "When this creature becomes the target of a spell or ability, sacrifice it."
|
||||||
addCard(Zone.HAND, playerB, "Phantasmal Image", 1); // Creature {1}{U}
|
addCard(Zone.HAND, playerB, phantasmalImage, 1); // Creature {1}{U}
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
|
addCard(Zone.BATTLEFIELD, playerB, "Island", 2);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Thing in the Ice");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, thingInTheIce);
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised");
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised);
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised");
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised);
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised");
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised);
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Banners Raised");
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, bannersRaised);
|
||||||
|
|
||||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Phantasmal Image");
|
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, phantasmalImage);
|
||||||
|
|
||||||
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
setStopAt(2, PhaseStep.BEGIN_COMBAT);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertLife(playerA, 20);
|
assertLife(playerA, 20);
|
||||||
assertGraveyardCount(playerA, "Banners Raised", 4);
|
assertGraveyardCount(playerA, bannersRaised, 4);
|
||||||
assertPermanentCount(playerA, "Thing in the Ice", 0);
|
assertPermanentCount(playerA, thingInTheIce, 0);
|
||||||
assertPermanentCount(playerA, "Awoken Horror", 1);
|
assertPermanentCount(playerA, awokenHorror, 1);
|
||||||
assertPowerToughness(playerA, "Awoken Horror", 7, 8);
|
assertPowerToughness(playerA, awokenHorror, 7, 8);
|
||||||
|
|
||||||
assertPermanentCount(playerB, "Awoken Horror", 1);
|
assertPermanentCount(playerB, awokenHorror, 1);
|
||||||
assertPowerToughness(playerB, "Awoken Horror", 7, 8);
|
assertPowerToughness(playerB, awokenHorror, 7, 8);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -493,45 +811,45 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
public void testMoonmistDelver() {
|
public void testMoonmistDelver() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island");
|
addCard(Zone.BATTLEFIELD, playerA, "Island");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 4);
|
||||||
addCard(Zone.HAND, playerA, "Delver of Secrets");
|
addCard(Zone.HAND, playerA, delverOfSecrets);
|
||||||
addCard(Zone.HAND, playerA, "Moonmist", 2);
|
addCard(Zone.HAND, playerA, moonmist, 2);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Delver of Secrets");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, delverOfSecrets);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Moonmist");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, moonmist);
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Delver of Secrets", 0);
|
assertPermanentCount(playerA, delverOfSecrets, 0);
|
||||||
assertPermanentCount(playerA, "Insectile Aberration", 1);
|
assertPermanentCount(playerA, insectileAberration, 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Moonmist");
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, moonmist);
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
assertPermanentCount(playerA, "Delver of Secrets", 1);
|
assertPermanentCount(playerA, delverOfSecrets, 1);
|
||||||
assertPermanentCount(playerA, "Insectile Aberration", 0);
|
assertPermanentCount(playerA, insectileAberration, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMoonmistHuntmasterDressdown() {
|
public void testMoonmistHuntmasterDressdown() {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 6);
|
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 6);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Huntmaster of the Fells"); //Has on-transform triggers
|
addCard(Zone.BATTLEFIELD, playerA, huntmasterOfTheFells); //Has on-transform triggers
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Maskwood Nexus"); //Make back side human
|
addCard(Zone.BATTLEFIELD, playerA, maskwoodNexus); //Make back side human
|
||||||
|
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Dress Down"); //Creatures lose all abilities
|
addCard(Zone.HAND, playerA, dressDown); //Creatures lose all abilities
|
||||||
addCard(Zone.HAND, playerA, "Moonmist", 2);
|
addCard(Zone.HAND, playerA, moonmist, 2);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.UPKEEP, playerA, "Dress Down");
|
castSpell(1, PhaseStep.UPKEEP, playerA, dressDown);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Moonmist");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, moonmist);
|
||||||
checkPermanentCount("Huntmaster flipped", 1, PhaseStep.BEGIN_COMBAT, playerA, "Ravager of the Fells", 1);
|
checkPermanentCount("Huntmaster flipped", 1, PhaseStep.BEGIN_COMBAT, playerA, ravagerOfTheFells, 1);
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Moonmist");
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, moonmist);
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
|
@ -539,8 +857,71 @@ public class TransformTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
assertLife(playerA, 20);
|
assertLife(playerA, 20);
|
||||||
assertLife(playerB, 20);
|
assertLife(playerB, 20);
|
||||||
assertGraveyardCount(playerA, "Dress Down", 1);
|
assertGraveyardCount(playerA, dressDown, 1);
|
||||||
assertPermanentCount(playerA, "Huntmaster of the Fells", 1);
|
assertPermanentCount(playerA, huntmasterOfTheFells, 1);
|
||||||
assertPermanentCount(playerA, 6+1+1);
|
assertPermanentCount(playerA, 6+1+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTokenCopyTransformed() {
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, baithookAngler);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Breeding Pool", 5);
|
||||||
|
addCard(Zone.HAND, playerA, croakingCounterpart);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hook-Haunt Drifter using Disturb");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, croakingCounterpart, hookHauntDrifter);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
for (Permanent token : currentGame.getBattlefield().getActivePermanents(playerA.getId(), currentGame)) {
|
||||||
|
if (!(token instanceof PermanentToken)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assertTrue(token.getSubtype(currentGame).contains(SubType.FROG));
|
||||||
|
assertEquals(ObjectColor.GREEN, token.getColor(currentGame));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFrontSaga() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, azusasManyJourneys);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, azusasManyJourneys, 0);
|
||||||
|
assertPermanentCount(playerA, likenessOfTheSeeker, 1);
|
||||||
|
assertPowerToughness(playerA, likenessOfTheSeeker, 3, 3);
|
||||||
|
assertAbilityCount(playerA, likenessOfTheSeeker, SagaAbility.class, 0); // does not have saga ability
|
||||||
|
assertLife(playerA, 20 + 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* testing if a double faced card gains a death trigger, it still works correctly
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDiesTrigger() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, baithookAngler);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Swamp", 3);
|
||||||
|
addCard(Zone.HAND, playerA, abnormalEndurance);
|
||||||
|
|
||||||
|
addCard(Zone.HAND, playerB, lightningBolt);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Mountain");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerB, lightningBolt, baithookAngler);
|
||||||
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, abnormalEndurance, baithookAngler, lightningBolt);
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.DECLARE_ATTACKERS);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertGraveyardCount(playerA, baithookAngler, 0);
|
||||||
|
assertGraveyardCount(playerB, lightningBolt, 1);
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, baithookAngler, 1);
|
||||||
|
assertTrue(getPermanent(baithookAngler, playerA).isTapped());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,13 @@ package org.mage.test.cards.copy;
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
import org.junit.Ignore;
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
|
|
@ -85,4 +88,22 @@ public class CopyCreatureCardToTokenImplTest extends CardTestPlayerBase {
|
||||||
assertPermanentCount(playerA, "Thrashing Brontodon", 1);
|
assertPermanentCount(playerA, "Thrashing Brontodon", 1);
|
||||||
assertType("Thrashing Brontodon", CardType.ARTIFACT, true);
|
assertType("Thrashing Brontodon", CardType.ARTIFACT, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTokenCopyTransformedHasSecondFaceWithModifications() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
String hookHauntDrifter = "Hook-Haunt Drifter";
|
||||||
|
addCard(Zone.GRAVEYARD, playerA, "Baithook Angler");
|
||||||
|
addCard(Zone.BATTLEFIELD, playerB, "Faerie Artisans", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Breeding Pool", 5);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cast Hook-Haunt Drifter using Disturb");
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
Permanent token = getPermanent(hookHauntDrifter, playerB);
|
||||||
|
assertTrue(token.getCardType(currentGame).contains(CardType.ARTIFACT));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -907,6 +907,32 @@ public class ModalDoubleFacedCardsTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_Copy_AsSpell_Backside() {
|
||||||
|
addCard(Zone.HAND, playerA, "Alrund, God of the Cosmos", 1); // {3}{U}{U}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 2);
|
||||||
|
//
|
||||||
|
// Copy target creature spell you control, except it isn't legendary if the spell is legendary.
|
||||||
|
addCard(Zone.HAND, playerA, "Double Major", 1); // {G}{U}
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Forest", 1);
|
||||||
|
|
||||||
|
// cast mdf card
|
||||||
|
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {U}", 2);
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hakka, Whispering Raven");
|
||||||
|
// prepare copy of spell
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Double Major", "Hakka, Whispering Raven", "Hakka, Whispering Raven");
|
||||||
|
checkStackSize("before copy spell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2);
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, playerA, true);
|
||||||
|
checkStackSize("after copy spell", 1, PhaseStep.PRECOMBAT_MAIN, playerA, 2);
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
checkPermanentCount("after", 1, PhaseStep.PRECOMBAT_MAIN, playerA, "Hakka, Whispering Raven", 2);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test_Copy_AsCloneFromPermanent() {
|
public void test_Copy_AsCloneFromPermanent() {
|
||||||
addCard(Zone.HAND, playerA, "Akoum Warrior", 1); // {5}{R}
|
addCard(Zone.HAND, playerA, "Akoum Warrior", 1); // {5}{R}
|
||||||
|
|
@ -1138,8 +1164,8 @@ public class ModalDoubleFacedCardsTest extends CardTestPlayerBase {
|
||||||
Assert.assertNotNull(permanent);
|
Assert.assertNotNull(permanent);
|
||||||
|
|
||||||
// MDFC on battlefield has only one side (not transformable)
|
// MDFC on battlefield has only one side (not transformable)
|
||||||
Assert.assertFalse("server must not be transformable", permanent.isTransformable());
|
// Assert.assertFalse("server must not be transformable", permanent.isTransformable());
|
||||||
Assert.assertNull("server must have not other side", permanent.getOtherFace());
|
// Assert.assertNull("server must have not other side", permanent.getOtherFace());
|
||||||
|
|
||||||
List<String> rules = permanent.getRules(game);
|
List<String> rules = permanent.getRules(game);
|
||||||
Assert.assertTrue("server must ignore side 2 - untap ability", rules.stream().noneMatch(r -> r.contains("Untap")));
|
Assert.assertTrue("server must ignore side 2 - untap ability", rules.stream().noneMatch(r -> r.contains("Untap")));
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,191 @@
|
||||||
package org.mage.test.cards.cost.splitcards;
|
package org.mage.test.cards.cost.splitcards;
|
||||||
|
|
||||||
import mage.constants.CardType;
|
import mage.constants.*;
|
||||||
import mage.constants.EmptyNames;
|
import mage.view.CardView;
|
||||||
import mage.constants.PhaseStep;
|
import mage.view.GameView;
|
||||||
import mage.constants.SubType;
|
import mage.view.PlayerView;
|
||||||
import mage.constants.Zone;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.player.TestPlayer;
|
import org.mage.test.player.TestPlayer;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author oscscull
|
* @author oscscull
|
||||||
*/
|
*/
|
||||||
public class RoomCardTest extends CardTestPlayerBase {
|
public class RoomCardTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
|
/*
|
||||||
|
Bottomless Pool // Locker Room
|
||||||
|
{U}
|
||||||
|
Enchantment - Room
|
||||||
|
When you unlock this door, return up to one target creature to its owner's hand.
|
||||||
|
(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)
|
||||||
|
<strong>Locker Room</strong>
|
||||||
|
{4}{U}
|
||||||
|
<strong>Enchantment -- Room</strong>
|
||||||
|
Whenever one or more creatures you control deal combat damage to a player, draw a card.
|
||||||
|
(You may cast either half. That door unlocks on the battlefield. As a sorcery, you may pay the mana cost of a locked door to unlock it.)
|
||||||
|
*/
|
||||||
|
private static final String bottomlessPoolLockerRoom = "Bottomless Pool // Locker Room";
|
||||||
|
private static final String bottomlessPool = "Bottomless Pool";
|
||||||
|
public static final String lockerRoom = "Locker Room";
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCardViewLeftHalf() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool, true);
|
||||||
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
|
|
||||||
|
runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
||||||
|
GameView gameView = getGameView(playerA);
|
||||||
|
PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null);
|
||||||
|
assertNotNull(playerView, "Player view must be found");
|
||||||
|
CardView cardView = playerView.getBattlefield().values()
|
||||||
|
.stream()
|
||||||
|
.filter(pv -> pv.getName().equals(bottomlessPool))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
assertNotNull(cardView, "Locker Room card view must be found on battlefield");
|
||||||
|
// permanent should have 3 abilities
|
||||||
|
// unlock ability + unlock trigger from right half + info
|
||||||
|
assertEquals(3, cardView.getRules().size(), "Locker Room must have 3 rules, has: " + cardView.getRules().size());
|
||||||
|
assertEquals("{U}", cardView.getManaCostStr(), "Mana cost must be from left half");
|
||||||
|
StringBuilder sb = new StringBuilder("\n" + cardView.getName());
|
||||||
|
sb.append("\n - Types: ").append(cardView.getCardTypes());
|
||||||
|
sb.append("\n - Subtypes: ").append(cardView.getSubTypes());
|
||||||
|
sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr());
|
||||||
|
sb.append("\n - Abilities: ");
|
||||||
|
cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule));
|
||||||
|
logger.info(sb.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCardViewRightHalf() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom, true);
|
||||||
|
|
||||||
|
runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
||||||
|
GameView gameView = getGameView(playerA);
|
||||||
|
PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null);
|
||||||
|
assertNotNull(playerView, "Player view must be found");
|
||||||
|
CardView cardView = playerView.getBattlefield().values()
|
||||||
|
.stream()
|
||||||
|
.filter(pv -> pv.getName().equals(lockerRoom))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
assertNotNull(cardView, "Locker Room card view must be found on battlefield");
|
||||||
|
// permanent should have 3 abilities
|
||||||
|
// unlock ability + unlock trigger from left half + info
|
||||||
|
assertEquals(3, cardView.getRules().size(), "Locker Room must have 3 rules, has: " + cardView.getRules().size());
|
||||||
|
assertEquals("{4}{U}", cardView.getManaCostStr(), "Mana cost must be from right half");
|
||||||
|
StringBuilder sb = new StringBuilder("\n" + cardView.getName());
|
||||||
|
sb.append("\n - Types: ").append(cardView.getCardTypes());
|
||||||
|
sb.append("\n - Subtypes: ").append(cardView.getSubTypes());
|
||||||
|
sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr());
|
||||||
|
sb.append("\n - Abilities: ");
|
||||||
|
cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule));
|
||||||
|
logger.info(sb.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCardViewBothHalves() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool, true);
|
||||||
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half.");
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
||||||
|
GameView gameView = getGameView(playerA);
|
||||||
|
PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null);
|
||||||
|
assertNotNull(playerView, "Player view must be found");
|
||||||
|
CardView cardView = playerView.getBattlefield().values()
|
||||||
|
.stream()
|
||||||
|
.filter(pv -> pv.getName().equals(bottomlessPoolLockerRoom))
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
assertNotNull(cardView, "Locker Room card view must be found on battlefield");
|
||||||
|
// permanent should have 3 abilities
|
||||||
|
// 1 ability from both halves
|
||||||
|
// no unlock abilities
|
||||||
|
// 1 info
|
||||||
|
String manaCost = getPermanent(bottomlessPoolLockerRoom)
|
||||||
|
.getManaCost()
|
||||||
|
.stream()
|
||||||
|
.map(Objects::toString)
|
||||||
|
.reduce("", String::concat);
|
||||||
|
assertEquals(3, cardView.getRules().size(), "Locker Room must have 3 rules, has: " + cardView.getRules().size());
|
||||||
|
assertEquals(manaCost, cardView.getManaCostStr(), "Mana cost must be combined from both halves");
|
||||||
|
StringBuilder sb = new StringBuilder("\n" + cardView.getName());
|
||||||
|
sb.append("\n - Types: ").append(cardView.getCardTypes());
|
||||||
|
sb.append("\n - Subtypes: ").append(cardView.getSubTypes());
|
||||||
|
sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr());
|
||||||
|
sb.append("\n - Abilities: ");
|
||||||
|
cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule));
|
||||||
|
logger.info(sb.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCardViewFullyLocked() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, bottomlessPoolLockerRoom);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||||
|
|
||||||
|
runCode("print card view", 1, PhaseStep.PRECOMBAT_MAIN, playerA, (info, player, game) -> {
|
||||||
|
GameView gameView = getGameView(playerA);
|
||||||
|
PlayerView playerView = gameView.getPlayers().stream().findFirst().orElse(null);
|
||||||
|
assertNotNull(playerView, "Player view must be found");
|
||||||
|
CardView cardView = playerView.getBattlefield().values()
|
||||||
|
.stream()
|
||||||
|
.filter(pv -> pv.getName().isEmpty())
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
assertNotNull(cardView, "Locked room card view must be found on battlefield");
|
||||||
|
// permanent should have 3 abilities
|
||||||
|
// 1 info
|
||||||
|
// two unlock abilities
|
||||||
|
assertEquals(3, cardView.getRules().size(), "Locked room must have 3 rules, has: " + cardView.getRules().size());
|
||||||
|
assertEquals("", cardView.getManaCostStr(), "Mana cost must be empty");
|
||||||
|
StringBuilder sb = new StringBuilder("\n" + cardView.getName());
|
||||||
|
sb.append("\n - Types: ").append(cardView.getCardTypes());
|
||||||
|
sb.append("\n - Subtypes: ").append(cardView.getSubTypes());
|
||||||
|
sb.append("\n - Mana Cost: ").append(cardView.getManaCostStr());
|
||||||
|
sb.append("\n - Abilities: ");
|
||||||
|
cardView.getRules().forEach(rule -> sb.append("\n * ").append(rule));
|
||||||
|
logger.info(sb.toString());
|
||||||
|
});
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
execute();
|
||||||
|
}
|
||||||
|
|
||||||
// Bottomless pool is cast. It unlocks, and the trigger to return a creature
|
// Bottomless pool is cast. It unlocks, and the trigger to return a creature
|
||||||
// should bounce one of two grizzly bears.
|
// should bounce one of two grizzly bears.
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -23,13 +195,13 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// creature to its owner’s hand.
|
// creature to its owner’s hand.
|
||||||
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
||||||
// damage to a player, draw a card.
|
// damage to a player, draw a card.
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 2);
|
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 2);
|
||||||
|
|
||||||
checkPlayableAbility("playerA can cast Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA,
|
checkPlayableAbility("playerA can cast Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA,
|
||||||
"Cast Bottomless Pool", true);
|
"Cast Bottomless Pool", true);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
|
|
||||||
// Target one of playerB's "Grizzly Bears" with the return effect.
|
// Target one of playerB's "Grizzly Bears" with the return effect.
|
||||||
addTarget(playerA, "Grizzly Bears");
|
addTarget(playerA, "Grizzly Bears");
|
||||||
|
|
@ -43,11 +215,11 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// Verify that one "Grizzly Bears" has been returned to playerB's hand.
|
// Verify that one "Grizzly Bears" has been returned to playerB's hand.
|
||||||
assertHandCount(playerB, "Grizzly Bears", 1);
|
assertHandCount(playerB, "Grizzly Bears", 1);
|
||||||
// Verify that "Bottomless Pool" is on playerA's battlefield.
|
// Verify that "Bottomless Pool" is on playerA's battlefield.
|
||||||
assertPermanentCount(playerA, "Bottomless Pool", 1);
|
assertPermanentCount(playerA, bottomlessPool, 1);
|
||||||
// Verify that "Bottomless Pool" is an Enchantment.
|
// Verify that "Bottomless Pool" is an Enchantment.
|
||||||
assertType("Bottomless Pool", CardType.ENCHANTMENT, true);
|
assertType(bottomlessPool, CardType.ENCHANTMENT, true);
|
||||||
// Verify that "Bottomless Pool" has the Room subtype.
|
// Verify that "Bottomless Pool" has the Room subtype.
|
||||||
assertSubtype("Bottomless Pool", SubType.ROOM);
|
assertSubtype(bottomlessPool, SubType.ROOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locker room is cast. It enters, and gives a coastal piracy effect that
|
// Locker room is cast. It enters, and gives a coastal piracy effect that
|
||||||
|
|
@ -59,7 +231,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// creature to its owner’s hand.
|
// creature to its owner’s hand.
|
||||||
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
||||||
// damage to a player, draw a card.
|
// damage to a player, draw a card.
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||||
|
|
||||||
// Cards to be drawn
|
// Cards to be drawn
|
||||||
|
|
@ -68,7 +240,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// 2 attackers
|
// 2 attackers
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 2);
|
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 2);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Locker Room");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom);
|
||||||
attack(1, playerA, "Memnite");
|
attack(1, playerA, "Memnite");
|
||||||
attack(1, playerA, "Memnite");
|
attack(1, playerA, "Memnite");
|
||||||
// After combat damage, Memnites dealt combat damage to playerB (1 damage * 2).
|
// After combat damage, Memnites dealt combat damage to playerB (1 damage * 2).
|
||||||
|
|
@ -83,9 +255,9 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
// Assertions after the first execute() (Locker Room and creatures are on
|
// Assertions after the first execute() (Locker Room and creatures are on
|
||||||
// battlefield, combat resolved):
|
// battlefield, combat resolved):
|
||||||
assertPermanentCount(playerA, "Locker Room", 1);
|
assertPermanentCount(playerA, lockerRoom, 1);
|
||||||
assertType("Locker Room", CardType.ENCHANTMENT, true);
|
assertType(lockerRoom, CardType.ENCHANTMENT, true);
|
||||||
assertSubtype("Locker Room", SubType.ROOM);
|
assertSubtype(lockerRoom, SubType.ROOM);
|
||||||
assertPermanentCount(playerA, "Memnite", 2);
|
assertPermanentCount(playerA, "Memnite", 2);
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
@ -102,13 +274,13 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// creature to its owner’s hand.
|
// creature to its owner’s hand.
|
||||||
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
||||||
// damage to a player, draw a card.
|
// damage to a player, draw a card.
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||||
|
|
||||||
// 2 creatures owned by player A
|
// 2 creatures owned by player A
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 2);
|
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 2);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Locker Room");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
checkPlayableAbility("playerA can unlock Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA,
|
checkPlayableAbility("playerA can unlock Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA,
|
||||||
"{U}: Unlock the left half.", true);
|
"{U}: Unlock the left half.", true);
|
||||||
|
|
@ -125,12 +297,12 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
assertPermanentCount(playerA, "Memnite", 1);
|
assertPermanentCount(playerA, "Memnite", 1);
|
||||||
// Verify that one "Memnite" has been returned to playerA's hand.
|
// Verify that one "Memnite" has been returned to playerA's hand.
|
||||||
assertHandCount(playerA, "Memnite", 1);
|
assertHandCount(playerA, "Memnite", 1);
|
||||||
// Verify that "Bottomless Pool // Locker Room" is on playerA's battlefield.
|
// Verify that bottomlessPoolLockerRoom is on playerA's battlefield.
|
||||||
assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1);
|
assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1);
|
||||||
// Verify that "Bottomless Pool // Locker Room" is an Enchantment.
|
// Verify that bottomlessPoolLockerRoom is an Enchantment.
|
||||||
assertType("Bottomless Pool // Locker Room", CardType.ENCHANTMENT, true);
|
assertType(bottomlessPoolLockerRoom, CardType.ENCHANTMENT, true);
|
||||||
// Verify that "Bottomless Pool // Locker Room" has the Room subtype.
|
// Verify that bottomlessPoolLockerRoom has the Room subtype.
|
||||||
assertSubtype("Bottomless Pool // Locker Room", SubType.ROOM);
|
assertSubtype(bottomlessPoolLockerRoom, SubType.ROOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -140,7 +312,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// creature to its owner’s hand.
|
// creature to its owner’s hand.
|
||||||
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
||||||
// damage to a player, draw a card.
|
// damage to a player, draw a card.
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.HAND, playerA, "Felidar Guardian");
|
addCard(Zone.HAND, playerA, "Felidar Guardian");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 4);
|
||||||
|
|
@ -148,7 +320,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// creatures owned by player A
|
// creatures owned by player A
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
// resolve spell cast
|
// resolve spell cast
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
// unlock and trigger bounce on Memnite
|
// unlock and trigger bounce on Memnite
|
||||||
|
|
@ -160,7 +332,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
// etb and flicker on Bottomless Pool
|
// etb and flicker on Bottomless Pool
|
||||||
setChoice(playerA, "Yes");
|
setChoice(playerA, "Yes");
|
||||||
addTarget(playerA, "Bottomless Pool");
|
addTarget(playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
|
||||||
|
|
@ -187,7 +359,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// creature to its owner’s hand.
|
// creature to its owner’s hand.
|
||||||
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
||||||
// damage to a player, draw a card.
|
// damage to a player, draw a card.
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.HAND, playerA, "Felidar Guardian");
|
addCard(Zone.HAND, playerA, "Felidar Guardian");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||||
|
|
@ -196,7 +368,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Black Knight", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Black Knight", 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
// resolve spell cast
|
// resolve spell cast
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
// unlock and trigger bounce on Memnite
|
// unlock and trigger bounce on Memnite
|
||||||
|
|
@ -208,7 +380,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
// etb and flicker on Bottomless Pool
|
// etb and flicker on Bottomless Pool
|
||||||
setChoice(playerA, "Yes");
|
setChoice(playerA, "Yes");
|
||||||
addTarget(playerA, "Bottomless Pool");
|
addTarget(playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
// can unlock again
|
// can unlock again
|
||||||
checkPlayableAbility("playerA can unlock Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA,
|
checkPlayableAbility("playerA can unlock Bottomless Pool", 1, PhaseStep.PRECOMBAT_MAIN, playerA,
|
||||||
|
|
@ -228,7 +400,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// Verify that one "Black Knight" has been returned to playerA's hand.
|
// Verify that one "Black Knight" has been returned to playerA's hand.
|
||||||
assertHandCount(playerA, "Black Knight", 1);
|
assertHandCount(playerA, "Black Knight", 1);
|
||||||
// Verify that "Bottomless Pool" is on playerA's battlefield.
|
// Verify that "Bottomless Pool" is on playerA's battlefield.
|
||||||
assertPermanentCount(playerA, "Bottomless Pool", 1);
|
assertPermanentCount(playerA, bottomlessPool, 1);
|
||||||
// Verify that "Felidar Guardian" is on playerA's battlefield.
|
// Verify that "Felidar Guardian" is on playerA's battlefield.
|
||||||
assertPermanentCount(playerA, "Felidar Guardian", 1);
|
assertPermanentCount(playerA, "Felidar Guardian", 1);
|
||||||
}
|
}
|
||||||
|
|
@ -240,11 +412,11 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// creature to its owner’s hand.
|
// creature to its owner’s hand.
|
||||||
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
||||||
// damage to a player, draw a card.
|
// damage to a player, draw a card.
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Erratic Apparition", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Erratic Apparition", 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
// resolve spell cast
|
// resolve spell cast
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
setChoice(playerA, "When you unlock"); // x2 triggers
|
setChoice(playerA, "When you unlock"); // x2 triggers
|
||||||
|
|
@ -262,8 +434,8 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
// Assertions:
|
// Assertions:
|
||||||
// Verify that "Bottomless Pool // Locker Room" is on playerA's battlefield.
|
// Verify that bottomlessPoolLockerRoom is on playerA's battlefield.
|
||||||
assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1);
|
assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1);
|
||||||
// Verify that "Erratic Apparition" is on playerA's battlefield.
|
// Verify that "Erratic Apparition" is on playerA's battlefield.
|
||||||
assertPermanentCount(playerA, "Erratic Apparition", 1);
|
assertPermanentCount(playerA, "Erratic Apparition", 1);
|
||||||
// Verify that "Erratic Apparition" has been pumped twice (etb + fully unlock)
|
// Verify that "Erratic Apparition" has been pumped twice (etb + fully unlock)
|
||||||
|
|
@ -277,17 +449,17 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// creature to its owner’s hand.
|
// creature to its owner’s hand.
|
||||||
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
||||||
// damage to a player, draw a card.
|
// damage to a player, draw a card.
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.HAND, playerA, "See Double");
|
addCard(Zone.HAND, playerA, "See Double");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 5);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Ornithopter", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Ornithopter", 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
// Copy spell on the stack
|
// Copy spell on the stack
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "See Double");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "See Double");
|
||||||
setModeChoice(playerA, "1");
|
setModeChoice(playerA, "1");
|
||||||
addTarget(playerA, "Bottomless Pool");
|
addTarget(playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 3);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN, 3);
|
||||||
addTarget(playerA, "Memnite");
|
addTarget(playerA, "Memnite");
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
@ -303,7 +475,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// Verify that one "Ornithopter" has been returned to playerA's hand.
|
// Verify that one "Ornithopter" has been returned to playerA's hand.
|
||||||
assertHandCount(playerA, "Ornithopter", 1);
|
assertHandCount(playerA, "Ornithopter", 1);
|
||||||
// Verify that 2 "Bottomless Pool" are on playerA's battlefield.
|
// Verify that 2 "Bottomless Pool" are on playerA's battlefield.
|
||||||
assertPermanentCount(playerA, "Bottomless Pool", 2);
|
assertPermanentCount(playerA, bottomlessPool, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -313,13 +485,13 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// creature to its owner's hand.
|
// creature to its owner's hand.
|
||||||
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
||||||
// damage to a player, draw a card.
|
// damage to a player, draw a card.
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.HAND, playerA, "Clever Impersonator");
|
addCard(Zone.HAND, playerA, "Clever Impersonator");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Ornithopter", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Ornithopter", 1);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
addTarget(playerA, "Memnite");
|
addTarget(playerA, "Memnite");
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
@ -327,7 +499,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Clever Impersonator");
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
setChoice(playerA, "Yes");
|
setChoice(playerA, "Yes");
|
||||||
setChoice(playerA, "Bottomless Pool");
|
setChoice(playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA,
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA,
|
||||||
|
|
@ -347,7 +519,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
assertHandCount(playerA, "Ornithopter", 1);
|
assertHandCount(playerA, "Ornithopter", 1);
|
||||||
// Verify that the original "Bottomless Pool" is on playerA's battlefield, and a
|
// Verify that the original "Bottomless Pool" is on playerA's battlefield, and a
|
||||||
// clone.
|
// clone.
|
||||||
assertPermanentCount(playerA, "Bottomless Pool", 2);
|
assertPermanentCount(playerA, bottomlessPool, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -366,11 +538,11 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// {U}{U}, Sacrifice this creature: Counter target spell with the same name as a
|
// {U}{U}, Sacrifice this creature: Counter target spell with the same name as a
|
||||||
// card exiled with this creature.
|
// card exiled with this creature.
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.HAND, playerA, "Twiddle");
|
addCard(Zone.HAND, playerA, "Twiddle");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mindreaver", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Mindreaver", 1);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 6);
|
||||||
addCard(Zone.LIBRARY, playerA, "Bottomless Pool // Locker Room", 1);
|
addCard(Zone.LIBRARY, playerA, bottomlessPoolLockerRoom, 1);
|
||||||
addCard(Zone.LIBRARY, playerA, "Plains", 2);
|
addCard(Zone.LIBRARY, playerA, "Plains", 2);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Twiddle");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Twiddle");
|
||||||
|
|
@ -384,10 +556,10 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
addTarget(playerA, playerA);
|
addTarget(playerA, playerA);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA,
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA,
|
||||||
"{U}{U}, Sacrifice {this}:");
|
"{U}{U}, Sacrifice {this}:");
|
||||||
addTarget(playerA, "Bottomless Pool");
|
addTarget(playerA, bottomlessPool);
|
||||||
|
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
@ -424,7 +596,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// Target creature and all other creatures with the same name as that creature
|
// Target creature and all other creatures with the same name as that creature
|
||||||
// get -3/-3 until end of turn.
|
// get -3/-3 until end of turn.
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room", 4);
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom, 4);
|
||||||
addCard(Zone.HAND, playerA, "Cackling Counterpart");
|
addCard(Zone.HAND, playerA, "Cackling Counterpart");
|
||||||
addCard(Zone.HAND, playerA, "Bile Blight");
|
addCard(Zone.HAND, playerA, "Bile Blight");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17);
|
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17);
|
||||||
|
|
@ -432,17 +604,17 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Opalescence");
|
addCard(Zone.BATTLEFIELD, playerA, "Opalescence");
|
||||||
|
|
||||||
// Cast Bottomless Pool (unlocked left half)
|
// Cast Bottomless Pool (unlocked left half)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Locker Room (unlocked right half)
|
// Cast Locker Room (unlocked right half)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Locker Room");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Bottomless Pool then unlock Locker Room (both halves unlocked)
|
// Cast Bottomless Pool then unlock Locker Room (both halves unlocked)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
@ -451,7 +623,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
// Create a fully locked room using Cackling Counterpart
|
// Create a fully locked room using Cackling Counterpart
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart");
|
||||||
addTarget(playerA, "Bottomless Pool // Locker Room");
|
addTarget(playerA, bottomlessPoolLockerRoom);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Bile Blight targeting the fully locked room
|
// Cast Bile Blight targeting the fully locked room
|
||||||
|
|
@ -468,21 +640,21 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// then -2/-2 after Bile Blight (dies)
|
// then -2/-2 after Bile Blight (dies)
|
||||||
assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 0);
|
assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 0);
|
||||||
// Token, so nothing should be in grave
|
// Token, so nothing should be in grave
|
||||||
assertGraveyardCount(playerA, "Bottomless Pool // Locker Room", 0);
|
assertGraveyardCount(playerA, bottomlessPoolLockerRoom, 0);
|
||||||
|
|
||||||
// Other rooms should NOT be affected by Bile Blight since they have different
|
// Other rooms should NOT be affected by Bile Blight since they have different
|
||||||
// names
|
// names
|
||||||
// Bottomless Pool: 1/1 base + 1/1 from anthem = 2/2
|
// Bottomless Pool: 1/1 base + 1/1 from anthem = 2/2
|
||||||
assertPowerToughness(playerA, "Bottomless Pool", 2, 2);
|
assertPowerToughness(playerA, bottomlessPool, 2, 2);
|
||||||
// Locker Room: 5/5 base + 1/1 from anthem = 6/6
|
// Locker Room: 5/5 base + 1/1 from anthem = 6/6
|
||||||
assertPowerToughness(playerA, "Locker Room", 6, 6);
|
assertPowerToughness(playerA, lockerRoom, 6, 6);
|
||||||
// Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem = 7/7
|
// Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem = 7/7
|
||||||
assertPowerToughness(playerA, "Bottomless Pool // Locker Room", 7, 7);
|
assertPowerToughness(playerA, bottomlessPoolLockerRoom, 7, 7);
|
||||||
|
|
||||||
// Verify remaining rooms are still on battlefield
|
// Verify remaining rooms are still on battlefield
|
||||||
assertPermanentCount(playerA, "Bottomless Pool", 1);
|
assertPermanentCount(playerA, bottomlessPool, 1);
|
||||||
assertPermanentCount(playerA, "Locker Room", 1);
|
assertPermanentCount(playerA, lockerRoom, 1);
|
||||||
assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1);
|
assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
@ -515,7 +687,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// Target creature and all other creatures with the same name as that creature
|
// Target creature and all other creatures with the same name as that creature
|
||||||
// get -3/-3 until end of turn.
|
// get -3/-3 until end of turn.
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room", 4);
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom, 4);
|
||||||
addCard(Zone.HAND, playerA, "Cackling Counterpart");
|
addCard(Zone.HAND, playerA, "Cackling Counterpart");
|
||||||
addCard(Zone.HAND, playerA, "Bile Blight");
|
addCard(Zone.HAND, playerA, "Bile Blight");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17);
|
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17);
|
||||||
|
|
@ -523,17 +695,17 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Opalescence");
|
addCard(Zone.BATTLEFIELD, playerA, "Opalescence");
|
||||||
|
|
||||||
// Cast Bottomless Pool (unlocked left half)
|
// Cast Bottomless Pool (unlocked left half)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Locker Room (unlocked right half)
|
// Cast Locker Room (unlocked right half)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Locker Room");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Bottomless Pool then unlock Locker Room (both halves unlocked)
|
// Cast Bottomless Pool then unlock Locker Room (both halves unlocked)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
@ -542,12 +714,12 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
// Create a fully locked room using Cackling Counterpart
|
// Create a fully locked room using Cackling Counterpart
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart");
|
||||||
addTarget(playerA, "Bottomless Pool // Locker Room");
|
addTarget(playerA, bottomlessPoolLockerRoom);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Bile Blight targeting the half locked room
|
// Cast Bile Blight targeting the half locked room
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bile Blight");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bile Blight");
|
||||||
addTarget(playerA, "Locker Room");
|
addTarget(playerA, lockerRoom);
|
||||||
|
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
@ -559,21 +731,21 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// since they share the "Locker Room" name component
|
// since they share the "Locker Room" name component
|
||||||
|
|
||||||
// Locker Room: 5/5 base + 1/1 from anthem - 3/3 from Bile Blight = 3/3
|
// Locker Room: 5/5 base + 1/1 from anthem - 3/3 from Bile Blight = 3/3
|
||||||
assertPowerToughness(playerA, "Locker Room", 3, 3);
|
assertPowerToughness(playerA, lockerRoom, 3, 3);
|
||||||
// Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem - 3/3 from Bile
|
// Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem - 3/3 from Bile
|
||||||
// Blight = 4/4
|
// Blight = 4/4
|
||||||
assertPowerToughness(playerA, "Bottomless Pool // Locker Room", 4, 4);
|
assertPowerToughness(playerA, bottomlessPoolLockerRoom, 4, 4);
|
||||||
|
|
||||||
// Other rooms should NOT be affected
|
// Other rooms should NOT be affected
|
||||||
// Bottomless Pool: 1/1 base + 1/1 from anthem = 2/2 (unaffected)
|
// Bottomless Pool: 1/1 base + 1/1 from anthem = 2/2 (unaffected)
|
||||||
assertPowerToughness(playerA, "Bottomless Pool", 2, 2);
|
assertPowerToughness(playerA, bottomlessPool, 2, 2);
|
||||||
// Fully locked room: 0/0 base + 1/1 from anthem = 1/1 (unaffected)
|
// Fully locked room: 0/0 base + 1/1 from anthem = 1/1 (unaffected)
|
||||||
assertPowerToughness(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1, 1);
|
assertPowerToughness(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1, 1);
|
||||||
|
|
||||||
// Verify all rooms are still on battlefield
|
// Verify all rooms are still on battlefield
|
||||||
assertPermanentCount(playerA, "Bottomless Pool", 1);
|
assertPermanentCount(playerA, bottomlessPool, 1);
|
||||||
assertPermanentCount(playerA, "Locker Room", 1);
|
assertPermanentCount(playerA, lockerRoom, 1);
|
||||||
assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1);
|
assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1);
|
||||||
assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1);
|
assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -607,7 +779,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// Target creature and all other creatures with the same name as that creature
|
// Target creature and all other creatures with the same name as that creature
|
||||||
// get -3/-3 until end of turn.
|
// get -3/-3 until end of turn.
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room", 4);
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom, 4);
|
||||||
addCard(Zone.HAND, playerA, "Cackling Counterpart");
|
addCard(Zone.HAND, playerA, "Cackling Counterpart");
|
||||||
addCard(Zone.HAND, playerA, "Bile Blight");
|
addCard(Zone.HAND, playerA, "Bile Blight");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17);
|
addCard(Zone.BATTLEFIELD, playerA, "Underground Sea", 17);
|
||||||
|
|
@ -615,17 +787,17 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Opalescence");
|
addCard(Zone.BATTLEFIELD, playerA, "Opalescence");
|
||||||
|
|
||||||
// Cast Bottomless Pool (unlocked left half)
|
// Cast Bottomless Pool (unlocked left half)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Locker Room (unlocked right half)
|
// Cast Locker Room (unlocked right half)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Locker Room");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, lockerRoom);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Bottomless Pool then unlock Locker Room (both halves unlocked)
|
// Cast Bottomless Pool then unlock Locker Room (both halves unlocked)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
@ -634,12 +806,12 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
// Create a fully locked room using Cackling Counterpart
|
// Create a fully locked room using Cackling Counterpart
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Cackling Counterpart");
|
||||||
addTarget(playerA, "Bottomless Pool // Locker Room");
|
addTarget(playerA, bottomlessPoolLockerRoom);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Bile Blight targeting the fully locked room
|
// Cast Bile Blight targeting the fully locked room
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bile Blight");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bile Blight");
|
||||||
addTarget(playerA, "Bottomless Pool // Locker Room");
|
addTarget(playerA, bottomlessPoolLockerRoom);
|
||||||
|
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
@ -647,27 +819,27 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
// Assertions:
|
// Assertions:
|
||||||
// All rooms except the fully locked room should be affected by Bile Blight
|
// All rooms except the fully locked room should be affected by Bile Blight
|
||||||
// since they all share name components with "Bottomless Pool // Locker Room"
|
// since they all share name components with bottomlessPoolLockerRoom
|
||||||
|
|
||||||
// Bottomless Pool: 1/1 base + 1/1 from anthem - 3/3 from Bile Blight = -1/-1
|
// Bottomless Pool: 1/1 base + 1/1 from anthem - 3/3 from Bile Blight = -1/-1
|
||||||
// (dies)
|
// (dies)
|
||||||
assertPermanentCount(playerA, "Bottomless Pool", 0);
|
assertPermanentCount(playerA, bottomlessPool, 0);
|
||||||
assertGraveyardCount(playerA, "Bottomless Pool // Locker Room", 1);
|
assertGraveyardCount(playerA, bottomlessPoolLockerRoom, 1);
|
||||||
|
|
||||||
// Locker Room: 5/5 base + 1/1 from anthem - 3/3 from Bile Blight = 3/3
|
// Locker Room: 5/5 base + 1/1 from anthem - 3/3 from Bile Blight = 3/3
|
||||||
assertPowerToughness(playerA, "Locker Room", 3, 3);
|
assertPowerToughness(playerA, lockerRoom, 3, 3);
|
||||||
|
|
||||||
// Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem - 3/3 from Bile
|
// Bottomless Pool // Locker Room: 6/6 base + 1/1 from anthem - 3/3 from Bile
|
||||||
// Blight = 4/4
|
// Blight = 4/4
|
||||||
assertPowerToughness(playerA, "Bottomless Pool // Locker Room", 4, 4);
|
assertPowerToughness(playerA, bottomlessPoolLockerRoom, 4, 4);
|
||||||
|
|
||||||
// Fully locked room should NOT be affected (different name)
|
// Fully locked room should NOT be affected (different name)
|
||||||
// Fully locked room: 0/0 base + 1/1 from anthem = 1/1 (unaffected)
|
// Fully locked room: 0/0 base + 1/1 from anthem = 1/1 (unaffected)
|
||||||
assertPowerToughness(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1, 1);
|
assertPowerToughness(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1, 1);
|
||||||
|
|
||||||
// Verify remaining rooms are still on battlefield
|
// Verify remaining rooms are still on battlefield
|
||||||
assertPermanentCount(playerA, "Locker Room", 1);
|
assertPermanentCount(playerA, lockerRoom, 1);
|
||||||
assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1);
|
assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1);
|
||||||
assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1);
|
assertPermanentCount(playerA, EmptyNames.FULLY_LOCKED_ROOM.getTestCommand(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -678,7 +850,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// creature to its owner's hand.
|
// creature to its owner's hand.
|
||||||
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
// Locker Room {4}{U} Whenever one or more creatures you control deal combat
|
||||||
// damage to a player, draw a card.
|
// damage to a player, draw a card.
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.HAND, playerA, "Counterspell");
|
addCard(Zone.HAND, playerA, "Counterspell");
|
||||||
addCard(Zone.HAND, playerA, "Campus Renovation");
|
addCard(Zone.HAND, playerA, "Campus Renovation");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
|
||||||
|
|
@ -689,16 +861,16 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 1);
|
addCard(Zone.BATTLEFIELD, playerB, "Grizzly Bears", 1);
|
||||||
|
|
||||||
// Cast Bottomless Pool
|
// Cast Bottomless Pool
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
|
|
||||||
// Counter it while on stack
|
// Counter it while on stack
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Counterspell");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Counterspell");
|
||||||
addTarget(playerA, "Bottomless Pool");
|
addTarget(playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Use Campus Renovation to return it from graveyard
|
// Use Campus Renovation to return it from graveyard
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Campus Renovation");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Campus Renovation");
|
||||||
addTarget(playerA, "Bottomless Pool // Locker Room");
|
addTarget(playerA, bottomlessPoolLockerRoom);
|
||||||
|
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
@ -749,26 +921,26 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// As Pithing Needle enters, choose a card name.
|
// As Pithing Needle enters, choose a card name.
|
||||||
// Activated abilities of sources with the chosen name can't be activated.
|
// Activated abilities of sources with the chosen name can't be activated.
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.HAND, playerA, "Pithing Needle");
|
addCard(Zone.HAND, playerA, "Pithing Needle");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Opalescence");
|
addCard(Zone.BATTLEFIELD, playerA, "Opalescence");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Diviner's Wand");
|
addCard(Zone.BATTLEFIELD, playerA, "Diviner's Wand");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 20);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 20);
|
||||||
|
|
||||||
// Cast Bottomless Pool (unlocked left half only)
|
// Cast Bottomless Pool (unlocked left half only)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Equip Diviner's Wand
|
// Equip Diviner's Wand
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {3}");
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Equip {3}");
|
||||||
addTarget(playerA, "Bottomless Pool");
|
addTarget(playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Pithing Needle naming the locked side
|
// Cast Pithing Needle naming the locked side
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pithing Needle");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Pithing Needle");
|
||||||
setChoice(playerA, "Locker Room");
|
setChoice(playerA, lockerRoom);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Validate that the room can activate the gained ability
|
// Validate that the room can activate the gained ability
|
||||||
|
|
@ -789,7 +961,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
// Verify the room is now fully unlocked
|
// Verify the room is now fully unlocked
|
||||||
assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1);
|
assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test converting one permanent into one room, then another (the room halves
|
// Test converting one permanent into one room, then another (the room halves
|
||||||
|
|
@ -813,14 +985,14 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// or
|
// or
|
||||||
// land until end of turn.
|
// land until end of turn.
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.HAND, playerA, "Surgical Suite // Hospital Room");
|
addCard(Zone.HAND, playerA, "Surgical Suite // Hospital Room");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Mirage Mirror");
|
addCard(Zone.BATTLEFIELD, playerA, "Mirage Mirror");
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 20);
|
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 20);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
|
addCard(Zone.BATTLEFIELD, playerA, "Memnite", 1);
|
||||||
|
|
||||||
// Cast Bottomless Pool (unlocked left half only)
|
// Cast Bottomless Pool (unlocked left half only)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
@ -832,7 +1004,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}: {this} becomes a copy");
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{2}: {this} becomes a copy");
|
||||||
addTarget(playerA, "Bottomless Pool // Locker Room");
|
addTarget(playerA, bottomlessPoolLockerRoom);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half.");
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half.");
|
||||||
|
|
||||||
|
|
@ -848,7 +1020,7 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
// Verify unlocked Bottomless pool
|
// Verify unlocked Bottomless pool
|
||||||
assertPermanentCount(playerA, "Bottomless Pool // Locker Room", 1);
|
assertPermanentCount(playerA, bottomlessPoolLockerRoom, 1);
|
||||||
// Verify unlocked Surgical Suite
|
// Verify unlocked Surgical Suite
|
||||||
assertPermanentCount(playerA, "Surgical Suite", 1);
|
assertPermanentCount(playerA, "Surgical Suite", 1);
|
||||||
// Verify mirage mirror is Hospital Room
|
// Verify mirage mirror is Hospital Room
|
||||||
|
|
@ -873,32 +1045,33 @@ public class RoomCardTest extends CardTestPlayerBase {
|
||||||
// other types,
|
// other types,
|
||||||
// and it has "{2}{U}{U}: Return Sakashima the Impostor to its owner's hand at
|
// and it has "{2}{U}{U}: Return Sakashima the Impostor to its owner's hand at
|
||||||
// the beginning of the next end step."
|
// the beginning of the next end step."
|
||||||
|
String sakashimaTheImpostor = "Sakashima the Impostor";
|
||||||
|
|
||||||
addCard(Zone.HAND, playerA, "Bottomless Pool // Locker Room");
|
addCard(Zone.HAND, playerA, bottomlessPoolLockerRoom);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Island", 10);
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 10);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Opalescence");
|
||||||
|
addCard(Zone.HAND, playerA, sakashimaTheImpostor);
|
||||||
|
|
||||||
addCard(Zone.HAND, playerB, "Sakashima the Impostor");
|
|
||||||
addCard(Zone.BATTLEFIELD, playerB, "Island", 10);
|
|
||||||
|
|
||||||
// Cast Bottomless Pool (unlocked left half only)
|
// Cast Bottomless Pool (unlocked left half only)
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Bottomless Pool");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, bottomlessPool);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
addTarget(playerA, TestPlayer.TARGET_SKIP);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
// Cast Sakashima copying the room
|
// Cast Sakashima copying the room
|
||||||
castSpell(2, PhaseStep.PRECOMBAT_MAIN, playerB, "Sakashima the Impostor");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, sakashimaTheImpostor);
|
||||||
setChoice(playerB, "Yes"); // Choose to copy
|
setChoice(playerA, "Yes"); // Choose to copy
|
||||||
waitStackResolved(2, PhaseStep.PRECOMBAT_MAIN);
|
setChoice(playerA, bottomlessPool);
|
||||||
|
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{4}{U}: Unlock the right half.");
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
|
||||||
|
|
||||||
setStopAt(2, PhaseStep.END_TURN);
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
// Verify Sakashima entered and is copying the room
|
// Verify Sakashima dies to state-based actions
|
||||||
assertPermanentCount(playerB, "Sakashima the Impostor", 1);
|
// copies room and because sakashima has no unlocked designations, its mana value is 0
|
||||||
|
// opalescence makes it a 0/0 and it dies
|
||||||
|
assertPermanentCount(playerA, sakashimaTheImpostor, 0);
|
||||||
|
assertGraveyardCount(playerA, sakashimaTheImpostor, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -36,6 +36,8 @@ public class EtherealValkyrieTest extends CardTestPlayerBase {
|
||||||
private static final String alloyMyr = "Alloy Myr";
|
private static final String alloyMyr = "Alloy Myr";
|
||||||
// Land
|
// Land
|
||||||
private static final String exoticOrchard = "Exotic Orchard";
|
private static final String exoticOrchard = "Exotic Orchard";
|
||||||
|
// {U} Creature-Planeswalker TDFC
|
||||||
|
private static final String tamiyo = "Tamiyo, Inquisitive Student";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that a regular card is playable.
|
* Test that a regular card is playable.
|
||||||
|
|
@ -202,4 +204,27 @@ public class EtherealValkyrieTest extends CardTestPlayerBase {
|
||||||
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
|
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
|
||||||
execute();
|
execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test a TDFC, which should be castable.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testTransformingDoubleFacedCard() {
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Plains", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 1);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 4);
|
||||||
|
addCard(Zone.HAND, playerA, etherealValkyrie);
|
||||||
|
addCard(Zone.HAND, playerA, tamiyo);
|
||||||
|
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, etherealValkyrie);
|
||||||
|
addTarget(playerA, tamiyo);
|
||||||
|
|
||||||
|
activateAbility(3, PhaseStep.PRECOMBAT_MAIN, playerA, "Foretell {U}");
|
||||||
|
|
||||||
|
setStopAt(3, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
execute();
|
||||||
|
assertPermanentCount(playerA, tamiyo, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package org.mage.test.cards.single.spm;
|
||||||
import mage.constants.PhaseStep;
|
import mage.constants.PhaseStep;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
|
@ -33,7 +32,6 @@ public class GwenStacyTest extends CardTestPlayerBase {
|
||||||
private static final String ghostSpider = "Ghost-Spider";
|
private static final String ghostSpider = "Ghost-Spider";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("Enable after transform mdfc rework")
|
|
||||||
public void testGhostSpider() {
|
public void testGhostSpider() {
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import mage.constants.PhaseStep;
|
||||||
import mage.constants.SubType;
|
import mage.constants.SubType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.filter.common.FilterCreaturePermanent;
|
import mage.filter.common.FilterCreaturePermanent;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mage.test.serverside.base.CardTestPlayerBase;
|
import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
|
|
||||||
|
|
@ -18,19 +17,20 @@ import org.mage.test.serverside.base.CardTestPlayerBase;
|
||||||
public class PeterParkerTest extends CardTestPlayerBase {
|
public class PeterParkerTest extends CardTestPlayerBase {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Peter Parker
|
Peter Parker
|
||||||
{1}{W}
|
{1}{W}
|
||||||
Legendary Creature - Human Scientist Hero
|
Legendary Creature - Human Scientist Hero
|
||||||
When Peter Parker enters, create a 2/1 green Spider creature token with reach.
|
When Peter Parker enters, create a 2/1 green Spider creature token with reach.
|
||||||
{1}{G}{W}{U}: Transform Peter Parker. Activate only as a sorcery.
|
{1}{G}{W}{U}: Transform Peter Parker. Activate only as a sorcery.
|
||||||
Amazing Spider-Man
|
Amazing Spider-Man
|
||||||
{1}{G}{W}{U}
|
{1}{G}{W}{U}
|
||||||
Legendary Creature - Spider Human Hero
|
Legendary Creature - Spider Human Hero
|
||||||
Vigilance, reach
|
Vigilance, reach
|
||||||
Each legendary spell you cast that's one or more colors has web-slinging {G}{W}{U}.
|
Each legendary spell you cast that's one or more colors has web-slinging {G}{W}{U}.
|
||||||
4/4
|
4/4
|
||||||
*/
|
*/
|
||||||
private static final String peterParker = "Peter Parker";
|
private static final String peterParker = "Peter Parker";
|
||||||
|
public static final String amazingSpiderMan = "Amazing Spider-Man";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -73,8 +73,16 @@ public class PeterParkerTest extends CardTestPlayerBase {
|
||||||
*/
|
*/
|
||||||
private static final String balduvianBears = "Balduvian Bears";
|
private static final String balduvianBears = "Balduvian Bears";
|
||||||
|
|
||||||
|
/*
|
||||||
|
Unsummon
|
||||||
|
{U}
|
||||||
|
Instant
|
||||||
|
Return target creature to its owner's hand.
|
||||||
|
*/
|
||||||
|
private static final String unsummon = "Unsummon";
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Ignore("Enable after MDFC rework")
|
|
||||||
public void testAmazingSpiderMan() {
|
public void testAmazingSpiderMan() {
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
|
@ -91,7 +99,7 @@ public class PeterParkerTest extends CardTestPlayerBase {
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8);
|
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8);
|
||||||
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8);
|
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8);
|
||||||
|
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Amazing Spider-Man", true);
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, amazingSpiderMan, true);
|
||||||
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
|
@ -112,4 +120,131 @@ public class PeterParkerTest extends CardTestPlayerBase {
|
||||||
execute();
|
execute();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransform() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
addCustomCardWithAbility("tap all creatures", playerA, new SimpleActivatedAbility(
|
||||||
|
new TapAllEffect(new FilterCreaturePermanent(SubType.BEAR, "bears")),
|
||||||
|
new ManaCostsImpl<>("")
|
||||||
|
));
|
||||||
|
|
||||||
|
addCard(Zone.HAND, playerA, peterParker);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, balduvianBears);
|
||||||
|
addCard(Zone.HAND, playerA, adelbertSteiner);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, peterParker, true);
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G}{W}{U}: Transform");
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, adelbertSteiner + " with Web-slinging");
|
||||||
|
setChoice(playerA, balduvianBears); // return to hand
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, amazingSpiderMan, 1);
|
||||||
|
assertPermanentCount(playerA, adelbertSteiner, 1);
|
||||||
|
assertPermanentCount(playerA, balduvianBears, 0);
|
||||||
|
assertHandCount(playerA, balduvianBears, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test that MDFC doesn't have static ability from one side after transforming
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testTransformLosesWebSlinging() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
addCustomCardWithAbility("tap all creatures", playerA, new SimpleActivatedAbility(
|
||||||
|
new TapAllEffect(new FilterCreaturePermanent(SubType.BEAR, "bears")),
|
||||||
|
new ManaCostsImpl<>("")
|
||||||
|
));
|
||||||
|
addCustomEffect_TargetTransform(playerA);
|
||||||
|
|
||||||
|
addCard(Zone.HAND, playerA, peterParker);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, balduvianBears);
|
||||||
|
addCard(Zone.HAND, playerA, adelbertSteiner);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, peterParker, true);
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{1}{G}{W}{U}: Transform"); // transform to Spider-Man
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
checkPlayableAbility("card in hand has web-slinging", 1, PhaseStep.PRECOMBAT_MAIN,
|
||||||
|
playerA, "Cast " + adelbertSteiner + " with Web-slinging", true);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target transform", amazingSpiderMan);
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
checkPlayableAbility("card in hand does not have web-slinging", 1, PhaseStep.PRECOMBAT_MAIN,
|
||||||
|
playerA, "Cast " + adelbertSteiner + " with Web-slinging", false);
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, amazingSpiderMan, 0);
|
||||||
|
assertPermanentCount(playerA, peterParker, 1);
|
||||||
|
assertHandCount(playerA, adelbertSteiner, 1);
|
||||||
|
assertPermanentCount(playerA, balduvianBears, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* test showing if a transformed MDFC gets re-cast, it won't trigger effects from the other face
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testTransformCastSecondSideDoesntTriggerFront() {
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
addCustomCardWithAbility("tap all creatures", playerA, new SimpleActivatedAbility(
|
||||||
|
new TapAllEffect(new FilterCreaturePermanent(SubType.BEAR, "bears")),
|
||||||
|
new ManaCostsImpl<>("")
|
||||||
|
));
|
||||||
|
addCustomEffect_TargetTransform(playerA);
|
||||||
|
|
||||||
|
addCard(Zone.HAND, playerA, peterParker);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tropical Island", 8);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Tundra", 8);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, balduvianBears);
|
||||||
|
addCard(Zone.HAND, playerA, adelbertSteiner);
|
||||||
|
addCard(Zone.HAND, playerA, unsummon);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "tap all"); // tap bears, addCard command isn't working to set tapped
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, amazingSpiderMan, true);
|
||||||
|
|
||||||
|
checkPlayableAbility("card in hand has web-slinging", 1, PhaseStep.PRECOMBAT_MAIN,
|
||||||
|
playerA, "Cast " + adelbertSteiner + " with Web-slinging", true);
|
||||||
|
|
||||||
|
activateAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "target transform", amazingSpiderMan);
|
||||||
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
|
|
||||||
|
checkPlayableAbility("card in hand does not have web-slinging", 1, PhaseStep.PRECOMBAT_MAIN,
|
||||||
|
playerA, "Cast " + adelbertSteiner + " with Web-slinging", false);
|
||||||
|
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, unsummon, peterParker, true);
|
||||||
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, amazingSpiderMan);
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
execute();
|
||||||
|
|
||||||
|
assertPermanentCount(playerA, amazingSpiderMan, 1);
|
||||||
|
assertPermanentCount(playerA, peterParker, 0);
|
||||||
|
assertHandCount(playerA, adelbertSteiner, 1);
|
||||||
|
assertPermanentCount(playerA, balduvianBears, 1);
|
||||||
|
assertPermanentCount(playerA, "Spider Token", 0);
|
||||||
|
currentGame.getState().getTriggers().forEach(
|
||||||
|
(key, value) -> logger.info(key + " - " + value)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -213,14 +213,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase {
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Tangled Vale");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Tangled Vale");
|
||||||
|
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Vale", 2, 1, 1, 2));
|
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Vale", 2, 2, 2, 2));
|
||||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Vale");
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Vale");
|
||||||
|
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 2, 2, 4));
|
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 4, 4, 4));
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
|
@ -244,14 +242,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase {
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Riverglide Pathway");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Riverglide Pathway");
|
||||||
|
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("1: check zcc pre disfigure", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
runCode("1: check zcc pre disfigure", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Riverglide Pathway", 2, 1, 2, 1));
|
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Riverglide Pathway", 2, 2, 2, 2));
|
||||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Riverglide Pathway");
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Riverglide Pathway");
|
||||||
|
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("2: check zcc post disfigure", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
runCode("2: check zcc post disfigure", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 2, 4, 2));
|
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 4, 4, 4));
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
|
@ -275,14 +271,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase {
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Lavaglide Pathway");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Wind Zendikon", "Lavaglide Pathway");
|
||||||
|
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Lavaglide Pathway", 2, 1, 1, 2));
|
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Lavaglide Pathway", 2, 2, 2, 2));
|
||||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Lavaglide Pathway");
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Lavaglide Pathway");
|
||||||
|
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 2, 2, 4));
|
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Riverglide Pathway", 4, 4, 4));
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
|
@ -335,14 +329,12 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase {
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron");
|
||||||
|
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 2, 3, 2));
|
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 3, 3, 3));
|
||||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Florahedron");
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Florahedron");
|
||||||
|
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
runCode("2: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 3, 5, 3));
|
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 5, 5, 5));
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
|
@ -403,25 +395,25 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase {
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tangled Florahedron");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Tangled Florahedron");
|
||||||
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.PRECOMBAT_MAIN);
|
||||||
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron");
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron");
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
runCode("1: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 2, 3, 2));
|
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 3, 3, 3, 3));
|
||||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Florahedron", true);
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Disfigure", "Tangled Florahedron", true);
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("2: check zcc card", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
runCode("2: check zcc card", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 3, 5, 3));
|
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 5, 5, 5));
|
||||||
|
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Tangled Florahedron");
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Tangled Florahedron");
|
||||||
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron", true);
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Demonic Vigor", "Tangled Florahedron", true);
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("3: check zcc", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
runCode("3: check zcc", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 7, 4, 7, 4));
|
(String info, Player player, Game game) -> checkZCCMDFCPermanent(info, player, game, "Tangled Florahedron", 7, 7, 7, 7));
|
||||||
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
|
waitStackResolved(1, PhaseStep.POSTCOMBAT_MAIN);
|
||||||
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Disfigure", "Tangled Florahedron", true);
|
castSpell(1, PhaseStep.POSTCOMBAT_MAIN, playerA, "Disfigure", "Tangled Florahedron", true);
|
||||||
// TODO: investigate why MDFC zcc moves separatedly.
|
|
||||||
runCode("4: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
runCode("4: check zcc card", 1, PhaseStep.POSTCOMBAT_MAIN, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 5, 9, 5));
|
(String info, Player player, Game game) -> checkZCCMDFCCardInHand(info, player, game, "Tangled Florahedron", 9, 9, 9));
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
|
|
@ -458,20 +450,19 @@ public class ReturnToHandEffectsTest extends CardTestPlayerBase {
|
||||||
runCode("3: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
runCode("3: check zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCNormalPermanent(info, player, game, "Carrion Feeder", 5, 5));
|
(String info, Player player, Game game) -> checkZCCNormalPermanent(info, player, game, "Carrion Feeder", 5, 5));
|
||||||
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Coat with Venom", "Carrion Feeder", true);
|
castSpell(1, PhaseStep.BEGIN_COMBAT, playerA, "Coat with Venom", "Carrion Feeder", true);
|
||||||
runCode("4: check graveyard zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
runCode("4: check hand zcc", 1, PhaseStep.BEGIN_COMBAT, playerA,
|
||||||
(String info, Player player, Game game) -> checkZCCCardInGraveyard(info, player, game, "Carrion Feeder", 6));
|
(String info, Player player, Game game) -> checkZCCNormalCardInHand(info, player, game, "Carrion Feeder", 7));
|
||||||
|
|
||||||
setStrictChooseMode(true);
|
setStrictChooseMode(true);
|
||||||
setStopAt(1, PhaseStep.END_TURN);
|
setStopAt(1, PhaseStep.END_TURN);
|
||||||
execute();
|
execute();
|
||||||
// Vigor tries to return the Carrion Feeder card with zcc 4, so 6 doesn't return.
|
|
||||||
|
|
||||||
assertGraveyardCount(playerA, "Disfigure", 1);
|
assertGraveyardCount(playerA, "Disfigure", 1);
|
||||||
assertGraveyardCount(playerA, "Demonic Vigor", 1);
|
assertGraveyardCount(playerA, "Demonic Vigor", 1);
|
||||||
assertGraveyardCount(playerA, "Makeshift Mannequin", 1);
|
assertGraveyardCount(playerA, "Makeshift Mannequin", 1);
|
||||||
assertGraveyardCount(playerA, "Carrion Feeder", 1);
|
assertGraveyardCount(playerA, "Carrion Feeder", 0);
|
||||||
assertPermanentCount(playerA, "Carrion Feeder", 0);
|
assertPermanentCount(playerA, "Carrion Feeder", 0);
|
||||||
assertHandCount(playerA, "Carrion Feeder", 0);
|
assertHandCount(playerA, "Carrion Feeder", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,8 @@ import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.ContinuousEffect;
|
import mage.abilities.effects.ContinuousEffect;
|
||||||
import mage.abilities.effects.ContinuousEffectsList;
|
import mage.abilities.effects.ContinuousEffectsList;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.cards.DoubleFacedCard;
|
||||||
|
import mage.cards.DoubleFacedCardHalf;
|
||||||
import mage.cards.decks.Deck;
|
import mage.cards.decks.Deck;
|
||||||
import mage.cards.decks.DeckCardLists;
|
import mage.cards.decks.DeckCardLists;
|
||||||
import mage.cards.decks.importer.DeckImporter;
|
import mage.cards.decks.importer.DeckImporter;
|
||||||
|
|
@ -773,6 +775,12 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
||||||
if (gameZone == Zone.BATTLEFIELD) {
|
if (gameZone == Zone.BATTLEFIELD) {
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
Card newCard = cardInfo.createCard();
|
Card newCard = cardInfo.createCard();
|
||||||
|
if (newCard instanceof DoubleFacedCard) {
|
||||||
|
DoubleFacedCardHalf rightHalf = ((DoubleFacedCard) newCard).getRightHalfCard();
|
||||||
|
if (rightHalf.getName().equals(cardName) && rightHalf.isPermanent()) {
|
||||||
|
newCard = rightHalf;
|
||||||
|
}
|
||||||
|
}
|
||||||
getBattlefieldCards(player).add(new PutToBattlefieldInfo(
|
getBattlefieldCards(player).add(new PutToBattlefieldInfo(
|
||||||
newCard,
|
newCard,
|
||||||
tapped
|
tapped
|
||||||
|
|
@ -781,7 +789,8 @@ public abstract class CardTestPlayerAPIImpl extends MageTestPlayerBase implement
|
||||||
// TODO: is it bugged with double faced cards (wrong ref)?
|
// TODO: is it bugged with double faced cards (wrong ref)?
|
||||||
// add to all players
|
// add to all players
|
||||||
String aliasId = player.generateAliasName(aliasName, useAliasMultiNames, i + 1);
|
String aliasId = player.generateAliasName(aliasName, useAliasMultiNames, i + 1);
|
||||||
currentGame.getPlayers().values().forEach(pl -> ((TestPlayer) pl).addAlias(aliasId, newCard.getId()));
|
Card finalNewCard = newCard;
|
||||||
|
currentGame.getPlayers().values().forEach(pl -> ((TestPlayer) pl).addAlias(aliasId, finalNewCard.getId()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public class CardUtilTest extends CardTestPlayerBase {
|
||||||
// MDFC where both sides should be playable
|
// MDFC where both sides should be playable
|
||||||
private static final String birgi = "Birgi, God of Storytelling"; // {2}{R}, frontside of Harnfel
|
private static final String birgi = "Birgi, God of Storytelling"; // {2}{R}, frontside of Harnfel
|
||||||
private static final String harnfel = "Harnfel, Horn of Bounty"; // {4}{R}, backside of Birgi
|
private static final String harnfel = "Harnfel, Horn of Bounty"; // {4}{R}, backside of Birgi
|
||||||
|
private static final String tamiyo = "Tamiyo, Inquisitive Student"; // {U}, TDFC
|
||||||
/**
|
/**
|
||||||
* Test that it will for trigger for discarding a MDFC but will only let you cast the nonland side.
|
* Test that it will for trigger for discarding a MDFC but will only let you cast the nonland side.
|
||||||
*/
|
*/
|
||||||
|
|
@ -122,4 +122,29 @@ public class CardUtilTest extends CardTestPlayerBase {
|
||||||
Assert.assertEquals("12345", CardUtil.substring(str, 8, ending));
|
Assert.assertEquals("12345", CardUtil.substring(str, 8, ending));
|
||||||
Assert.assertEquals("12345", CardUtil.substring(str, 9, ending));
|
Assert.assertEquals("12345", CardUtil.substring(str, 9, ending));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test that it will for trigger for discarding a TDFC but will only let you cast the front side.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void cantPlayTDFCBackSide() {
|
||||||
|
addCard(Zone.HAND, playerA, changeOfFortune);
|
||||||
|
addCard(Zone.HAND, playerA, tamiyo);
|
||||||
|
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, oskar);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Mountain", 4);
|
||||||
|
addCard(Zone.BATTLEFIELD, playerA, "Island", 3);
|
||||||
|
|
||||||
|
skipInitShuffling();
|
||||||
|
setStrictChooseMode(true);
|
||||||
|
|
||||||
|
activateManaAbility(1, PhaseStep.PRECOMBAT_MAIN, playerA, "{T}: Add {R}", 4);
|
||||||
|
castSpell(1, PhaseStep.PRECOMBAT_MAIN, playerA, changeOfFortune);
|
||||||
|
setChoice(playerA, "Yes");
|
||||||
|
// only option is to cast front side, so auto chosen
|
||||||
|
|
||||||
|
setStopAt(1, PhaseStep.BEGIN_COMBAT);
|
||||||
|
execute();
|
||||||
|
assertPermanentCount(playerA, tamiyo, 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -650,6 +650,9 @@ public class VerifyCardDataTest {
|
||||||
CardInfo cardInfo = CardRepository.instance.findCardsByClass(info.getCardClass().getCanonicalName()).stream().findFirst().orElse(null);
|
CardInfo cardInfo = CardRepository.instance.findCardsByClass(info.getCardClass().getCanonicalName()).stream().findFirst().orElse(null);
|
||||||
Assert.assertNotNull(cardInfo);
|
Assert.assertNotNull(cardInfo);
|
||||||
|
|
||||||
|
if (cardInfo.isDoubleFacedCard()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
Card card = cardInfo.createCard();
|
Card card = cardInfo.createCard();
|
||||||
Card secondCard = card.getSecondCardFace();
|
Card secondCard = card.getSecondCardFace();
|
||||||
if (secondCard != null) {
|
if (secondCard != null) {
|
||||||
|
|
@ -1224,7 +1227,8 @@ public class VerifyCardDataTest {
|
||||||
cardInfo.getCardNumber(), cardInfo.getRarity(), cardInfo.getGraphicInfo()));
|
cardInfo.getCardNumber(), cardInfo.getRarity(), cardInfo.getGraphicInfo()));
|
||||||
Assert.assertNotNull(card);
|
Assert.assertNotNull(card);
|
||||||
|
|
||||||
if (card.getSecondCardFace() != null) {
|
//TODO: do we need this check after tdfc rework?
|
||||||
|
if (card.getSecondCardFace() != null && !(card instanceof DoubleFacedCard)) {
|
||||||
containsDoubleSideCards = true;
|
containsDoubleSideCards = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2288,10 +2292,10 @@ public class VerifyCardDataTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
// special check: Werewolves front ability should only be on front and vice versa
|
// special check: Werewolves front ability should only be on front and vice versa
|
||||||
if (card.getAbilities().containsClass(WerewolfFrontTriggeredAbility.class) && card.isNightCard()) {
|
if (card.getAbilities().containsClass(WerewolfFrontTriggeredAbility.class) && (card.isNightCard() || (card instanceof DoubleFacedCardHalf && ((DoubleFacedCardHalf) card).isBackSide()))) {
|
||||||
fail(card, "abilities", "card is a back face werewolf with a front face ability");
|
fail(card, "abilities", "card is a back face werewolf with a front face ability");
|
||||||
}
|
}
|
||||||
if (card.getAbilities().containsClass(WerewolfBackTriggeredAbility.class) && !card.isNightCard()) {
|
if (card.getAbilities().containsClass(WerewolfBackTriggeredAbility.class) && (!card.isNightCard() && (card instanceof DoubleFacedCardHalf && !((DoubleFacedCardHalf) card).isBackSide()))) {
|
||||||
fail(card, "abilities", "card is a front face werewolf with a back face ability");
|
fail(card, "abilities", "card is a front face werewolf with a back face ability");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2309,7 +2313,7 @@ public class VerifyCardDataTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
// special check: siege ability must be used in double faced cards only
|
// special check: siege ability must be used in double faced cards only
|
||||||
if (card.getAbilities().containsClass(SiegeAbility.class) && card.getSecondCardFace() == null) {
|
if (card.getAbilities().containsClass(SiegeAbility.class) && (card.getSecondCardFace() == null && (card instanceof DoubleFacedCardHalf && ((DoubleFacedCardHalf) card).getOtherSide() == null))) {
|
||||||
fail(card, "abilities", "miss second side settings in card with siege ability");
|
fail(card, "abilities", "miss second side settings in card with siege ability");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ public class EntersBattlefieldTriggeredAbility extends TriggeredAbilityImpl {
|
||||||
}
|
}
|
||||||
|
|
||||||
public EntersBattlefieldTriggeredAbility(Effect effect, boolean optional) {
|
public EntersBattlefieldTriggeredAbility(Effect effect, boolean optional) {
|
||||||
super(Zone.ALL, effect, optional); // Zone.All because a creature with trigger can be put into play and be sacrificed during the resolution of an effect (discard Obstinate Baloth with Smallpox)
|
super(Zone.BATTLEFIELD, effect, optional); // Zone.All doesn't appear to be necessary anymore (discard Obstinate Baloth with Smallpox still works)
|
||||||
this.withRuleTextReplacement(true); // default true to replace "{this}" with "it" or "this creature"
|
this.withRuleTextReplacement(true); // default true to replace "{this}" with "it" or "this creature"
|
||||||
|
|
||||||
// warning, it's impossible to add text auto-replacement for creatures here (When this creature enters),
|
// warning, it's impossible to add text auto-replacement for creatures here (When this creature enters),
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,9 @@ import mage.game.events.GameEvent;
|
||||||
import mage.game.events.ZoneChangeEvent;
|
import mage.game.events.ZoneChangeEvent;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author LevelX2
|
* @author LevelX2
|
||||||
|
|
@ -99,11 +102,10 @@ class PutIntoGraveFromAnywhereEffect extends ReplacementEffectImpl {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean applies(GameEvent event, Ability source, Game game) {
|
public boolean applies(GameEvent event, Ability source, Game game) {
|
||||||
|
UUID cardId = CardUtil.getMainCardId(game, source.getSourceId()); // for split cards
|
||||||
if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD
|
if (((ZoneChangeEvent) event).getToZone() == Zone.GRAVEYARD
|
||||||
&& event.getTargetId().equals(source.getSourceId())) {
|
&& (event.getTargetId().equals(cardId) || event.getTargetId().equals(source.getSourceId()))) {
|
||||||
if (condition == null || condition.apply(game, source)) {
|
return condition == null || condition.apply(game, source);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
39
Mage/src/main/java/mage/abilities/common/RoomAbility.java
Normal file
39
Mage/src/main/java/mage/abilities/common/RoomAbility.java
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
package mage.abilities.common;
|
||||||
|
|
||||||
|
import mage.abilities.effects.common.RoomCharacteristicsEffect;
|
||||||
|
import mage.constants.Zone;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.permanent.Permanent;
|
||||||
|
import mage.game.permanent.PermanentImpl;
|
||||||
|
|
||||||
|
// For the overall Room card flavor text and mana value effect.
|
||||||
|
public class RoomAbility extends SimpleStaticAbility {
|
||||||
|
public RoomAbility() {
|
||||||
|
super(Zone.BATTLEFIELD, new RoomCharacteristicsEffect());
|
||||||
|
this.setRuleVisible(true);
|
||||||
|
this.setRuleAtTheTop(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected RoomAbility(final RoomAbility ability) {
|
||||||
|
super(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRule() {
|
||||||
|
return "<i>(You may cast either half. That door unlocks on the battlefield. " +
|
||||||
|
"As a sorcery, you may pay the mana cost of a locked door to unlock it.)</i>";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RoomAbility copy() {
|
||||||
|
return new RoomAbility(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void applyCharacteristics(Game game, Permanent permanent) {
|
||||||
|
((RoomCharacteristicsEffect) this.getEffects().get(0)).removeCharacteristics(game, permanent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void restoreUnlockedStats(Game game, PermanentImpl permanent) {
|
||||||
|
((RoomCharacteristicsEffect) this.getEffects().get(0)).restoreUnlockedStats(game, permanent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -12,12 +12,11 @@ import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Special action for Room cards to unlock a locked half by paying its
|
||||||
|
* mana cost.
|
||||||
|
* This ability is only present if the corresponding half is currently
|
||||||
|
* locked.
|
||||||
* @author oscscull
|
* @author oscscull
|
||||||
* Special action for Room cards to unlock a locked half by paying its
|
|
||||||
* mana
|
|
||||||
* cost.
|
|
||||||
* This ability is only present if the corresponding half is currently
|
|
||||||
* locked.
|
|
||||||
*/
|
*/
|
||||||
public class RoomUnlockAbility extends SpecialAction {
|
public class RoomUnlockAbility extends SpecialAction {
|
||||||
|
|
||||||
|
|
@ -61,6 +60,10 @@ public class RoomUnlockAbility extends SpecialAction {
|
||||||
sb.append(isLeftHalf ? "left" : "right").append(" half is locked.)</i>");
|
sb.append(isLeftHalf ? "left" : "right").append(" half is locked.)</i>");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isLeftHalf() {
|
||||||
|
return isLeftHalf;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
import mage.abilities.keyword.TransformAbility;
|
import mage.abilities.keyword.TransformAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.cards.TransformingDoubleFacedCard;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.stack.Spell;
|
import mage.game.stack.Spell;
|
||||||
|
|
@ -20,6 +21,7 @@ import java.util.UUID;
|
||||||
public class SpellTransformedAbility extends SpellAbility {
|
public class SpellTransformedAbility extends SpellAbility {
|
||||||
|
|
||||||
protected final String manaCost; //This variable is only used for rules text
|
protected final String manaCost; //This variable is only used for rules text
|
||||||
|
private boolean ignoreTransformEffect; // TODO: temporary while converting tdfc
|
||||||
|
|
||||||
public SpellTransformedAbility(Card card, String manaCost) {
|
public SpellTransformedAbility(Card card, String manaCost) {
|
||||||
super(card.getSecondFaceSpellAbility());
|
super(card.getSecondFaceSpellAbility());
|
||||||
|
|
@ -35,7 +37,11 @@ public class SpellTransformedAbility extends SpellAbility {
|
||||||
this.clearManaCosts();
|
this.clearManaCosts();
|
||||||
this.clearManaCostsToPay();
|
this.clearManaCostsToPay();
|
||||||
this.addCost(new ManaCostsImpl<>(manaCost));
|
this.addCost(new ManaCostsImpl<>(manaCost));
|
||||||
this.addSubAbility(new TransformAbility());
|
if (!(card instanceof TransformingDoubleFacedCard)) {
|
||||||
|
this.addSubAbility(new TransformAbility());
|
||||||
|
} else {
|
||||||
|
ignoreTransformEffect = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public SpellTransformedAbility(final SpellAbility ability) {
|
public SpellTransformedAbility(final SpellAbility ability) {
|
||||||
|
|
@ -54,6 +60,7 @@ public class SpellTransformedAbility extends SpellAbility {
|
||||||
protected SpellTransformedAbility(final SpellTransformedAbility ability) {
|
protected SpellTransformedAbility(final SpellTransformedAbility ability) {
|
||||||
super(ability);
|
super(ability);
|
||||||
this.manaCost = ability.manaCost;
|
this.manaCost = ability.manaCost;
|
||||||
|
this.ignoreTransformEffect = ability.ignoreTransformEffect;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -65,6 +72,9 @@ public class SpellTransformedAbility extends SpellAbility {
|
||||||
public boolean activate(Game game, Set<MageIdentifier> allowedIdentifiers, boolean noMana) {
|
public boolean activate(Game game, Set<MageIdentifier> allowedIdentifiers, boolean noMana) {
|
||||||
if (super.activate(game, allowedIdentifiers, noMana)) {
|
if (super.activate(game, allowedIdentifiers, noMana)) {
|
||||||
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getSourceId(), Boolean.TRUE);
|
game.getState().setValue(TransformAbility.VALUE_KEY_ENTER_TRANSFORMED + getSourceId(), Boolean.TRUE);
|
||||||
|
if (ignoreTransformEffect) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
// TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides)
|
// TODO: must be removed after transform cards (one side) migrated to MDF engine (multiple sides)
|
||||||
TransformedEffect effect = new TransformedEffect();
|
TransformedEffect effect = new TransformedEffect();
|
||||||
game.addEffect(effect, this);
|
game.addEffect(effect, this);
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,7 @@ package mage.abilities.effects;
|
||||||
import mage.MageIdentifier;
|
import mage.MageIdentifier;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.ActivatedAbility;
|
import mage.abilities.ActivatedAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.*;
|
||||||
import mage.cards.ModalDoubleFacedCard;
|
|
||||||
import mage.cards.SplitCard;
|
|
||||||
import mage.cards.CardWithSpellOption;
|
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.players.Player;
|
import mage.players.Player;
|
||||||
|
|
@ -92,9 +89,9 @@ public abstract class AsThoughEffectImpl extends ContinuousEffectImpl implements
|
||||||
player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCard.getSpellAbility().getCosts(), identifier);
|
player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCard.getSpellAbility().getCosts(), identifier);
|
||||||
Card rightCard = ((SplitCard) card).getRightHalfCard();
|
Card rightCard = ((SplitCard) card).getRightHalfCard();
|
||||||
player.setCastSourceIdWithAlternateMana(rightCard.getId(), null, rightCard.getSpellAbility().getCosts(), identifier);
|
player.setCastSourceIdWithAlternateMana(rightCard.getId(), null, rightCard.getSpellAbility().getCosts(), identifier);
|
||||||
} else if (card instanceof ModalDoubleFacedCard) {
|
} else if (card instanceof DoubleFacedCard) {
|
||||||
Card leftCard = ((ModalDoubleFacedCard) card).getLeftHalfCard();
|
Card leftCard = ((DoubleFacedCard) card).getLeftHalfCard();
|
||||||
Card rightCard = ((ModalDoubleFacedCard) card).getRightHalfCard();
|
Card rightCard = ((DoubleFacedCard) card).getRightHalfCard();
|
||||||
// some MDFC's are land. IE: sea gate restoration
|
// some MDFC's are land. IE: sea gate restoration
|
||||||
if (!leftCard.isLand(game)) {
|
if (!leftCard.isLand(game)) {
|
||||||
player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCard.getSpellAbility().getCosts(), identifier);
|
player.setCastSourceIdWithAlternateMana(leftCard.getId(), null, leftCard.getSpellAbility().getCosts(), identifier);
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,11 @@ package mage.abilities.effects.common;
|
||||||
|
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.MageObjectReference;
|
import mage.MageObjectReference;
|
||||||
|
import mage.abilities.Abilities;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.abilities.common.RoomAbility;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
|
|
@ -63,6 +65,16 @@ public class CopyEffect extends ContinuousEffectImpl {
|
||||||
permanent = game.getPermanentEntering(copyToObjectId);
|
permanent = game.getPermanentEntering(copyToObjectId);
|
||||||
if (permanent != null) {
|
if (permanent != null) {
|
||||||
copyToPermanent(permanent, game, source);
|
copyToPermanent(permanent, game, source);
|
||||||
|
// Apply Room characteristics since effects aren't applied to entering permanents yet
|
||||||
|
if (permanent.hasSubtype(SubType.ROOM, game)) {
|
||||||
|
Abilities<Ability> abilities = permanent.getAbilities();
|
||||||
|
for (Ability ability : abilities) {
|
||||||
|
if (ability instanceof RoomAbility) {
|
||||||
|
((RoomAbility) ability).applyCharacteristics(game, permanent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// set reference to the permanent later on the battlefield so we have to add already one (if no token) to the zone change counter
|
// set reference to the permanent later on the battlefield so we have to add already one (if no token) to the zone change counter
|
||||||
int ZCCDiff = 1;
|
int ZCCDiff = 1;
|
||||||
if (permanent instanceof PermanentToken) {
|
if (permanent instanceof PermanentToken) {
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,28 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
||||||
// create token and modify all attributes permanently (without game usage)
|
// create token and modify all attributes permanently (without game usage)
|
||||||
Token token = CopyTokenFunction.createTokenCopy(copyFrom, game); // needed so that entersBattlefield triggered abilities see the attributes (e.g. Master Biomancer)
|
Token token = CopyTokenFunction.createTokenCopy(copyFrom, game); // needed so that entersBattlefield triggered abilities see the attributes (e.g. Master Biomancer)
|
||||||
applier.apply(game, token, source, targetId);
|
applier.apply(game, token, source, targetId);
|
||||||
|
// the active face should have the modified attributes
|
||||||
|
if (token.isEntersTransformed()) {
|
||||||
|
applyAdditionsToToken(token.getBackFace());
|
||||||
|
} else {
|
||||||
|
applyAdditionsToToken(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
token.putOntoBattlefield(number, game, source, playerId == null ? source.getControllerId() : playerId, tapped, attacking, attackedPlayer, attachedTo);
|
||||||
|
for (UUID tokenId : token.getLastAddedTokenIds()) { // by cards like Doubling Season multiple tokens can be added to the battlefield
|
||||||
|
Permanent tokenPermanent = game.getPermanent(tokenId);
|
||||||
|
if (tokenPermanent != null) {
|
||||||
|
addedTokenPermanents.add(tokenPermanent);
|
||||||
|
// TODO: Workaround to add counters to all created tokens, necessary for correct interactions with cards like Chatterfang, Squirrel General and Ochre Jelly / Printlifter Ooze. See #10786
|
||||||
|
if (counter != null && numberOfCounters > 0) {
|
||||||
|
tokenPermanent.addCounters(counter.createInstance(numberOfCounters), source.getControllerId(), source, game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void applyAdditionsToToken(Token token) {
|
||||||
if (becomesArtifact) {
|
if (becomesArtifact) {
|
||||||
token.addCardType(CardType.ARTIFACT);
|
token.addCardType(CardType.ARTIFACT);
|
||||||
}
|
}
|
||||||
|
|
@ -281,19 +303,6 @@ public class CreateTokenCopyTargetEffect extends OneShotEffect {
|
||||||
token.removeAbility(ability);
|
token.removeAbility(ability);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
token.putOntoBattlefield(number, game, source, playerId == null ? source.getControllerId() : playerId, tapped, attacking, attackedPlayer, attachedTo);
|
|
||||||
for (UUID tokenId : token.getLastAddedTokenIds()) { // by cards like Doubling Season multiple tokens can be added to the battlefield
|
|
||||||
Permanent tokenPermanent = game.getPermanent(tokenId);
|
|
||||||
if (tokenPermanent != null) {
|
|
||||||
addedTokenPermanents.add(tokenPermanent);
|
|
||||||
// TODO: Workaround to add counters to all created tokens, necessary for correct interactions with cards like Chatterfang, Squirrel General and Ochre Jelly / Printlifter Ooze. See #10786
|
|
||||||
if (counter != null && numberOfCounters > 0) {
|
|
||||||
tokenPermanent.addCounters(counter.createInstance(numberOfCounters), source.getControllerId(), source, game);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package mage.abilities.effects.common;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.ModalDoubleFacedCard;
|
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
|
@ -37,10 +36,6 @@ public class ReturnToHandAttachedEffect extends OneShotEffect {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Card card = permanent.getMainCard();
|
Card card = permanent.getMainCard();
|
||||||
// TODO: Once MDFC ZCC increments are fixed properly, can remove this special case. For now must allow so effect works.
|
|
||||||
if (permanent.getZoneChangeCounter(game) + 1 != card.getZoneChangeCounter(game) && !(card instanceof ModalDoubleFacedCard)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return player.moveCards(card, Zone.HAND, source, game);
|
return player.moveCards(card, Zone.HAND, source, game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
package mage.abilities.effects.common;
|
package mage.abilities.effects.common;
|
||||||
|
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.Mana;
|
import mage.abilities.Abilities;
|
||||||
|
import mage.abilities.AbilitiesImpl;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
|
import mage.abilities.SpellAbility;
|
||||||
|
import mage.abilities.common.RoomUnlockAbility;
|
||||||
|
import mage.abilities.costs.mana.ManaCost;
|
||||||
import mage.abilities.costs.mana.ManaCosts;
|
import mage.abilities.costs.mana.ManaCosts;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.effects.ContinuousEffectImpl;
|
import mage.abilities.effects.ContinuousEffectImpl;
|
||||||
|
|
@ -15,12 +19,13 @@ import mage.constants.SubLayer;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.PermanentCard;
|
import mage.game.permanent.PermanentCard;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author oscscull
|
|
||||||
* Continuous effect that sets the name and mana value of a Room permanent based
|
* Continuous effect that sets the name and mana value of a Room permanent based
|
||||||
* on its unlocked halves.
|
* on its unlocked halves.
|
||||||
*
|
|
||||||
* Functions as a characteristic-defining ability.
|
* Functions as a characteristic-defining ability.
|
||||||
* 709.5. Some split cards are permanent cards with a single shared type line.
|
* 709.5. Some split cards are permanent cards with a single shared type line.
|
||||||
* A shared type line on such an object represents two static abilities that
|
* A shared type line on such an object represents two static abilities that
|
||||||
|
|
@ -33,11 +38,13 @@ import mage.game.permanent.PermanentCard;
|
||||||
* object's right half."
|
* object's right half."
|
||||||
* These abilities, as well as which half of that permanent a characteristic is
|
* These abilities, as well as which half of that permanent a characteristic is
|
||||||
* in, are part of that object's copiable values.
|
* in, are part of that object's copiable values.
|
||||||
|
* @author oscscull
|
||||||
*/
|
*/
|
||||||
public class RoomCharacteristicsEffect extends ContinuousEffectImpl {
|
public class RoomCharacteristicsEffect extends ContinuousEffectImpl {
|
||||||
|
|
||||||
|
|
||||||
public RoomCharacteristicsEffect() {
|
public RoomCharacteristicsEffect() {
|
||||||
super(Duration.WhileOnBattlefield, Layer.PTChangingEffects_7, SubLayer.CharacteristicDefining_7a,
|
super(Duration.WhileOnBattlefield, Layer.TextChangingEffects_3, SubLayer.NA,
|
||||||
Outcome.Neutral);
|
Outcome.Neutral);
|
||||||
staticText = "";
|
staticText = "";
|
||||||
}
|
}
|
||||||
|
|
@ -59,6 +66,107 @@ public class RoomCharacteristicsEffect extends ContinuousEffectImpl {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return removeCharacteristics(game, permanent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean removeCharacteristics(Game game, Permanent permanent) {
|
||||||
|
Card roomCardBlueprint = getCard(permanent);
|
||||||
|
|
||||||
|
if (!(roomCardBlueprint instanceof SplitCard)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SplitCard roomCard = (SplitCard) roomCardBlueprint;
|
||||||
|
|
||||||
|
// Remove the name based on unlocked halves
|
||||||
|
String newName = permanent.getName();
|
||||||
|
|
||||||
|
boolean isLeftUnlocked = permanent.isLeftDoorUnlocked();
|
||||||
|
if (!isLeftUnlocked && roomCard.getLeftHalfCard() != null) {
|
||||||
|
newName = newName.replace(roomCard.getLeftHalfCard().getName() + " // ", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean isRightUnlocked = permanent.isRightDoorUnlocked();
|
||||||
|
if (!isRightUnlocked && roomCard.getRightHalfCard() != null) {
|
||||||
|
newName = newName
|
||||||
|
.replace(" // " + roomCard.getRightHalfCard().getName(), "")
|
||||||
|
.replace(roomCard.getRightHalfCard().getName(), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
permanent.setName(newName);
|
||||||
|
|
||||||
|
// Set the mana value based on unlocked halves
|
||||||
|
// Create a new Mana object to accumulate the costs
|
||||||
|
SpellAbility roomCardSpellAbility = roomCard.getSpellAbility().copy();
|
||||||
|
// Remove the mana from the left half's cost to our total Mana object
|
||||||
|
if (!isLeftUnlocked) {
|
||||||
|
ManaCosts<ManaCost> leftHalfManaCost = null;
|
||||||
|
if (roomCard.getLeftHalfCard() != null && roomCard.getLeftHalfCard().getSpellAbility() != null) {
|
||||||
|
leftHalfManaCost = roomCard.getLeftHalfCard().getSpellAbility().getManaCosts();
|
||||||
|
}
|
||||||
|
if (leftHalfManaCost != null) {
|
||||||
|
CardUtil.adjustCost(roomCardSpellAbility, leftHalfManaCost, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the mana from the right half's cost to our total Mana object
|
||||||
|
if (!isRightUnlocked) {
|
||||||
|
ManaCosts<ManaCost> rightHalfManaCost = null;
|
||||||
|
if (roomCard.getRightHalfCard() != null && roomCard.getRightHalfCard().getSpellAbility() != null) {
|
||||||
|
rightHalfManaCost = roomCard.getRightHalfCard().getSpellAbility().getManaCosts();
|
||||||
|
}
|
||||||
|
if (rightHalfManaCost != null) {
|
||||||
|
CardUtil.adjustCost(roomCardSpellAbility, rightHalfManaCost, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ManaCosts<ManaCost> roomCardManaCosts = roomCardSpellAbility.getManaCostsToPay();
|
||||||
|
if (roomCardManaCosts.getText().equals("{0}")) {
|
||||||
|
roomCardManaCosts = new ManaCostsImpl<>();
|
||||||
|
}
|
||||||
|
permanent.setManaCost(roomCardManaCosts);
|
||||||
|
|
||||||
|
|
||||||
|
// Remove abilities from locked halves and add unlock abilities
|
||||||
|
Abilities<Ability> removedLeftAbilities = new AbilitiesImpl<>();
|
||||||
|
Abilities<Ability> removedRightAbilities = new AbilitiesImpl<>();
|
||||||
|
Card abilitySource = permanent;
|
||||||
|
if (permanent.isCopy()) {
|
||||||
|
abilitySource = (Card) permanent.getCopyFrom();
|
||||||
|
}
|
||||||
|
for (Ability ability : abilitySource.getAbilities(game)) {
|
||||||
|
if (!isLeftUnlocked) {
|
||||||
|
if (roomCard.getLeftHalfCard() != null && roomCard.getLeftHalfCard().getAbilities().contains(ability)) {
|
||||||
|
if (!removedLeftAbilities.contains(ability)) {
|
||||||
|
removedLeftAbilities.add(ability);
|
||||||
|
}
|
||||||
|
permanent.removeAbility(ability, null, game);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isRightUnlocked) {
|
||||||
|
if (roomCard.getRightHalfCard() != null && roomCard.getRightHalfCard().getAbilities().contains(ability)) {
|
||||||
|
if (!removedRightAbilities.contains(ability)) {
|
||||||
|
removedRightAbilities.add(ability);
|
||||||
|
}
|
||||||
|
permanent.removeAbility(ability, null, game);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Add the Special Action to unlock doors.
|
||||||
|
// These will ONLY be active if the corresponding half is LOCKED!
|
||||||
|
if (!removedLeftAbilities.isEmpty()) {
|
||||||
|
RoomUnlockAbility leftUnlockAbility = new RoomUnlockAbility(roomCard.getLeftHalfCard().getManaCost(), true);
|
||||||
|
permanent.addAbility(leftUnlockAbility, roomCard.getLeftHalfCard().getId(), game);
|
||||||
|
}
|
||||||
|
if (!removedRightAbilities.isEmpty()) {
|
||||||
|
RoomUnlockAbility rightUnlockAbility = new RoomUnlockAbility(roomCard.getRightHalfCard().getManaCost(), false);
|
||||||
|
permanent.addAbility(rightUnlockAbility, roomCard.getRightHalfCard().getId(), game);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Card getCard(Permanent permanent) {
|
||||||
Card roomCardBlueprint;
|
Card roomCardBlueprint;
|
||||||
|
|
||||||
// Handle copies
|
// Handle copies
|
||||||
|
|
@ -74,69 +182,34 @@ public class RoomCharacteristicsEffect extends ContinuousEffectImpl {
|
||||||
} else {
|
} else {
|
||||||
roomCardBlueprint = permanent.getMainCard();
|
roomCardBlueprint = permanent.getMainCard();
|
||||||
}
|
}
|
||||||
|
return roomCardBlueprint;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(roomCardBlueprint instanceof SplitCard)) {
|
public void restoreUnlockedStats(Game game, Permanent permanent) {
|
||||||
return false;
|
// remove unlock abilities
|
||||||
}
|
for (Ability ability : permanent.getAbilities(game)) {
|
||||||
|
if (ability instanceof RoomUnlockAbility) {
|
||||||
SplitCard roomCard = (SplitCard) roomCardBlueprint;
|
if (((RoomUnlockAbility) ability).isLeftHalf() && permanent.isLeftDoorUnlocked()) {
|
||||||
|
permanent.removeAbility(ability, null, game);
|
||||||
// Set the name based on unlocked halves
|
} else if (!((RoomUnlockAbility) ability).isLeftHalf() && permanent.isRightDoorUnlocked()) {
|
||||||
String newName = "";
|
permanent.removeAbility(ability, null, game);
|
||||||
|
}
|
||||||
boolean isLeftUnlocked = permanent.isLeftDoorUnlocked();
|
|
||||||
if (isLeftUnlocked && roomCard.getLeftHalfCard() != null) {
|
|
||||||
newName += roomCard.getLeftHalfCard().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isRightUnlocked = permanent.isRightDoorUnlocked();
|
|
||||||
if (isRightUnlocked && roomCard.getRightHalfCard() != null) {
|
|
||||||
if (!newName.isEmpty()) {
|
|
||||||
newName += " // "; // Split card name separator
|
|
||||||
}
|
|
||||||
newName += roomCard.getRightHalfCard().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
permanent.setName(newName);
|
|
||||||
|
|
||||||
// Set the mana value based on unlocked halves
|
|
||||||
// Create a new Mana object to accumulate the costs
|
|
||||||
Mana totalManaCost = new Mana();
|
|
||||||
|
|
||||||
// Add the mana from the left half's cost to our total Mana object
|
|
||||||
if (isLeftUnlocked) {
|
|
||||||
ManaCosts leftHalfManaCost = null;
|
|
||||||
if (roomCard.getLeftHalfCard() != null && roomCard.getLeftHalfCard().getSpellAbility() != null) {
|
|
||||||
leftHalfManaCost = roomCard.getLeftHalfCard().getSpellAbility().getManaCosts();
|
|
||||||
}
|
|
||||||
if (leftHalfManaCost != null) {
|
|
||||||
totalManaCost.add(leftHalfManaCost.getMana());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// restore removed abilities
|
||||||
// Add the mana from the right half's cost to our total Mana object
|
// copies need abilities to be added back to game state for triggers
|
||||||
if (isRightUnlocked) {
|
SplitCard roomCard = (SplitCard) getCard(permanent);
|
||||||
ManaCosts rightHalfManaCost = null;
|
UUID sourceId = permanent.isCopy() ? permanent.getId() : null;
|
||||||
if (roomCard.getRightHalfCard() != null && roomCard.getRightHalfCard().getSpellAbility() != null) {
|
Game gameParam = permanent.isCopy() ? game : null;
|
||||||
rightHalfManaCost = roomCard.getRightHalfCard().getSpellAbility().getManaCosts();
|
if (permanent.isLeftDoorUnlocked()) {
|
||||||
}
|
for (Ability ability : roomCard.getLeftHalfCard().getAbilities()) {
|
||||||
if (rightHalfManaCost != null) {
|
permanent.addAbility(ability, sourceId, gameParam, true);
|
||||||
totalManaCost.add(rightHalfManaCost.getMana());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (permanent.isRightDoorUnlocked()) {
|
||||||
String newManaCostString = totalManaCost.toString();
|
for (Ability ability : roomCard.getRightHalfCard().getAbilities()) {
|
||||||
ManaCostsImpl newManaCosts;
|
permanent.addAbility(ability, sourceId, gameParam, true);
|
||||||
|
}
|
||||||
// If both halves are locked or total 0, it's 0mv.
|
|
||||||
if (newManaCostString.isEmpty() || totalManaCost.count() == 0) {
|
|
||||||
newManaCosts = new ManaCostsImpl<>("");
|
|
||||||
} else {
|
|
||||||
newManaCosts = new ManaCostsImpl<>(newManaCostString);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
permanent.setManaCost(newManaCosts);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -16,7 +16,7 @@ import mage.abilities.effects.common.InfoEffect;
|
||||||
import mage.abilities.keyword.WardAbility;
|
import mage.abilities.keyword.WardAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardImpl;
|
import mage.cards.CardImpl;
|
||||||
import mage.cards.ModalDoubleFacedCard;
|
import mage.cards.DoubleFacedCard;
|
||||||
import mage.cards.repository.TokenInfo;
|
import mage.cards.repository.TokenInfo;
|
||||||
import mage.cards.repository.TokenRepository;
|
import mage.cards.repository.TokenRepository;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
|
|
@ -375,9 +375,9 @@ public class BecomesFaceDownCreatureEffect extends ContinuousEffectImpl {
|
||||||
// it can't transform. If the front face of the card is a creature card, you can turn it face up by paying
|
// it can't transform. If the front face of the card is a creature card, you can turn it face up by paying
|
||||||
// its mana cost. If you do, its front face will be up.
|
// its mana cost. If you do, its front face will be up.
|
||||||
|
|
||||||
if (card instanceof ModalDoubleFacedCard) {
|
if (card instanceof DoubleFacedCard) {
|
||||||
// only MDFC uses independent card sides on 2024
|
// only MDFC uses independent card sides on 2024
|
||||||
return ((ModalDoubleFacedCard) card).getLeftHalfCard();
|
return ((DoubleFacedCard) card).getLeftHalfCard();
|
||||||
} else {
|
} else {
|
||||||
return card;
|
return card;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import mage.abilities.costs.common.ExileSourceCost;
|
||||||
import mage.abilities.costs.mana.ManaCostsImpl;
|
import mage.abilities.costs.mana.ManaCostsImpl;
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
|
import mage.cards.TransformingDoubleFacedCardHalf;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.filter.FilterCard;
|
import mage.filter.FilterCard;
|
||||||
import mage.filter.FilterPermanent;
|
import mage.filter.FilterPermanent;
|
||||||
|
|
|
||||||
|
|
@ -300,6 +300,7 @@ class ForetellAddCostEffect extends ContinuousEffectImpl {
|
||||||
if (game.getState().getZone(mainCardId) == Zone.EXILED) {
|
if (game.getState().getZone(mainCardId) == Zone.EXILED) {
|
||||||
String foretellCost = (String) game.getState().getValue(mainCardId.toString() + "Foretell Cost");
|
String foretellCost = (String) game.getState().getValue(mainCardId.toString() + "Foretell Cost");
|
||||||
String foretellSplitCost = (String) game.getState().getValue(mainCardId.toString() + "Foretell Split Cost");
|
String foretellSplitCost = (String) game.getState().getValue(mainCardId.toString() + "Foretell Split Cost");
|
||||||
|
// TODO: clean this up
|
||||||
if (card instanceof SplitCard) {
|
if (card instanceof SplitCard) {
|
||||||
if (foretellCost != null) {
|
if (foretellCost != null) {
|
||||||
SplitCardHalf leftHalfCard = ((SplitCard) card).getLeftHalfCard();
|
SplitCardHalf leftHalfCard = ((SplitCard) card).getLeftHalfCard();
|
||||||
|
|
@ -363,6 +364,14 @@ class ForetellAddCostEffect extends ContinuousEffectImpl {
|
||||||
ability.setAbilityName(spellCard.getName());
|
ability.setAbilityName(spellCard.getName());
|
||||||
game.getState().addOtherAbility(spellCard, ability);
|
game.getState().addOtherAbility(spellCard, ability);
|
||||||
}
|
}
|
||||||
|
} else if (card instanceof TransformingDoubleFacedCard && foretellCost != null) {
|
||||||
|
Card frontCard = ((TransformingDoubleFacedCard) card).getLeftHalfCard();
|
||||||
|
ForetellCostAbility ability = new ForetellCostAbility(foretellCost);
|
||||||
|
ability.setSourceId(frontCard.getId());
|
||||||
|
ability.setControllerId(source.getControllerId());
|
||||||
|
ability.setSpellAbilityType(frontCard.getSpellAbility().getSpellAbilityType());
|
||||||
|
ability.setAbilityName(frontCard.getName());
|
||||||
|
game.getState().addOtherAbility(frontCard, ability);
|
||||||
} else if (foretellCost != null) {
|
} else if (foretellCost != null) {
|
||||||
ForetellCostAbility ability = new ForetellCostAbility(foretellCost);
|
ForetellCostAbility ability = new ForetellCostAbility(foretellCost);
|
||||||
ability.setSourceId(card.getId());
|
ability.setSourceId(card.getId());
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import mage.abilities.effects.common.counter.RemoveCounterSourceEffect;
|
||||||
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
|
import mage.abilities.triggers.BeginningOfUpkeepTriggeredAbility;
|
||||||
import mage.cards.Card;
|
import mage.cards.Card;
|
||||||
import mage.cards.CardsImpl;
|
import mage.cards.CardsImpl;
|
||||||
import mage.cards.ModalDoubleFacedCard;
|
import mage.cards.DoubleFacedCard;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.counters.CounterType;
|
import mage.counters.CounterType;
|
||||||
import mage.filter.StaticFilters;
|
import mage.filter.StaticFilters;
|
||||||
|
|
@ -177,10 +177,10 @@ public class SuspendAbility extends SpecialAction {
|
||||||
* or added by Jhoira of the Ghitu
|
* or added by Jhoira of the Ghitu
|
||||||
*/
|
*/
|
||||||
public static void addSuspendTemporaryToCard(Card card, Ability source, Game game) {
|
public static void addSuspendTemporaryToCard(Card card, Ability source, Game game) {
|
||||||
if (card instanceof ModalDoubleFacedCard) {
|
if (card instanceof DoubleFacedCard) {
|
||||||
// Need to ensure the suspend ability gets put on the left side card
|
// Need to ensure the suspend ability gets put on the left side card
|
||||||
// since counters get added to this card.
|
// since counters get added to this card.
|
||||||
card = ((ModalDoubleFacedCard) card).getLeftHalfCard();
|
card = ((DoubleFacedCard) card).getLeftHalfCard();
|
||||||
}
|
}
|
||||||
SuspendAbility ability = new SuspendAbility(0, null, card, false);
|
SuspendAbility ability = new SuspendAbility(0, null, card, false);
|
||||||
ability.setSourceId(card.getId());
|
ability.setSourceId(card.getId());
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
import mage.abilities.Abilities;
|
import mage.abilities.Abilities;
|
||||||
|
|
@ -72,6 +73,7 @@ public interface Card extends MageObject, Ownerable {
|
||||||
|
|
||||||
SpellAbility getSecondFaceSpellAbility();
|
SpellAbility getSecondFaceSpellAbility();
|
||||||
|
|
||||||
|
//TODO: remove after tdfc rework
|
||||||
boolean isNightCard();
|
boolean isNightCard();
|
||||||
|
|
||||||
default boolean meldsWith(Card card) {
|
default boolean meldsWith(Card card) {
|
||||||
|
|
@ -250,6 +252,10 @@ public interface Card extends MageObject, Ownerable {
|
||||||
|
|
||||||
List<UUID> getAttachments();
|
List<UUID> getAttachments();
|
||||||
|
|
||||||
|
void setPT(int power, int toughness);
|
||||||
|
|
||||||
|
void setPT(MageInt power, MageInt toughness);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param attachment can be any object: card, permanent, token
|
* @param attachment can be any object: card, permanent, token
|
||||||
* @param source can be null for default checks like state base
|
* @param source can be null for default checks like state base
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
import mage.MageObject;
|
import mage.MageObject;
|
||||||
import mage.MageObjectImpl;
|
import mage.MageObjectImpl;
|
||||||
import mage.Mana;
|
import mage.Mana;
|
||||||
|
|
@ -126,6 +127,11 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
nightCard = card.nightCard;
|
nightCard = card.nightCard;
|
||||||
secondSideCardClazz = card.secondSideCardClazz;
|
secondSideCardClazz = card.secondSideCardClazz;
|
||||||
secondSideCard = null; // will be set on first getSecondCardFace call if card has one
|
secondSideCard = null; // will be set on first getSecondCardFace call if card has one
|
||||||
|
// TODO: temporary until cards tdfc cards are converted
|
||||||
|
// can do normal copy after
|
||||||
|
if (card.secondSideCard instanceof DoubleFacedCardHalf) {
|
||||||
|
secondSideCard = card.secondSideCard.copy();
|
||||||
|
}
|
||||||
if (card.secondSideCard instanceof MockableCard) {
|
if (card.secondSideCard instanceof MockableCard) {
|
||||||
// workaround to support gui's mock cards
|
// workaround to support gui's mock cards
|
||||||
secondSideCard = card.secondSideCard.copy();
|
secondSideCard = card.secondSideCard.copy();
|
||||||
|
|
@ -393,6 +399,17 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
this.abilities.setControllerId(ownerId);
|
this.abilities.setControllerId(ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPT(int power, int toughness) {
|
||||||
|
this.setPT(new MageInt(power), new MageInt(toughness));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setPT(MageInt power, MageInt toughness) {
|
||||||
|
this.power = power;
|
||||||
|
this.toughness = toughness;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UUID getControllerOrOwnerId() {
|
public UUID getControllerOrOwnerId() {
|
||||||
return getOwnerId();
|
return getOwnerId();
|
||||||
|
|
@ -517,13 +534,13 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle half of Modal Double Faces Cards on stack
|
// handle half of Double Faces Cards on stack
|
||||||
if (stackObject == null && (this instanceof ModalDoubleFacedCard)) {
|
if (stackObject == null && (this instanceof DoubleFacedCard)) {
|
||||||
stackObject = game.getStack().getSpell(((ModalDoubleFacedCard) this).getLeftHalfCard().getId(),
|
stackObject = game.getStack().getSpell(((DoubleFacedCard) this).getLeftHalfCard().getId(),
|
||||||
false);
|
false);
|
||||||
if (stackObject == null) {
|
if (stackObject == null) {
|
||||||
stackObject = game.getStack()
|
stackObject = game.getStack()
|
||||||
.getSpell(((ModalDoubleFacedCard) this).getRightHalfCard().getId(), false);
|
.getSpell(((DoubleFacedCard) this).getRightHalfCard().getId(), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -650,7 +667,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
// If a spell or ability instructs a player to transform a permanent that
|
// If a spell or ability instructs a player to transform a permanent that
|
||||||
// isn’t represented by a transforming token or a transforming double-faced
|
// isn’t represented by a transforming token or a transforming double-faced
|
||||||
// card, nothing happens.
|
// card, nothing happens.
|
||||||
return this.secondSideCardClazz != null || this.nightCard;
|
return this.secondSideCardClazz != null || this.nightCard || this.secondSideCard != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -947,7 +964,7 @@ public abstract class CardImpl extends MageObjectImpl implements Card {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (controller != null && spellAbility != null && !spellAbility.getTargets().isEmpty()){
|
if (controller != null && spellAbility != null && !spellAbility.getTargets().isEmpty()) {
|
||||||
// Line of code below functionally gets the target of the aura's Enchant ability, then compares to this permanent. Enchant improperly implemented in XMage, see #9583
|
// Line of code below functionally gets the target of the aura's Enchant ability, then compares to this permanent. Enchant improperly implemented in XMage, see #9583
|
||||||
// Note: stillLegalTarget used exclusively to account for Dream Leash. Can be made canTarget in the event that that card is rewritten (and "stillLegalTarget" removed from TargetImpl).
|
// Note: stillLegalTarget used exclusively to account for Dream Leash. Can be made canTarget in the event that that card is rewritten (and "stillLegalTarget" removed from TargetImpl).
|
||||||
canAttach &= spellAbility.getTargets().get(0).copy().withNotTarget(true).stillLegalTarget(controller, this.getId(), source, game);
|
canAttach &= spellAbility.getTargets().get(0).copy().withNotTarget(true).stillLegalTarget(controller, this.getId(), source, game);
|
||||||
|
|
|
||||||
413
Mage/src/main/java/mage/cards/DoubleFacedCard.java
Normal file
413
Mage/src/main/java/mage/cards/DoubleFacedCard.java
Normal file
|
|
@ -0,0 +1,413 @@
|
||||||
|
package mage.cards;
|
||||||
|
|
||||||
|
import mage.MageInt;
|
||||||
|
import mage.MageObject;
|
||||||
|
import mage.ObjectColor;
|
||||||
|
import mage.abilities.*;
|
||||||
|
import mage.abilities.costs.mana.ManaCost;
|
||||||
|
import mage.abilities.costs.mana.ManaCosts;
|
||||||
|
import mage.constants.*;
|
||||||
|
import mage.counters.Counter;
|
||||||
|
import mage.counters.Counters;
|
||||||
|
import mage.game.Game;
|
||||||
|
import mage.game.GameState;
|
||||||
|
import mage.game.events.ZoneChangeEvent;
|
||||||
|
import mage.util.CardUtil;
|
||||||
|
import mage.util.SubTypes;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author JayDi85 - originally from ModalDoubleFaceCard
|
||||||
|
*/
|
||||||
|
public abstract class DoubleFacedCard extends CardImpl implements CardWithHalves {
|
||||||
|
|
||||||
|
protected DoubleFacedCardHalf leftHalfCard; // main card in all zone
|
||||||
|
protected DoubleFacedCardHalf rightHalfCard; // second side card, can be only in stack and battlefield zones
|
||||||
|
|
||||||
|
protected DoubleFacedCard(UUID ownerId, CardSetInfo setInfo, CardType[] cardTypes, String costs, SpellAbilityType spellAbilityType) {
|
||||||
|
super(ownerId, setInfo, cardTypes, costs, spellAbilityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleFacedCard(DoubleFacedCard card) {
|
||||||
|
super(card);
|
||||||
|
// make sure all parts created and parent ref added
|
||||||
|
this.leftHalfCard = (DoubleFacedCardHalf) card.getLeftHalfCard().copy();
|
||||||
|
leftHalfCard.setParentCard(this);
|
||||||
|
this.rightHalfCard = (DoubleFacedCardHalf) card.getRightHalfCard().copy();
|
||||||
|
rightHalfCard.setParentCard(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleFacedCardHalf getLeftHalfCard() {
|
||||||
|
return leftHalfCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DoubleFacedCardHalf getRightHalfCard() {
|
||||||
|
return leftHalfCard;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParts(DoubleFacedCardHalf leftHalfCard, DoubleFacedCardHalf rightHalfCard) {
|
||||||
|
// for card copy only - set new parts
|
||||||
|
this.leftHalfCard = leftHalfCard;
|
||||||
|
leftHalfCard.setParentCard(this);
|
||||||
|
this.rightHalfCard = rightHalfCard;
|
||||||
|
rightHalfCard.setParentCard(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void assignNewId() {
|
||||||
|
super.assignNewId();
|
||||||
|
leftHalfCard.assignNewId();
|
||||||
|
rightHalfCard.assignNewId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCopy(boolean isCopy, MageObject copiedFrom) {
|
||||||
|
super.setCopy(isCopy, copiedFrom);
|
||||||
|
leftHalfCard.setCopy(isCopy, copiedFrom);
|
||||||
|
rightHalfCard.setCopy(isCopy, copiedFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setSideZones(Zone mainZone, Game game) {
|
||||||
|
switch (mainZone) {
|
||||||
|
case BATTLEFIELD:
|
||||||
|
case STACK:
|
||||||
|
throw new IllegalArgumentException("Wrong code usage: you must put to battlefield/stack only real side card (half), not main");
|
||||||
|
default:
|
||||||
|
game.setZone(leftHalfCard.getId(), mainZone);
|
||||||
|
game.setZone(rightHalfCard.getId(), mainZone);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
checkGoodZones(game, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
|
||||||
|
if (super.moveToZone(toZone, source, game, flag, appliedEffects)) {
|
||||||
|
Zone currentZone = game.getState().getZone(getId());
|
||||||
|
setSideZones(currentZone, game);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setZone(Zone zone, Game game) {
|
||||||
|
super.setZone(zone, game);
|
||||||
|
setSideZones(zone, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List<UUID> appliedEffects) {
|
||||||
|
if (super.moveToExile(exileId, name, source, game, appliedEffects)) {
|
||||||
|
Zone currentZone = game.getState().getZone(getId());
|
||||||
|
setSideZones(currentZone, game);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runtime check for good zones and other MDF data
|
||||||
|
*/
|
||||||
|
public static void checkGoodZones(Game game, DoubleFacedCard card) {
|
||||||
|
Card leftPart = card.getLeftHalfCard();
|
||||||
|
Card rightPart = card.getRightHalfCard();
|
||||||
|
|
||||||
|
Zone zoneMain = game.getState().getZone(card.getId());
|
||||||
|
Zone zoneLeft = game.getState().getZone(leftPart.getId());
|
||||||
|
Zone zoneRight = game.getState().getZone(rightPart.getId());
|
||||||
|
|
||||||
|
// runtime check:
|
||||||
|
// * in battlefield and stack - card + one of the sides (another side in outside zone)
|
||||||
|
// * in other zones - card + both sides (need both sides due cost reductions, spell and other access before put to stack)
|
||||||
|
//
|
||||||
|
// 712.8a While a double-faced card is outside the game or in a zone other than the battlefield or stack,
|
||||||
|
// it has only the characteristics of its front face.
|
||||||
|
//
|
||||||
|
// 712.8f While a modal double-faced spell is on the stack or a modal double-faced permanent is on the battlefield,
|
||||||
|
// it has only the characteristics of the face that’s up.
|
||||||
|
Zone needZoneLeft;
|
||||||
|
Zone needZoneRight;
|
||||||
|
switch (zoneMain) {
|
||||||
|
case BATTLEFIELD:
|
||||||
|
case STACK:
|
||||||
|
if (zoneMain == zoneLeft) {
|
||||||
|
needZoneLeft = zoneMain;
|
||||||
|
needZoneRight = Zone.OUTSIDE;
|
||||||
|
} else if (zoneMain == zoneRight) {
|
||||||
|
needZoneLeft = Zone.OUTSIDE;
|
||||||
|
needZoneRight = zoneMain;
|
||||||
|
} else {
|
||||||
|
// impossible
|
||||||
|
needZoneLeft = zoneMain;
|
||||||
|
needZoneRight = Zone.OUTSIDE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
needZoneLeft = zoneMain;
|
||||||
|
needZoneRight = zoneMain;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zoneLeft != needZoneLeft || zoneRight != needZoneRight) {
|
||||||
|
throw new IllegalStateException("Wrong code usage: MDF card uses wrong zones - " + card
|
||||||
|
+ "\r\n" + String.format("* main zone: %s", zoneMain)
|
||||||
|
+ "\r\n" + String.format("* left side: need %s, actual %s", needZoneLeft, zoneLeft)
|
||||||
|
+ "\r\n" + String.format("* right side: need %s, actual %s", needZoneRight, zoneRight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean removeFromZone(Game game, Zone fromZone, Ability source) {
|
||||||
|
// zone contains only one main card
|
||||||
|
return super.removeFromZone(game, fromZone, source);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) {
|
||||||
|
if (isCopy()) { // same as meld cards
|
||||||
|
super.updateZoneChangeCounter(game, event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
super.updateZoneChangeCounter(game, event);
|
||||||
|
game.getState().updateZoneChangeCounter(leftHalfCard.getId());
|
||||||
|
game.getState().updateZoneChangeCounter(rightHalfCard.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Counters getCounters(Game game) {
|
||||||
|
return getCounters(game.getState());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Counters getCounters(GameState state) {
|
||||||
|
return state.getCardState(leftHalfCard.getId()).getCounters();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addCounters(Counter counter, UUID playerAddingCounters, Ability source, Game game, List<UUID> appliedEffects, boolean isEffect, int maxCounters) {
|
||||||
|
return leftHalfCard.addCounters(counter, playerAddingCounters, source, game, appliedEffects, isEffect, maxCounters);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void removeCounters(String counterName, int amount, Ability source, Game game) {
|
||||||
|
leftHalfCard.removeCounters(counterName, amount, source, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean cast(Game game, Zone fromZone, SpellAbility ability, UUID controllerId) {
|
||||||
|
if (this.leftHalfCard.getSpellAbility() != null) {
|
||||||
|
this.leftHalfCard.getSpellAbility().setControllerId(controllerId);
|
||||||
|
}
|
||||||
|
if (this.rightHalfCard.getSpellAbility() != null) {
|
||||||
|
this.rightHalfCard.getSpellAbility().setControllerId(controllerId);
|
||||||
|
}
|
||||||
|
return super.cast(game, fromZone, ability, controllerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<SuperType> getSuperType(Game game) {
|
||||||
|
// CardImpl's constructor can call some code on init, so you must check left/right before
|
||||||
|
// it's a bad workaround
|
||||||
|
return leftHalfCard != null ? leftHalfCard.getSuperType(game) : supertype;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<CardType> getCardType(Game game) {
|
||||||
|
// CardImpl's constructor can call some code on init, so you must check left/right before
|
||||||
|
// it's a bad workaround
|
||||||
|
return leftHalfCard != null ? leftHalfCard.getCardType(game) : cardType;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SubTypes getSubtype() {
|
||||||
|
// rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face.
|
||||||
|
// CardImpl's constructor can call some code on init, so you must check left/right before
|
||||||
|
return leftHalfCard != null ? leftHalfCard.getSubtype() : subtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SubTypes getSubtype(Game game) {
|
||||||
|
// rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face.
|
||||||
|
// CardImpl's constructor can call some code on init, so you must check left/right before
|
||||||
|
return leftHalfCard != null ? leftHalfCard.getSubtype(game) : subtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasSubtype(SubType subtype, Game game) {
|
||||||
|
return leftHalfCard.hasSubtype(subtype, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Abilities<Ability> getAbilities() {
|
||||||
|
return getInnerAbilities(true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Abilities<Ability> getInitAbilities() {
|
||||||
|
// must init only parent related abilities, spell card must be init separately
|
||||||
|
return getInnerAbilities(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Abilities<Ability> getSharedAbilities(Game game) {
|
||||||
|
// no shared abilities for mdf cards (e.g. must be left or right only)
|
||||||
|
return new AbilitiesImpl<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Abilities<Ability> getAbilities(Game game) {
|
||||||
|
return getInnerAbilities(game, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIgnoreDefaultAbility(Ability ability) {
|
||||||
|
// ignore default play/spell ability from main card (only halves are actual)
|
||||||
|
// default abilities added on card creation from card type and can't be skipped
|
||||||
|
|
||||||
|
// skip cast spell
|
||||||
|
if (ability instanceof SpellAbility) {
|
||||||
|
SpellAbilityType type = ((SpellAbility) ability).getSpellAbilityType();
|
||||||
|
return type == SpellAbilityType.MODAL || type == SpellAbilityType.TRANSFORMED;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip play land
|
||||||
|
return ability instanceof PlayLandAbility;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isIgnoreTransformSpellAbility(Ability ability) {
|
||||||
|
return ability instanceof SpellAbility && ((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.TRANSFORMED_RIGHT;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Abilities<Ability> getInnerAbilities(Game game, boolean showLeftSide, boolean showRightSide) {
|
||||||
|
Abilities<Ability> allAbilites = new AbilitiesImpl<>();
|
||||||
|
|
||||||
|
for (Ability ability : super.getAbilities(game)) {
|
||||||
|
if (isIgnoreDefaultAbility(ability)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
allAbilites.add(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showLeftSide) {
|
||||||
|
allAbilites.addAll(leftHalfCard.getAbilities(game));
|
||||||
|
}
|
||||||
|
if (showRightSide) {
|
||||||
|
for (Ability ability: rightHalfCard.getAbilities(game)) {
|
||||||
|
if (isIgnoreTransformSpellAbility(ability)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
allAbilites.add(ability);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allAbilites;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Abilities<Ability> getInnerAbilities(boolean showLeftSide, boolean showRightSide) {
|
||||||
|
Abilities<Ability> allAbilites = new AbilitiesImpl<>();
|
||||||
|
|
||||||
|
for (Ability ability : super.getAbilities()) {
|
||||||
|
if (isIgnoreDefaultAbility(ability)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
allAbilites.add(ability);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showLeftSide) {
|
||||||
|
allAbilites.addAll(leftHalfCard.getAbilities());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showRightSide) {
|
||||||
|
for (Ability ability: rightHalfCard.getAbilities()) {
|
||||||
|
if (isIgnoreTransformSpellAbility(ability)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
allAbilites.add(ability);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return allAbilites;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getRules() {
|
||||||
|
// rules must show only main side (another side visible by toggle/transform button in GUI)
|
||||||
|
// card hints from both sides
|
||||||
|
return CardUtil.getCardRulesWithAdditionalInfo(
|
||||||
|
this,
|
||||||
|
this.getInnerAbilities(true, false),
|
||||||
|
this.getInnerAbilities(true, true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> getRules(Game game) {
|
||||||
|
// rules must show only main side (another side visible by toggle/transform button in GUI)
|
||||||
|
// card hints from both sides
|
||||||
|
return CardUtil.getCardRulesWithAdditionalInfo(
|
||||||
|
game,
|
||||||
|
this,
|
||||||
|
this.getInnerAbilities(game, true, false),
|
||||||
|
this.getInnerAbilities(game, true, true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasAbility(Ability ability, Game game) {
|
||||||
|
return super.hasAbility(ability, game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectColor getColor() {
|
||||||
|
return leftHalfCard.getColor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectColor getColor(Game game) {
|
||||||
|
return leftHalfCard.getColor(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ObjectColor getFrameColor(Game game) {
|
||||||
|
return leftHalfCard.getFrameColor(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOwnerId(UUID ownerId) {
|
||||||
|
super.setOwnerId(ownerId);
|
||||||
|
abilities.setControllerId(ownerId);
|
||||||
|
leftHalfCard.getAbilities().setControllerId(ownerId);
|
||||||
|
leftHalfCard.setOwnerId(ownerId);
|
||||||
|
rightHalfCard.getAbilities().setControllerId(ownerId);
|
||||||
|
rightHalfCard.setOwnerId(ownerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ManaCosts<ManaCost> getManaCost() {
|
||||||
|
return leftHalfCard.getManaCost();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getManaValue() {
|
||||||
|
// Rules:
|
||||||
|
// The converted mana cost of a modal double-faced card is based on the characteristics of the
|
||||||
|
// face that’s being considered. On the stack and battlefield, consider whichever face is up.
|
||||||
|
// In all other zones, consider only the front face. This is different than how the converted
|
||||||
|
// mana cost of a transforming double-faced card is determined.
|
||||||
|
|
||||||
|
// on stack or battlefield it must be half card with own cost
|
||||||
|
return leftHalfCard.getManaValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MageInt getPower() {
|
||||||
|
return leftHalfCard.getPower();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MageInt getToughness() {
|
||||||
|
return leftHalfCard.getToughness();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,25 +1,25 @@
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
|
import mage.game.events.ZoneChangeEvent;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author JayDi85
|
* @author JayDi85 - originally from ModalDoubleFaceCardHalf
|
||||||
*/
|
*/
|
||||||
public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubleFacedCardHalf {
|
public abstract class DoubleFacedCardHalf extends CardImpl implements SubCard<DoubleFacedCard> {
|
||||||
|
|
||||||
ModalDoubleFacedCard parentCard;
|
protected DoubleFacedCard parentCard;
|
||||||
|
|
||||||
public ModalDoubleFacedCardHalfImpl(
|
public DoubleFacedCardHalf(
|
||||||
UUID ownerId, CardSetInfo setInfo,
|
UUID ownerId, CardSetInfo setInfo,
|
||||||
SuperType[] cardSuperTypes, CardType[] cardTypes, SubType[] cardSubTypes,
|
SuperType[] cardSuperTypes, CardType[] cardTypes, SubType[] cardSubTypes,
|
||||||
String costs, ModalDoubleFacedCard parentCard, SpellAbilityType spellAbilityType
|
String costs, DoubleFacedCard parentCard, SpellAbilityType spellAbilityType
|
||||||
) {
|
) {
|
||||||
super(ownerId, setInfo, cardTypes, costs, spellAbilityType);
|
super(ownerId, setInfo, cardTypes, costs, spellAbilityType);
|
||||||
this.supertype.addAll(Arrays.asList(cardSuperTypes));
|
this.supertype.addAll(Arrays.asList(cardSuperTypes));
|
||||||
|
|
@ -27,7 +27,7 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl
|
||||||
this.parentCard = parentCard;
|
this.parentCard = parentCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ModalDoubleFacedCardHalfImpl(final ModalDoubleFacedCardHalfImpl card) {
|
protected DoubleFacedCardHalf(final DoubleFacedCardHalf card) {
|
||||||
super(card);
|
super(card);
|
||||||
this.parentCard = card.parentCard;
|
this.parentCard = card.parentCard;
|
||||||
}
|
}
|
||||||
|
|
@ -49,6 +49,11 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl
|
||||||
return parentCard.getCardNumber();
|
return parentCard.getCardNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isTransformable() {
|
||||||
|
return getOtherSide().isPermanent();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
|
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
|
||||||
return parentCard.moveToZone(toZone, source, game, flag, appliedEffects);
|
return parentCard.moveToZone(toZone, source, game, flag, appliedEffects);
|
||||||
|
|
@ -65,25 +70,23 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModalDoubleFacedCard getMainCard() {
|
public Card getMainCard() {
|
||||||
return parentCard;
|
return parentCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) {
|
||||||
|
parentCard.updateZoneChangeCounter(game, event);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setZone(Zone zone, Game game) {
|
public void setZone(Zone zone, Game game) {
|
||||||
// see ModalDoubleFacedCard.checkGoodZones for details
|
// see DoubleFacedCard.checkGoodZones for details
|
||||||
game.setZone(parentCard.getId(), zone);
|
game.setZone(parentCard.getId(), zone);
|
||||||
game.setZone(this.getId(), zone);
|
game.setZone(this.getId(), zone);
|
||||||
|
|
||||||
// find another side to sync
|
// find another side to sync
|
||||||
ModalDoubleFacedCardHalf otherSide;
|
Card otherSide = getOtherSide();
|
||||||
if (!parentCard.getLeftHalfCard().getId().equals(this.getId())) {
|
|
||||||
otherSide = parentCard.getLeftHalfCard();
|
|
||||||
} else if (!parentCard.getRightHalfCard().getId().equals(this.getId())) {
|
|
||||||
otherSide = parentCard.getRightHalfCard();
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("Wrong code usage: MDF halves must use different ids");
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (zone) {
|
switch (zone) {
|
||||||
case STACK:
|
case STACK:
|
||||||
|
|
@ -96,33 +99,39 @@ public class ModalDoubleFacedCardHalfImpl extends CardImpl implements ModalDoubl
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModalDoubleFacedCard.checkGoodZones(game, parentCard);
|
DoubleFacedCard.checkGoodZones(game, parentCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Card getOtherSide() {
|
||||||
|
Card otherSide;
|
||||||
|
if (!parentCard.getLeftHalfCard().getId().equals(this.getId())) {
|
||||||
|
otherSide = parentCard.getLeftHalfCard();
|
||||||
|
} else if (!parentCard.getRightHalfCard().getId().equals(this.getId())) {
|
||||||
|
otherSide = parentCard.getRightHalfCard();
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Wrong code usage: MDF halves must use different ids");
|
||||||
|
}
|
||||||
|
return otherSide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBackSide() {
|
||||||
|
if (parentCard.getLeftHalfCard().getId().equals(this.getId())) {
|
||||||
|
return false;
|
||||||
|
} else if (parentCard.getRightHalfCard().getId().equals(this.getId())) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Wrong code usage: MDF halves must use different ids");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModalDoubleFacedCardHalfImpl copy() {
|
public void setParentCard(DoubleFacedCard card) {
|
||||||
return new ModalDoubleFacedCardHalfImpl(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setParentCard(ModalDoubleFacedCard card) {
|
|
||||||
this.parentCard = card;
|
this.parentCard = card;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ModalDoubleFacedCard getParentCard() {
|
public DoubleFacedCard getParentCard() {
|
||||||
return this.parentCard;
|
return parentCard;
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPT(int power, int toughness) {
|
|
||||||
this.setPT(new MageInt(power), new MageInt(toughness));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setPT(MageInt power, MageInt toughness) {
|
|
||||||
this.power = power;
|
|
||||||
this.toughness = toughness;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -1,30 +1,15 @@
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
import mage.MageInt;
|
|
||||||
import mage.MageObject;
|
|
||||||
import mage.ObjectColor;
|
|
||||||
import mage.abilities.*;
|
import mage.abilities.*;
|
||||||
import mage.abilities.costs.mana.ManaCost;
|
|
||||||
import mage.abilities.costs.mana.ManaCosts;
|
|
||||||
import mage.constants.*;
|
import mage.constants.*;
|
||||||
import mage.counters.Counter;
|
|
||||||
import mage.counters.Counters;
|
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.GameState;
|
|
||||||
import mage.game.events.ZoneChangeEvent;
|
|
||||||
import mage.util.CardUtil;
|
|
||||||
import mage.util.SubTypes;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author JayDi85
|
* @author JayDi85
|
||||||
*/
|
*/
|
||||||
public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithHalves {
|
public abstract class ModalDoubleFacedCard extends DoubleFacedCard {
|
||||||
|
|
||||||
protected Card leftHalfCard; // main card in all zone
|
|
||||||
protected Card rightHalfCard; // second side card, can be only in stack and battlefield zones
|
|
||||||
|
|
||||||
public ModalDoubleFacedCard(
|
public ModalDoubleFacedCard(
|
||||||
UUID ownerId, CardSetInfo setInfo,
|
UUID ownerId, CardSetInfo setInfo,
|
||||||
|
|
@ -48,184 +33,21 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH
|
||||||
) {
|
) {
|
||||||
super(ownerId, setInfo, typesLeft, costsLeft + costsRight, SpellAbilityType.MODAL);
|
super(ownerId, setInfo, typesLeft, costsLeft + costsRight, SpellAbilityType.MODAL);
|
||||||
// main card name must be same as left side
|
// main card name must be same as left side
|
||||||
leftHalfCard = new ModalDoubleFacedCardHalfImpl(
|
leftHalfCard = new ModalDoubleFacedCardHalf(
|
||||||
this.getOwnerId(), setInfo.copy(),
|
this.getOwnerId(), setInfo.copy(),
|
||||||
superTypesLeft, typesLeft, subTypesLeft, costsLeft,
|
superTypesLeft, typesLeft, subTypesLeft, costsLeft,
|
||||||
this, SpellAbilityType.MODAL_LEFT
|
this, SpellAbilityType.MODAL_LEFT
|
||||||
);
|
);
|
||||||
rightHalfCard = new ModalDoubleFacedCardHalfImpl(
|
rightHalfCard = new ModalDoubleFacedCardHalf(
|
||||||
this.getOwnerId(), new CardSetInfo(secondSideName, setInfo),
|
this.getOwnerId(), new CardSetInfo(secondSideName, setInfo),
|
||||||
superTypesRight, typesRight, subTypesRight, costsRight,
|
superTypesRight, typesRight, subTypesRight, costsRight,
|
||||||
this, SpellAbilityType.MODAL_RIGHT
|
this, SpellAbilityType.MODAL_RIGHT
|
||||||
);
|
);
|
||||||
|
this.secondSideCard = rightHalfCard;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ModalDoubleFacedCard(ModalDoubleFacedCard card) {
|
public ModalDoubleFacedCard(final ModalDoubleFacedCard card) {
|
||||||
super(card);
|
super(card);
|
||||||
// make sure all parts created and parent ref added
|
|
||||||
this.leftHalfCard = card.getLeftHalfCard().copy();
|
|
||||||
((ModalDoubleFacedCardHalf) leftHalfCard).setParentCard(this);
|
|
||||||
this.rightHalfCard = card.rightHalfCard.copy();
|
|
||||||
((ModalDoubleFacedCardHalf) rightHalfCard).setParentCard(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModalDoubleFacedCardHalf getLeftHalfCard() {
|
|
||||||
return (ModalDoubleFacedCardHalf) leftHalfCard;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModalDoubleFacedCardHalf getRightHalfCard() {
|
|
||||||
return (ModalDoubleFacedCardHalf) rightHalfCard;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setParts(ModalDoubleFacedCardHalf leftHalfCard, ModalDoubleFacedCardHalf rightHalfCard) {
|
|
||||||
// for card copy only - set new parts
|
|
||||||
this.leftHalfCard = leftHalfCard;
|
|
||||||
leftHalfCard.setParentCard(this);
|
|
||||||
this.rightHalfCard = rightHalfCard;
|
|
||||||
rightHalfCard.setParentCard(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void assignNewId() {
|
|
||||||
super.assignNewId();
|
|
||||||
leftHalfCard.assignNewId();
|
|
||||||
rightHalfCard.assignNewId();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setCopy(boolean isCopy, MageObject copiedFrom) {
|
|
||||||
super.setCopy(isCopy, copiedFrom);
|
|
||||||
leftHalfCard.setCopy(isCopy, copiedFrom); // TODO: must check copiedFrom and assign sides? (??? related to #8476 ???)
|
|
||||||
rightHalfCard.setCopy(isCopy, copiedFrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setSideZones(Zone mainZone, Game game) {
|
|
||||||
switch (mainZone) {
|
|
||||||
case BATTLEFIELD:
|
|
||||||
case STACK:
|
|
||||||
throw new IllegalArgumentException("Wrong code usage: you must put to battlefield/stack only real side card (half), not main");
|
|
||||||
default:
|
|
||||||
// must keep both sides in same zone cause xmage need access to cost reduction, spell
|
|
||||||
// and other abilities before put it to stack (in playable calcs)
|
|
||||||
game.setZone(leftHalfCard.getId(), mainZone);
|
|
||||||
game.setZone(rightHalfCard.getId(), mainZone);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
checkGoodZones(game, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean moveToZone(Zone toZone, Ability source, Game game, boolean flag, List<UUID> appliedEffects) {
|
|
||||||
if (super.moveToZone(toZone, source, game, flag, appliedEffects)) {
|
|
||||||
Zone currentZone = game.getState().getZone(getId());
|
|
||||||
setSideZones(currentZone, game);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setZone(Zone zone, Game game) {
|
|
||||||
super.setZone(zone, game);
|
|
||||||
setSideZones(zone, game);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean moveToExile(UUID exileId, String name, Ability source, Game game, List<UUID> appliedEffects) {
|
|
||||||
if (super.moveToExile(exileId, name, source, game, appliedEffects)) {
|
|
||||||
Zone currentZone = game.getState().getZone(getId());
|
|
||||||
setSideZones(currentZone, game);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime check for good zones and other MDF data
|
|
||||||
*/
|
|
||||||
public static void checkGoodZones(Game game, ModalDoubleFacedCard card) {
|
|
||||||
Card leftPart = card.getLeftHalfCard();
|
|
||||||
Card rightPart = card.getRightHalfCard();
|
|
||||||
|
|
||||||
Zone zoneMain = game.getState().getZone(card.getId());
|
|
||||||
Zone zoneLeft = game.getState().getZone(leftPart.getId());
|
|
||||||
Zone zoneRight = game.getState().getZone(rightPart.getId());
|
|
||||||
|
|
||||||
// runtime check:
|
|
||||||
// * in battlefield and stack - card + one of the sides (another side in outside zone)
|
|
||||||
// * in other zones - card + both sides (need both sides due cost reductions, spell and other access before put to stack)
|
|
||||||
//
|
|
||||||
// 712.8a While a double-faced card is outside the game or in a zone other than the battlefield or stack,
|
|
||||||
// it has only the characteristics of its front face.
|
|
||||||
//
|
|
||||||
// 712.8f While a modal double-faced spell is on the stack or a modal double-faced permanent is on the battlefield,
|
|
||||||
// it has only the characteristics of the face that’s up.
|
|
||||||
Zone needZoneLeft;
|
|
||||||
Zone needZoneRight;
|
|
||||||
switch (zoneMain) {
|
|
||||||
case BATTLEFIELD:
|
|
||||||
case STACK:
|
|
||||||
if (zoneMain == zoneLeft) {
|
|
||||||
needZoneLeft = zoneMain;
|
|
||||||
needZoneRight = Zone.OUTSIDE;
|
|
||||||
} else if (zoneMain == zoneRight) {
|
|
||||||
needZoneLeft = Zone.OUTSIDE;
|
|
||||||
needZoneRight = zoneMain;
|
|
||||||
} else {
|
|
||||||
// impossible
|
|
||||||
needZoneLeft = zoneMain;
|
|
||||||
needZoneRight = Zone.OUTSIDE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
needZoneLeft = zoneMain;
|
|
||||||
needZoneRight = zoneMain;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zoneLeft != needZoneLeft || zoneRight != needZoneRight) {
|
|
||||||
throw new IllegalStateException("Wrong code usage: MDF card uses wrong zones - " + card
|
|
||||||
+ "\r\n" + String.format("* main zone: %s", zoneMain)
|
|
||||||
+ "\r\n" + String.format("* left side: need %s, actual %s", needZoneLeft, zoneLeft)
|
|
||||||
+ "\r\n" + String.format("* right side: need %s, actual %s", needZoneRight, zoneRight));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean removeFromZone(Game game, Zone fromZone, Ability source) {
|
|
||||||
// zone contains only one main card
|
|
||||||
return super.removeFromZone(game, fromZone, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void updateZoneChangeCounter(Game game, ZoneChangeEvent event) {
|
|
||||||
if (isCopy()) { // same as meld cards
|
|
||||||
super.updateZoneChangeCounter(game, event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.updateZoneChangeCounter(game, event);
|
|
||||||
leftHalfCard.updateZoneChangeCounter(game, event);
|
|
||||||
rightHalfCard.updateZoneChangeCounter(game, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Counters getCounters(Game game) {
|
|
||||||
return getCounters(game.getState());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Counters getCounters(GameState state) {
|
|
||||||
return state.getCardState(leftHalfCard.getId()).getCounters();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean addCounters(Counter counter, UUID playerAddingCounters, Ability source, Game game, List<UUID> appliedEffects, boolean isEffect, int maxCounters) {
|
|
||||||
return leftHalfCard.addCounters(counter, playerAddingCounters, source, game, appliedEffects, isEffect, maxCounters);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeCounters(String counterName, int amount, Ability source, Game game) {
|
|
||||||
leftHalfCard.removeCounters(counterName, amount, source, game);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -236,201 +58,22 @@ public abstract class ModalDoubleFacedCard extends CardImpl implements CardWithH
|
||||||
case MODAL_RIGHT:
|
case MODAL_RIGHT:
|
||||||
return this.rightHalfCard.cast(game, fromZone, ability, controllerId);
|
return this.rightHalfCard.cast(game, fromZone, ability, controllerId);
|
||||||
default:
|
default:
|
||||||
if (this.leftHalfCard.getSpellAbility() != null) {
|
|
||||||
this.leftHalfCard.getSpellAbility().setControllerId(controllerId);
|
|
||||||
}
|
|
||||||
if (this.rightHalfCard.getSpellAbility() != null) {
|
|
||||||
this.rightHalfCard.getSpellAbility().setControllerId(controllerId);
|
|
||||||
}
|
|
||||||
return super.cast(game, fromZone, ability, controllerId);
|
return super.cast(game, fromZone, ability, controllerId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SuperType> getSuperType(Game game) {
|
public boolean isTransformable() {
|
||||||
// CardImpl's constructor can call some code on init, so you must check left/right before
|
return this.getLeftHalfCard().isPermanent() && this.getRightHalfCard().isPermanent();
|
||||||
// it's a bad workaround
|
|
||||||
return leftHalfCard != null ? leftHalfCard.getSuperType(game) : supertype;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CardType> getCardType(Game game) {
|
public ModalDoubleFacedCardHalf getLeftHalfCard() {
|
||||||
// CardImpl's constructor can call some code on init, so you must check left/right before
|
return (ModalDoubleFacedCardHalf) leftHalfCard;
|
||||||
// it's a bad workaround
|
|
||||||
return leftHalfCard != null ? leftHalfCard.getCardType(game) : cardType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SubTypes getSubtype() {
|
public ModalDoubleFacedCardHalf getRightHalfCard() {
|
||||||
// rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face.
|
return (ModalDoubleFacedCardHalf) rightHalfCard;
|
||||||
// CardImpl's constructor can call some code on init, so you must check left/right before
|
|
||||||
return leftHalfCard != null ? leftHalfCard.getSubtype() : subtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public SubTypes getSubtype(Game game) {
|
|
||||||
// rules: While a double-faced card isn’t on the stack or battlefield, consider only the characteristics of its front face.
|
|
||||||
// CardImpl's constructor can call some code on init, so you must check left/right before
|
|
||||||
return leftHalfCard != null ? leftHalfCard.getSubtype(game) : subtype;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasSubtype(SubType subtype, Game game) {
|
|
||||||
return leftHalfCard.hasSubtype(subtype, game);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Abilities<Ability> getAbilities() {
|
|
||||||
return getInnerAbilities(true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Abilities<Ability> getInitAbilities() {
|
|
||||||
// must init only parent related abilities, spell card must be init separately
|
|
||||||
return getInnerAbilities(false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Abilities<Ability> getSharedAbilities(Game game) {
|
|
||||||
// no shared abilities for mdf cards (e.g. must be left or right only)
|
|
||||||
return new AbilitiesImpl<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Abilities<Ability> getAbilities(Game game) {
|
|
||||||
return getInnerAbilities(game, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isIgnoreDefaultAbility(Ability ability) {
|
|
||||||
// ignore default play/spell ability from main card (only halfes are actual)
|
|
||||||
// default abilities added on card creation from card type and can't be skipped
|
|
||||||
|
|
||||||
// skip cast spell
|
|
||||||
if (ability instanceof SpellAbility && ((SpellAbility) ability).getSpellAbilityType() == SpellAbilityType.MODAL) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// skip play land
|
|
||||||
return ability instanceof PlayLandAbility;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Abilities<Ability> getInnerAbilities(Game game, boolean showLeftSide, boolean showRightSide) {
|
|
||||||
Abilities<Ability> allAbilites = new AbilitiesImpl<>();
|
|
||||||
|
|
||||||
for (Ability ability : super.getAbilities(game)) {
|
|
||||||
if (isIgnoreDefaultAbility(ability)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
allAbilites.add(ability);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showLeftSide) {
|
|
||||||
allAbilites.addAll(leftHalfCard.getAbilities(game));
|
|
||||||
}
|
|
||||||
if (showRightSide) {
|
|
||||||
allAbilites.addAll(rightHalfCard.getAbilities(game));
|
|
||||||
}
|
|
||||||
|
|
||||||
return allAbilites;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Abilities<Ability> getInnerAbilities(boolean showLeftSide, boolean showRightSide) {
|
|
||||||
Abilities<Ability> allAbilites = new AbilitiesImpl<>();
|
|
||||||
|
|
||||||
for (Ability ability : super.getAbilities()) {
|
|
||||||
if (isIgnoreDefaultAbility(ability)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
allAbilites.add(ability);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showLeftSide) {
|
|
||||||
allAbilites.addAll(leftHalfCard.getAbilities());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (showRightSide) {
|
|
||||||
allAbilites.addAll(rightHalfCard.getAbilities());
|
|
||||||
}
|
|
||||||
|
|
||||||
return allAbilites;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> getRules() {
|
|
||||||
// rules must show only main side (another side visible by toggle/transform button in GUI)
|
|
||||||
// card hints from both sides
|
|
||||||
return CardUtil.getCardRulesWithAdditionalInfo(
|
|
||||||
this,
|
|
||||||
this.getInnerAbilities(true, false),
|
|
||||||
this.getInnerAbilities(true, true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> getRules(Game game) {
|
|
||||||
// rules must show only main side (another side visible by toggle/transform button in GUI)
|
|
||||||
// card hints from both sides
|
|
||||||
return CardUtil.getCardRulesWithAdditionalInfo(
|
|
||||||
game,
|
|
||||||
this,
|
|
||||||
this.getInnerAbilities(game, true, false),
|
|
||||||
this.getInnerAbilities(game, true, true)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean hasAbility(Ability ability, Game game) {
|
|
||||||
return super.hasAbility(ability, game);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObjectColor getColor() {
|
|
||||||
return leftHalfCard.getColor();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObjectColor getColor(Game game) {
|
|
||||||
return leftHalfCard.getColor(game);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ObjectColor getFrameColor(Game game) {
|
|
||||||
return leftHalfCard.getFrameColor(game);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOwnerId(UUID ownerId) {
|
|
||||||
super.setOwnerId(ownerId);
|
|
||||||
abilities.setControllerId(ownerId);
|
|
||||||
leftHalfCard.getAbilities().setControllerId(ownerId);
|
|
||||||
leftHalfCard.setOwnerId(ownerId);
|
|
||||||
rightHalfCard.getAbilities().setControllerId(ownerId);
|
|
||||||
rightHalfCard.setOwnerId(ownerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ManaCosts<ManaCost> getManaCost() {
|
|
||||||
return leftHalfCard.getManaCost();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getManaValue() {
|
|
||||||
// Rules:
|
|
||||||
// The converted mana cost of a modal double-faced card is based on the characteristics of the
|
|
||||||
// face that’s being considered. On the stack and battlefield, consider whichever face is up.
|
|
||||||
// In all other zones, consider only the front face. This is different than how the converted
|
|
||||||
// mana cost of a transforming double-faced card is determined.
|
|
||||||
|
|
||||||
// on stack or battlefield it must be half card with own cost
|
|
||||||
return leftHalfCard.getManaValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MageInt getPower() {
|
|
||||||
return leftHalfCard.getPower();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public MageInt getToughness() {
|
|
||||||
return leftHalfCard.getToughness();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,34 @@
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
import mage.MageInt;
|
import mage.constants.CardType;
|
||||||
|
import mage.constants.SpellAbilityType;
|
||||||
|
import mage.constants.SubType;
|
||||||
|
import mage.constants.SuperType;
|
||||||
|
|
||||||
/**
|
import java.util.UUID;
|
||||||
* @author JayDi85
|
|
||||||
*/
|
public class ModalDoubleFacedCardHalf extends DoubleFacedCardHalf {
|
||||||
public interface ModalDoubleFacedCardHalf extends SubCard<ModalDoubleFacedCard> {
|
|
||||||
|
public ModalDoubleFacedCardHalf(
|
||||||
|
UUID ownerId, CardSetInfo setInfo,
|
||||||
|
SuperType[] cardSuperTypes, CardType[] cardTypes, SubType[] cardSubTypes,
|
||||||
|
String costs, ModalDoubleFacedCard parentCard, SpellAbilityType spellAbilityType
|
||||||
|
) {
|
||||||
|
super(ownerId, setInfo, cardSuperTypes, cardTypes, cardSubTypes, costs, parentCard, spellAbilityType);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ModalDoubleFacedCardHalf(final ModalDoubleFacedCardHalf card) {
|
||||||
|
super(card);
|
||||||
|
this.parentCard = card.parentCard;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
ModalDoubleFacedCardHalf copy();
|
public ModalDoubleFacedCardHalf copy() {
|
||||||
|
return new ModalDoubleFacedCardHalf(this);
|
||||||
|
}
|
||||||
|
|
||||||
void setPT(int power, int toughness);
|
@Override
|
||||||
|
public ModalDoubleFacedCard getParentCard() {
|
||||||
void setPT(MageInt power, MageInt toughness);
|
return (ModalDoubleFacedCard) parentCard;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,20 @@
|
||||||
package mage.cards;
|
package mage.cards;
|
||||||
|
|
||||||
import java.util.UUID;
|
import mage.ObjectColor;
|
||||||
|
|
||||||
import mage.abilities.Abilities;
|
import mage.abilities.Abilities;
|
||||||
import mage.abilities.Ability;
|
import mage.abilities.Ability;
|
||||||
import mage.abilities.common.EntersBattlefieldAbility;
|
import mage.abilities.common.EntersBattlefieldAbility;
|
||||||
import mage.abilities.common.RoomUnlockAbility;
|
import mage.abilities.common.RoomAbility;
|
||||||
import mage.abilities.common.SimpleStaticAbility;
|
|
||||||
import mage.abilities.common.UnlockThisDoorTriggeredAbility;
|
|
||||||
import mage.abilities.condition.common.RoomHalfLockedCondition;
|
|
||||||
import mage.abilities.costs.mana.ManaCosts;
|
|
||||||
import mage.abilities.decorator.ConditionalContinuousEffect;
|
|
||||||
import mage.abilities.effects.OneShotEffect;
|
import mage.abilities.effects.OneShotEffect;
|
||||||
import mage.abilities.effects.common.RoomCharacteristicsEffect;
|
|
||||||
import mage.constants.CardType;
|
import mage.constants.CardType;
|
||||||
import mage.constants.Duration;
|
|
||||||
import mage.constants.Outcome;
|
import mage.constants.Outcome;
|
||||||
import mage.constants.SpellAbilityType;
|
import mage.constants.SpellAbilityType;
|
||||||
import mage.constants.Zone;
|
import mage.constants.Zone;
|
||||||
import mage.game.Game;
|
import mage.game.Game;
|
||||||
import mage.game.permanent.Permanent;
|
import mage.game.permanent.Permanent;
|
||||||
import mage.game.permanent.PermanentToken;
|
import mage.game.permanent.PermanentToken;
|
||||||
import mage.abilities.effects.common.continuous.LoseAbilitySourceEffect;
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author oscscull
|
* @author oscscull
|
||||||
|
|
@ -43,6 +36,13 @@ public abstract class RoomCard extends SplitCard {
|
||||||
this.getOwnerId(), new CardSetInfo(names[1], setInfo.getExpansionSetCode(), setInfo.getCardNumber(),
|
this.getOwnerId(), new CardSetInfo(names[1], setInfo.getExpansionSetCode(), setInfo.getCardNumber(),
|
||||||
setInfo.getRarity(), setInfo.getGraphicInfo()),
|
setInfo.getRarity(), setInfo.getGraphicInfo()),
|
||||||
types, costsRight, this, SpellAbilityType.SPLIT_RIGHT);
|
types, costsRight, this, SpellAbilityType.SPLIT_RIGHT);
|
||||||
|
|
||||||
|
// Add the one-shot effect to unlock a door on cast -> ETB
|
||||||
|
Ability entersAbility = new EntersBattlefieldAbility(new RoomEnterUnlockEffect());
|
||||||
|
entersAbility.setRuleVisible(false);
|
||||||
|
this.addAbility(entersAbility);
|
||||||
|
|
||||||
|
this.addAbility(new RoomAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected RoomCard(RoomCard card) {
|
protected RoomCard(RoomCard card) {
|
||||||
|
|
@ -58,56 +58,6 @@ public abstract class RoomCard extends SplitCard {
|
||||||
this.lastCastHalf = lastCastHalf;
|
this.lastCastHalf = lastCastHalf;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addRoomAbilities(Ability leftAbility, Ability rightAbility) {
|
|
||||||
getLeftHalfCard().addAbility(leftAbility);
|
|
||||||
getRightHalfCard().addAbility(rightAbility);
|
|
||||||
this.addAbility(leftAbility.copy());
|
|
||||||
this.addAbility(rightAbility.copy());
|
|
||||||
|
|
||||||
// Add the one-shot effect to unlock a door on cast -> ETB
|
|
||||||
Ability entersAbility = new EntersBattlefieldAbility(new RoomEnterUnlockEffect());
|
|
||||||
entersAbility.setRuleVisible(false);
|
|
||||||
this.addAbility(entersAbility);
|
|
||||||
|
|
||||||
// Remove locked door abilities - keeping unlock triggers (or they won't trigger
|
|
||||||
// when unlocked)
|
|
||||||
if (leftAbility != null && !(leftAbility instanceof UnlockThisDoorTriggeredAbility)) {
|
|
||||||
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
|
|
||||||
new LoseAbilitySourceEffect(leftAbility, Duration.WhileOnBattlefield),
|
|
||||||
RoomHalfLockedCondition.LEFT, "")).setRuleVisible(false);
|
|
||||||
this.addAbility(ability);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rightAbility != null && !(rightAbility instanceof UnlockThisDoorTriggeredAbility)) {
|
|
||||||
Ability ability = new SimpleStaticAbility(Zone.BATTLEFIELD, new ConditionalContinuousEffect(
|
|
||||||
new LoseAbilitySourceEffect(rightAbility, Duration.WhileOnBattlefield),
|
|
||||||
RoomHalfLockedCondition.RIGHT, "")).setRuleVisible(false);
|
|
||||||
this.addAbility(ability);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the Special Action to unlock doors.
|
|
||||||
// These will ONLY be active if the corresponding half is LOCKED!
|
|
||||||
if (leftAbility != null) {
|
|
||||||
ManaCosts leftHalfManaCost = null;
|
|
||||||
if (this.getLeftHalfCard() != null && this.getLeftHalfCard().getSpellAbility() != null) {
|
|
||||||
leftHalfManaCost = this.getLeftHalfCard().getSpellAbility().getManaCosts();
|
|
||||||
}
|
|
||||||
RoomUnlockAbility leftUnlockAbility = new RoomUnlockAbility(leftHalfManaCost, true);
|
|
||||||
this.addAbility(leftUnlockAbility.setRuleAtTheTop(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rightAbility != null) {
|
|
||||||
ManaCosts rightHalfManaCost = null;
|
|
||||||
if (this.getRightHalfCard() != null && this.getRightHalfCard().getSpellAbility() != null) {
|
|
||||||
rightHalfManaCost = this.getRightHalfCard().getSpellAbility().getManaCosts();
|
|
||||||
}
|
|
||||||
RoomUnlockAbility rightUnlockAbility = new RoomUnlockAbility(rightHalfManaCost, false);
|
|
||||||
this.addAbility(rightUnlockAbility.setRuleAtTheTop(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addAbility(new RoomAbility());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Abilities<Ability> getAbilities() {
|
public Abilities<Ability> getAbilities() {
|
||||||
return this.abilities;
|
return this.abilities;
|
||||||
|
|
@ -131,6 +81,41 @@ public abstract class RoomCard extends SplitCard {
|
||||||
game.setZone(getLeftHalfCard().getId(), zone);
|
game.setZone(getLeftHalfCard().getId(), zone);
|
||||||
game.setZone(getRightHalfCard().getId(), zone);
|
game.setZone(getRightHalfCard().getId(), zone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void setRoomCharacteristics(Permanent permanent, Game game) {
|
||||||
|
if (!(permanent.getMainCard() instanceof RoomCard)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setRoomCharacteristics(permanent, (RoomCard) permanent.getMainCard(), game, permanent.isLeftDoorUnlocked(), permanent.isRightDoorUnlocked());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static method for setting room characteristics on permanents
|
||||||
|
public static void setRoomCharacteristics(Permanent permanent, RoomCard roomCard, Game game, boolean isLeftUnlocked, boolean isRightUnlocked) {
|
||||||
|
permanent.setName(roomCard.name);
|
||||||
|
|
||||||
|
permanent.setManaCost(roomCard.getManaCost());
|
||||||
|
|
||||||
|
// Set color indicator based on unlocked halves
|
||||||
|
ObjectColor newColor = new ObjectColor();
|
||||||
|
if (isLeftUnlocked && roomCard.getLeftHalfCard() != null) {
|
||||||
|
newColor.addColor(roomCard.getLeftHalfCard().getColor());
|
||||||
|
}
|
||||||
|
if (isRightUnlocked && roomCard.getRightHalfCard() != null) {
|
||||||
|
newColor.addColor(roomCard.getRightHalfCard().getColor());
|
||||||
|
}
|
||||||
|
permanent.getColor().setColor(roomCard.getColor());
|
||||||
|
|
||||||
|
// Get abilities from each half
|
||||||
|
Abilities<Ability> leftAbilities = roomCard.getLeftHalfCard().getAbilities();
|
||||||
|
for (Ability ability : leftAbilities) {
|
||||||
|
permanent.addAbility(ability, roomCard.getLeftHalfCard().getId(), game, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Abilities<Ability> rightAbilities = roomCard.getRightHalfCard().getAbilities();
|
||||||
|
for (Ability ability : rightAbilities) {
|
||||||
|
permanent.addAbility(ability, roomCard.getRightHalfCard().getId(), game,true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RoomEnterUnlockEffect extends OneShotEffect {
|
class RoomEnterUnlockEffect extends OneShotEffect {
|
||||||
|
|
@ -189,27 +174,3 @@ class RoomEnterUnlockEffect extends OneShotEffect {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the overall Room card flavor text and mana value effect.
|
|
||||||
class RoomAbility extends SimpleStaticAbility {
|
|
||||||
public RoomAbility() {
|
|
||||||
super(Zone.ALL, null);
|
|
||||||
this.setRuleVisible(true);
|
|
||||||
this.setRuleAtTheTop(true);
|
|
||||||
this.addEffect(new RoomCharacteristicsEffect());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected RoomAbility(final RoomAbility ability) {
|
|
||||||
super(ability);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getRule() {
|
|
||||||
return "<i>(You may cast either half. That door unlocks on the battlefield. " +
|
|
||||||
"As a sorcery, you may pay the mana cost of a locked door to unlock it.)</i>";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public RoomAbility copy() {
|
|
||||||
return new RoomAbility(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue