mirror of
https://github.com/Card-Forge/forge.git
synced 2025-11-15 02:08:00 +00:00
Resolve "ZNR: Modal Double Faced Cards"
This commit is contained in:
@@ -1856,7 +1856,7 @@ public class ComputerUtilCard {
|
||||
|
||||
public static AiPlayDecision checkNeedsToPlayReqs(final Card card, final SpellAbility sa) {
|
||||
Game game = card.getGame();
|
||||
boolean isRightSplit = sa != null && sa.isRightSplit();
|
||||
boolean isRightSplit = sa != null && sa.getCardState() != null;
|
||||
String needsToPlayName = isRightSplit ? "SplitNeedsToPlay" : "NeedsToPlay";
|
||||
String needsToPlayVarName = isRightSplit ? "SplitNeedsToPlayVar" : "NeedsToPlayVar";
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@ public enum CardSplitType
|
||||
Meld(FaceSelectionMethod.USE_ACTIVE_FACE, CardStateName.Meld),
|
||||
Split(FaceSelectionMethod.COMBINE, CardStateName.RightSplit),
|
||||
Flip(FaceSelectionMethod.USE_PRIMARY_FACE, CardStateName.Flipped),
|
||||
Adventure(FaceSelectionMethod.USE_PRIMARY_FACE, CardStateName.Adventure);
|
||||
Adventure(FaceSelectionMethod.USE_PRIMARY_FACE, CardStateName.Adventure),
|
||||
Modal(FaceSelectionMethod.USE_ACTIVE_FACE, CardStateName.Modal);
|
||||
|
||||
CardSplitType(FaceSelectionMethod calcMode, CardStateName stateName) {
|
||||
method = calcMode;
|
||||
|
||||
@@ -10,6 +10,7 @@ public enum CardStateName {
|
||||
LeftSplit,
|
||||
RightSplit,
|
||||
Adventure,
|
||||
Modal
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -532,7 +532,12 @@ public class BoosterGenerator {
|
||||
|
||||
Predicate<PaperCard> toAdd = null;
|
||||
if (operator.equalsIgnoreCase(BoosterSlots.DUAL_FACED_CARD)) {
|
||||
toAdd = Predicates.compose(Predicates.or(CardRulesPredicates.splitType(CardSplitType.Transform), CardRulesPredicates.splitType(CardSplitType.Meld)),
|
||||
toAdd = Predicates.compose(
|
||||
Predicates.or(
|
||||
CardRulesPredicates.splitType(CardSplitType.Transform),
|
||||
CardRulesPredicates.splitType(CardSplitType.Meld),
|
||||
CardRulesPredicates.splitType(CardSplitType.Modal)
|
||||
),
|
||||
PaperCard.FN_GET_RULES);
|
||||
} else if (operator.equalsIgnoreCase(BoosterSlots.LAND)) { toAdd = Predicates.compose(CardRulesPredicates.Presets.IS_LAND, PaperCard.FN_GET_RULES);
|
||||
} else if (operator.equalsIgnoreCase(BoosterSlots.BASIC_LAND)) { toAdd = IPaperCard.Predicates.Presets.IS_BASIC_LAND;
|
||||
|
||||
@@ -81,7 +81,7 @@ public class ImageUtil {
|
||||
|
||||
public static boolean hasBackFacePicture(PaperCard cp) {
|
||||
CardSplitType cst = cp.getRules().getSplitType();
|
||||
return cst == CardSplitType.Transform || cst == CardSplitType.Flip || cst == CardSplitType.Meld;
|
||||
return cst == CardSplitType.Transform || cst == CardSplitType.Flip || cst == CardSplitType.Meld || cst == CardSplitType.Modal;
|
||||
}
|
||||
|
||||
public static String getNameToUse(PaperCard cp, boolean backFace) {
|
||||
|
||||
@@ -338,28 +338,14 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
public CardStateName getAlternateStateName() {
|
||||
if (hasAlternateState()) {
|
||||
if (isSplitCard()) {
|
||||
if (currentStateName == CardStateName.RightSplit) {
|
||||
return CardStateName.LeftSplit;
|
||||
}
|
||||
else {
|
||||
return CardStateName.RightSplit;
|
||||
return currentStateName == CardStateName.RightSplit ? CardStateName.LeftSplit : CardStateName.RightSplit;
|
||||
} else if (getRules() != null) {
|
||||
CardStateName changedState = getRules().getSplitType().getChangedStateName();
|
||||
if (currentStateName != changedState) {
|
||||
return changedState;
|
||||
}
|
||||
}
|
||||
else if (isFlipCard() && currentStateName != CardStateName.Flipped) {
|
||||
return CardStateName.Flipped;
|
||||
}
|
||||
else if (isDoubleFaced() && currentStateName != CardStateName.Transformed) {
|
||||
return CardStateName.Transformed;
|
||||
}
|
||||
else if (isMeldable() && currentStateName != CardStateName.Meld) {
|
||||
return CardStateName.Meld;
|
||||
}
|
||||
else if (this.isAdventureCard() && currentStateName != CardStateName.Adventure) {
|
||||
return CardStateName.Adventure;
|
||||
}
|
||||
else {
|
||||
return CardStateName.Original;
|
||||
}
|
||||
return CardStateName.Original;
|
||||
}
|
||||
else if (isFaceDown()) {
|
||||
return CardStateName.Original;
|
||||
@@ -642,7 +628,7 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
}
|
||||
|
||||
public boolean turnFaceDown(boolean override) {
|
||||
if (override || (!isDoubleFaced() && !isMeldable())) {
|
||||
if (override || !hasBackSide()) {
|
||||
facedown = true;
|
||||
if (setState(CardStateName.FaceDown, true)) {
|
||||
runFacedownCommands();
|
||||
@@ -738,6 +724,10 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
return getName(currentState);
|
||||
}
|
||||
|
||||
public final String getName(CardStateName stateName) {
|
||||
return getName(getState(stateName));
|
||||
}
|
||||
|
||||
public final String getName(CardState state) {
|
||||
if (changedCardNames.isEmpty()) {
|
||||
return state.getName();
|
||||
@@ -798,6 +788,14 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
return getRules() != null && getRules().getSplitType() == CardSplitType.Meld;
|
||||
}
|
||||
|
||||
public final boolean isModal() {
|
||||
return getRules() != null && getRules().getSplitType() == CardSplitType.Modal;
|
||||
}
|
||||
|
||||
public final boolean hasBackSide() {
|
||||
return isDoubleFaced() || isMeldable() || isModal();
|
||||
}
|
||||
|
||||
public final boolean isFlipCard() {
|
||||
return hasState(CardStateName.Flipped);
|
||||
}
|
||||
@@ -813,6 +811,9 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
public final boolean isBackSide() {
|
||||
return backside;
|
||||
}
|
||||
public final void setBackSide(boolean value) {
|
||||
backside = value;
|
||||
}
|
||||
|
||||
public boolean isCloned() {
|
||||
return !clonedStates.isEmpty();
|
||||
@@ -3380,13 +3381,13 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
public final CardStateName getFaceupCardStateName() {
|
||||
if (isFlipped() && hasState(CardStateName.Flipped)) {
|
||||
return CardStateName.Flipped;
|
||||
} else if (backside && isDoubleFaced() && hasState(CardStateName.Transformed)) {
|
||||
return CardStateName.Transformed;
|
||||
} else if (backside && isMeldable() && hasState(CardStateName.Meld)) {
|
||||
return CardStateName.Meld;
|
||||
} else {
|
||||
return CardStateName.Original;
|
||||
} else if (backside && hasBackSide()) {
|
||||
CardStateName stateName = getRules().getSplitType().getChangedStateName();
|
||||
if (hasState(stateName)) {
|
||||
return stateName;
|
||||
}
|
||||
}
|
||||
return CardStateName.Original;
|
||||
}
|
||||
|
||||
private final CardCloneStates getLastClonedState() {
|
||||
@@ -6068,20 +6069,13 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
}
|
||||
|
||||
public void setSplitStateToPlayAbility(final SpellAbility sa) {
|
||||
if (isAdventureCard()) {
|
||||
if (sa.isAdventure()) {
|
||||
setState(CardStateName.Adventure, true);
|
||||
CardStateName stateName = sa.getCardState();
|
||||
if (hasState(stateName)) {
|
||||
setState(stateName, true);
|
||||
// need to set backSide value according to the SplitType
|
||||
if (hasBackSide()) {
|
||||
setBackSide(getRules().getSplitType().getChangedStateName().equals(stateName));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!isSplitCard()) {
|
||||
return; // just in case
|
||||
}
|
||||
// Split card support
|
||||
if (sa.isLeftSplit()) {
|
||||
setState(CardStateName.LeftSplit, true);
|
||||
} else if (sa.isRightSplit()) {
|
||||
setState(CardStateName.RightSplit, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6167,6 +6161,52 @@ public class Card extends GameEntity implements Comparable<Card> {
|
||||
}
|
||||
}
|
||||
|
||||
if (isModal() && hasState(CardStateName.Modal)) {
|
||||
if (getState(CardStateName.Modal).getType().isLand() && !getLastKnownZone().is(ZoneType.Battlefield)) {
|
||||
LandAbility la = new LandAbility(this, player, null);
|
||||
la.setCardState(CardStateName.Modal);
|
||||
|
||||
Card source = CardUtil.getLKICopy(this);
|
||||
boolean lkicheck = true;
|
||||
|
||||
// if Card is Facedown, need to check if MayPlay still applies
|
||||
if (isFaceDown()) {
|
||||
source.forceTurnFaceUp();
|
||||
}
|
||||
|
||||
source.setSplitStateToPlayAbility(la);
|
||||
|
||||
if (la.canPlay(source)) {
|
||||
abilities.add(la);
|
||||
}
|
||||
|
||||
if (lkicheck) {
|
||||
// double freeze tracker, so it doesn't update view
|
||||
game.getTracker().freeze();
|
||||
CardCollection preList = new CardCollection(source);
|
||||
game.getAction().checkStaticAbilities(false, Sets.newHashSet(source), preList);
|
||||
}
|
||||
|
||||
// extra for MayPlay
|
||||
for (CardPlayOption o : source.mayPlay(player)) {
|
||||
la = new LandAbility(this, player, o.getAbility());
|
||||
la.setCardState(CardStateName.Modal);
|
||||
if (la.canPlay(source)) {
|
||||
abilities.add(la);
|
||||
}
|
||||
}
|
||||
|
||||
// reset static abilities
|
||||
if (lkicheck) {
|
||||
game.getAction().checkStaticAbilities(false);
|
||||
// clear delayed changes, this check should not have updated the view
|
||||
game.getTracker().clearDelayed();
|
||||
// need to unfreeze tracker
|
||||
game.getTracker().unfreeze();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return abilities;
|
||||
}
|
||||
|
||||
|
||||
@@ -240,8 +240,8 @@ public class CardFactory {
|
||||
c.setState(CardStateName.Flipped, false);
|
||||
c.setImageKey(cp.getImageKey(true));
|
||||
}
|
||||
else if (c.isDoubleFaced() && cp instanceof PaperCard) {
|
||||
c.setState(CardStateName.Transformed, false);
|
||||
else if (c.hasBackSide() && cp instanceof PaperCard && cardRules != null) {
|
||||
c.setState(cardRules.getSplitType().getChangedStateName(), false);
|
||||
c.setImageKey(cp.getImageKey(true));
|
||||
}
|
||||
else if (c.isSplitCard()) {
|
||||
@@ -251,14 +251,9 @@ public class CardFactory {
|
||||
c.setRarity(cp.getRarity());
|
||||
c.setState(CardStateName.RightSplit, false);
|
||||
c.setImageKey(originalPicture);
|
||||
} else if (c.isMeldable() && cp instanceof PaperCard) {
|
||||
c.setState(CardStateName.Meld, false);
|
||||
c.setImageKey(cp.getImageKey(true));
|
||||
} else if (c.isAdventureCard()) {
|
||||
c.setState(CardStateName.Adventure, false);
|
||||
c.setImageKey(originalPicture);
|
||||
c.setSetCode(cp.getEdition());
|
||||
c.setRarity(cp.getRarity());
|
||||
}
|
||||
|
||||
c.setSetCode(cp.getEdition());
|
||||
@@ -272,7 +267,7 @@ public class CardFactory {
|
||||
private static void buildAbilities(final Card card) {
|
||||
|
||||
for (final CardStateName state : card.getStates()) {
|
||||
if (card.isDoubleFaced() && state == CardStateName.FaceDown) {
|
||||
if (card.hasBackSide() && state == CardStateName.FaceDown) {
|
||||
continue; // Ignore FaceDown for DFC since they have none.
|
||||
}
|
||||
card.setState(state, false);
|
||||
@@ -281,11 +276,7 @@ public class CardFactory {
|
||||
// ************** Link to different CardFactories *******************
|
||||
if (state == CardStateName.LeftSplit || state == CardStateName.RightSplit) {
|
||||
for (final SpellAbility sa : card.getSpellAbilities()) {
|
||||
if (state == CardStateName.LeftSplit) {
|
||||
sa.setLeftSplit();
|
||||
} else {
|
||||
sa.setRightSplit();
|
||||
}
|
||||
sa.setCardState(state);
|
||||
}
|
||||
CardFactoryUtil.setupKeywordedAbilities(card);
|
||||
final CardState original = card.getState(CardStateName.Original);
|
||||
|
||||
@@ -4817,7 +4817,7 @@ public class CardFactoryUtil {
|
||||
if (sa == null) {
|
||||
return;
|
||||
}
|
||||
sa.setAdventure(true);
|
||||
sa.setCardState(CardStateName.Adventure);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("Event$ Moved | ValidCard$ Card.Self | Origin$ Stack | ExcludeDestination$ Exile ");
|
||||
|
||||
@@ -1769,7 +1769,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
return false;
|
||||
}
|
||||
|
||||
public final void playLandNoCheck(final Card land) {
|
||||
public final Card playLandNoCheck(final Card land) {
|
||||
land.setController(this, 0);
|
||||
if (land.isFaceDown()) {
|
||||
land.turnFaceUp(null);
|
||||
@@ -1785,6 +1785,7 @@ public class Player extends GameEntity implements Comparable<Player> {
|
||||
game.getTriggerHandler().runTrigger(TriggerType.LandPlayed, AbilityKey.mapFromCard(land), false);
|
||||
game.getStack().unfreezeStack();
|
||||
addLandPlayedThisTurn();
|
||||
return c;
|
||||
}
|
||||
|
||||
public final boolean canPlayLand(final Card land) {
|
||||
|
||||
@@ -17,10 +17,15 @@
|
||||
*/
|
||||
package forge.game.spellability;
|
||||
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
||||
import forge.card.CardStateName;
|
||||
import forge.game.card.Card;
|
||||
import forge.game.card.CardUtil;
|
||||
import forge.game.cost.Cost;
|
||||
import forge.game.player.Player;
|
||||
import forge.game.staticability.StaticAbility;
|
||||
import forge.game.zone.ZoneType;
|
||||
|
||||
public class LandAbility extends Ability {
|
||||
|
||||
@@ -32,25 +37,58 @@ public class LandAbility extends Ability {
|
||||
public LandAbility(Card sourceCard) {
|
||||
this(sourceCard, sourceCard.getController(), null);
|
||||
}
|
||||
|
||||
public boolean canPlay(Card newHost) {
|
||||
final Player p = getActivatingPlayer();
|
||||
return p.canPlayLand(newHost, false, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canPlay() {
|
||||
final Card land = this.getHostCard();
|
||||
Card land = this.getHostCard();
|
||||
final Player p = this.getActivatingPlayer();
|
||||
|
||||
if (this.getCardState() != null) {
|
||||
if (!land.isLKI()) {
|
||||
land = CardUtil.getLKICopy(land);
|
||||
}
|
||||
CardStateName stateName = getCardState();
|
||||
if (!land.hasState(stateName)) {
|
||||
land.addAlternateState(stateName, false);
|
||||
land.getState(stateName).copyFrom(getHostCard().getState(stateName), true);
|
||||
}
|
||||
|
||||
land.setState(stateName, false);
|
||||
|
||||
// need to reset CMC
|
||||
land.setLKICMC(-1);
|
||||
land.setLKICMC(land.getCMC());
|
||||
}
|
||||
|
||||
return p.canPlayLand(land, false, this);
|
||||
}
|
||||
@Override
|
||||
public void resolve() {
|
||||
getActivatingPlayer().playLandNoCheck(getHostCard());
|
||||
getHostCard().setSplitStateToPlayAbility(this);
|
||||
final Card result = getActivatingPlayer().playLandNoCheck(getHostCard());
|
||||
|
||||
// increase mayplay used
|
||||
if (getMayPlay() != null) {
|
||||
getMayPlay().incMayPlayTurn();
|
||||
}
|
||||
// if land isn't in battlefield try to reset the card state
|
||||
if (result != null && !result.isInZone(ZoneType.Battlefield)) {
|
||||
result.setState(CardStateName.Original, true);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public String toUnsuppressedString() {
|
||||
StringBuilder sb = new StringBuilder("Play land");
|
||||
|
||||
if (getHostCard().isModal()) {
|
||||
sb.append(" (").append(getHostCard().getName(ObjectUtils.defaultIfNull(getCardState(), CardStateName.Original))).append(")");
|
||||
}
|
||||
|
||||
StaticAbility sta = getMayPlay();
|
||||
if (sta != null) {
|
||||
Card source = sta.getHostCard();
|
||||
@@ -69,5 +107,5 @@ public class LandAbility extends Ability {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -227,39 +227,19 @@ public abstract class Spell extends SpellAbility implements java.io.Serializable
|
||||
}
|
||||
source.turnFaceDownNoUpdate();
|
||||
lkicheck = true;
|
||||
} else if (isAdventure()) {
|
||||
} else if (getCardState() != null) {
|
||||
if (!source.isLKI()) {
|
||||
source = CardUtil.getLKICopy(source);
|
||||
}
|
||||
|
||||
source.setState(CardStateName.Adventure, false);
|
||||
|
||||
// need to reset CMC
|
||||
source.setLKICMC(-1);
|
||||
source.setLKICMC(source.getCMC());
|
||||
lkicheck = true;
|
||||
} else if (source.isSplitCard() && (isLeftSplit() || isRightSplit())) {
|
||||
if (!source.isLKI()) {
|
||||
source = CardUtil.getLKICopy(source);
|
||||
}
|
||||
if (isLeftSplit()) {
|
||||
if (!source.hasState(CardStateName.LeftSplit)) {
|
||||
source.addAlternateState(CardStateName.LeftSplit, false);
|
||||
source.getState(CardStateName.LeftSplit).copyFrom(
|
||||
getHostCard().getState(CardStateName.LeftSplit), true);
|
||||
}
|
||||
|
||||
source.setState(CardStateName.LeftSplit, false);
|
||||
CardStateName stateName = getCardState();
|
||||
if (!source.hasState(stateName)) {
|
||||
source.addAlternateState(stateName, false);
|
||||
source.getState(stateName).copyFrom(getHostCard().getState(stateName), true);
|
||||
}
|
||||
|
||||
if (isRightSplit()) {
|
||||
if (!source.hasState(CardStateName.RightSplit)) {
|
||||
source.addAlternateState(CardStateName.RightSplit, false);
|
||||
source.getState(CardStateName.RightSplit).copyFrom(
|
||||
getHostCard().getState(CardStateName.RightSplit), true);
|
||||
}
|
||||
|
||||
source.setState(CardStateName.RightSplit, false);
|
||||
source.setState(stateName, false);
|
||||
if (getHostCard().hasBackSide()) {
|
||||
source.setBackSide(getHostCard().getRules().getSplitType().getChangedStateName().equals(stateName));
|
||||
}
|
||||
|
||||
// need to reset CMC
|
||||
|
||||
@@ -21,6 +21,8 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Iterables;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import forge.card.CardStateName;
|
||||
import forge.card.mana.ManaCost;
|
||||
import forge.game.*;
|
||||
import forge.game.ability.AbilityFactory;
|
||||
@@ -113,9 +115,7 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
|
||||
private boolean basicLandAbility = false;
|
||||
|
||||
private boolean adventure = false;
|
||||
private SplitSide splitSide = null;
|
||||
enum SplitSide { LEFT, RIGHT }
|
||||
private CardStateName stateName = null;
|
||||
|
||||
private int totalManaSpent = 0;
|
||||
|
||||
@@ -840,26 +840,15 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
|
||||
mayPlay = sta;
|
||||
}
|
||||
|
||||
public boolean isLeftSplit() {
|
||||
return splitSide == SplitSide.LEFT;
|
||||
public CardStateName getCardState() {
|
||||
return stateName;
|
||||
}
|
||||
public boolean isRightSplit() {
|
||||
return splitSide == SplitSide.RIGHT;
|
||||
}
|
||||
public void setNoSplit() {
|
||||
splitSide = null;
|
||||
}
|
||||
public void setLeftSplit() {
|
||||
splitSide = SplitSide.LEFT;
|
||||
}
|
||||
public void setRightSplit() {
|
||||
splitSide = SplitSide.RIGHT;
|
||||
public void setCardState(CardStateName stateName0) {
|
||||
this.stateName = stateName0;
|
||||
}
|
||||
|
||||
public boolean isAdventure() {
|
||||
return this.adventure;
|
||||
}
|
||||
public void setAdventure(boolean adventure) {
|
||||
this.adventure = adventure;
|
||||
return this.stateName == CardStateName.Adventure;
|
||||
}
|
||||
|
||||
public SpellAbility copy() {
|
||||
|
||||
@@ -21,7 +21,6 @@ import forge.game.Game;
|
||||
import forge.game.GameType;
|
||||
import forge.game.ability.AbilityUtils;
|
||||
import forge.game.card.*;
|
||||
import forge.game.combat.Combat;
|
||||
import forge.game.cost.IndividualCostPaymentInstance;
|
||||
import forge.game.phase.PhaseType;
|
||||
import forge.game.player.Player;
|
||||
@@ -255,7 +254,7 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
||||
}
|
||||
|
||||
// TODO: this is an exception for Aftermath. Needs to be somehow generalized.
|
||||
if (this.getZone() != ZoneType.Graveyard && sa.isAftermath() && sa.isRightSplit()) {
|
||||
if (this.getZone() != ZoneType.Graveyard && sa.isAftermath() && sa.getCardState() != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -310,8 +309,6 @@ public class SpellAbilityRestriction extends SpellAbilityVariables {
|
||||
*/
|
||||
public final boolean checkActivatorRestrictions(final Card c, final SpellAbility sa) {
|
||||
Player activator = sa.getActivatingPlayer();
|
||||
final Game game = activator.getGame();
|
||||
final Combat combat = game.getPhaseHandler().getCombat();
|
||||
|
||||
if (sa.isSpell()) {
|
||||
// Spells should always default to "controller" but use mayPlay check.
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
Name:Branchloft Pathway
|
||||
ManaCost:no cost
|
||||
Types:Land
|
||||
A:AB$ Mana | Cost$ T | Produced$ G | SpellDescription$ Add {G}.
|
||||
AlternateMode:Modal
|
||||
Oracle:Add {G}.
|
||||
|
||||
ALTERNATE
|
||||
|
||||
Name:Boulderloft Pathway
|
||||
ManaCost:no cost
|
||||
Types:Land
|
||||
A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W}.
|
||||
Oracle:Add {W}.
|
||||
@@ -0,0 +1,19 @@
|
||||
Name:Emeria's Call
|
||||
ManaCost:4 W W W
|
||||
Types:Sorcery
|
||||
A:SP$ Token | Cost$ 4 W W W | TokenAmount$ 2 | TokenScript$ w_4_4_angel_warrior_flying | SubAbility$ DBPumpAll | SpellDescription$ Create two 4/4 white Angel Warrior creature tokens with flying. Non-Angel creatures you control gain indestructible until your next turn.
|
||||
SVar:DBPumpAll:DB$ PumpAll | ValidCards$ Creature.nonAngel+YouCtrl | KW$ Indestructible | UntilYourNextTurn$ True
|
||||
AlternateMode:Modal
|
||||
DeckHas:Ability$Token
|
||||
Oracle:Create two 4/4 white Angel Warrior creature tokens with flying. Non-Angel creatures you control gain indestructible until your next turn.
|
||||
|
||||
ALTERNATE
|
||||
|
||||
Name:Emeria, Shattered Skyclave
|
||||
ManaCost:no cost
|
||||
Types:Land
|
||||
K:ETBReplacement:Other:DBTap
|
||||
SVar:DBTap:DB$ Tap | ETB$ True | Defined$ Self | UnlessCost$ PayLife<3> | UnlessPayer$ You | UnlessAI$ Shockland | StackDescription$ enters the battlefield tapped. | SpellDescription$ As CARDNAME enters the battlefield, you may pay 3 life. If you don't, it enters the battlefield tapped.
|
||||
A:AB$ Mana | Cost$ T | Produced$ W | SpellDescription$ Add {W}.
|
||||
Oracle:As Emeria, Shattered Skyclave enters the battlefield, you may pay 3 life. If you don’t, it enters the battlefield tapped.\nAdd {W}.
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
Name:Angel Warrior
|
||||
ManaCost:no cost
|
||||
Types:Creature Angel Warrior
|
||||
Colors:white
|
||||
PT:4/4
|
||||
K:Flying
|
||||
Oracle:Flying
|
||||
@@ -220,6 +220,7 @@ public abstract class AbstractGuiGame implements IGuiGame, IMayViewCards {
|
||||
case Flipped:
|
||||
case Transformed:
|
||||
case Meld:
|
||||
case Modal:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user