Merge branch 'master' into code-cleanup

# Conflicts:
#	forge-game/src/main/java/forge/game/phase/PhaseHandler.java
This commit is contained in:
Jetz
2024-10-14 22:20:44 -04:00
732 changed files with 3039 additions and 2072 deletions

View File

@@ -933,9 +933,6 @@ public class AiController {
if (!sa.checkRestrictions(spellHost, player)) { if (!sa.checkRestrictions(spellHost, player)) {
return AiPlayDecision.AnotherTime; return AiPlayDecision.AnotherTime;
} }
if (sa instanceof SpellPermanent) {
return canPlayFromEffectAI((SpellPermanent) sa, false, true);
}
if (sa.usesTargeting()) { if (sa.usesTargeting()) {
if (!sa.isTargetNumberValid() && sa.getTargetRestrictions().getNumCandidates(sa, true) == 0) { if (!sa.isTargetNumberValid() && sa.getTargetRestrictions().getNumCandidates(sa, true) == 0) {
return AiPlayDecision.TargetingFailed; return AiPlayDecision.TargetingFailed;
@@ -945,6 +942,9 @@ public class AiController {
} }
} }
if (sa instanceof Spell) { if (sa instanceof Spell) {
if (card.isPermanent()) {
return canPlayFromEffectAI((Spell) sa, false, true);
}
if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife() && if (!player.cantLoseForZeroOrLessLife() && player.canLoseLife() &&
ComputerUtil.getDamageForPlaying(player, sa) >= player.getLife()) { ComputerUtil.getDamageForPlaying(player, sa) >= player.getLife()) {
return AiPlayDecision.CurseEffects; return AiPlayDecision.CurseEffects;
@@ -1030,8 +1030,8 @@ public class AiController {
} }
public CardCollection getCardsToDiscard(int min, final int max, final CardCollection validCards, final SpellAbility sa) { public CardCollection getCardsToDiscard(int min, final int max, final CardCollection validCards, final SpellAbility sa) {
if (validCards.size() < min) { if (validCards.size() <= min) {
return null; return validCards; //return all valid cards since they will be discarded without filtering needed
} }
Card sourceCard = null; Card sourceCard = null;
@@ -1275,7 +1275,7 @@ public class AiController {
return AiPlayDecision.WillPlay; return AiPlayDecision.WillPlay;
} }
if (spell instanceof SpellPermanent) { if (card.isPermanent()) {
if (!checkETBEffects(card, spell, null)) { if (!checkETBEffects(card, spell, null)) {
return AiPlayDecision.BadEtbEffects; return AiPlayDecision.BadEtbEffects;
} }

View File

@@ -627,6 +627,7 @@ public abstract class GameState {
} }
game.getStack().setResolving(false); game.getStack().setResolving(false);
game.getStack().unfreezeStack();
// Advance to a certain phase, activating all triggered abilities // Advance to a certain phase, activating all triggered abilities
if (advPhase != null) { if (advPhase != null) {

View File

@@ -643,6 +643,12 @@ public class PlayerControllerAi extends PlayerController {
} }
} }
if(source == null || !source.hasParam("LibraryPosition")
|| AbilityUtils.calculateAmount(source.getHostCard(), source.getParam("LibraryPosition"), source) >= 0) {
//Cards going to the top of a deck are returned in reverse order.
Collections.reverse(reordered);
}
assert(reordered.size() == cards.size()); assert(reordered.size() == cards.size());
return reordered; return reordered;
@@ -1520,6 +1526,24 @@ public class PlayerControllerAi extends PlayerController {
return SpellApiToAi.Converter.get(api).chooseCardName(player, sa, faces); return SpellApiToAi.Converter.get(api).chooseCardName(player, sa, faces);
} }
@Override
public ICardFace chooseSingleCardFace(SpellAbility sa, List<ICardFace> faces, String message) {
ApiType api = sa.getApi();
if (null == api) {
throw new InvalidParameterException("SA is not api-based, this is not supported yet");
}
return SpellApiToAi.Converter.get(api).chooseCardFace(player, sa, faces);
}
@Override
public CardState chooseSingleCardState(SpellAbility sa, List<CardState> states, String message, Map<String, Object> params) {
ApiType api = sa.getApi();
if (null == api) {
throw new InvalidParameterException("SA is not api-based, this is not supported yet");
}
return SpellApiToAi.Converter.get(api).chooseCardState(player, sa, states, params);
}
@Override @Override
public Card chooseDungeon(Player ai, List<PaperCard> dungeonCards, String message) { public Card chooseDungeon(Player ai, List<PaperCard> dungeonCards, String message) {
// TODO: improve the conditions that define which dungeon is a viable option to choose // TODO: improve the conditions that define which dungeon is a viable option to choose

View File

@@ -8,6 +8,7 @@ import forge.card.mana.ManaCost;
import forge.card.mana.ManaCostParser; import forge.card.mana.ManaCostParser;
import forge.game.GameEntity; import forge.game.GameEntity;
import forge.game.card.Card; import forge.game.card.Card;
import forge.game.card.CardState;
import forge.game.card.CounterType; import forge.game.card.CounterType;
import forge.game.cost.Cost; import forge.game.cost.Cost;
import forge.game.mana.ManaCostBeingPaid; import forge.game.mana.ManaCostBeingPaid;
@@ -365,6 +366,18 @@ public abstract class SpellAbilityAi {
return face == null ? "" : face.getName(); return face == null ? "" : face.getName();
} }
public ICardFace chooseCardFace(Player ai, SpellAbility sa, List<ICardFace> faces) {
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseCardFace is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
return Iterables.getFirst(faces, null);
}
public CardState chooseCardState(Player ai, SpellAbility sa, List<CardState> faces, Map<String, Object> params) {
System.err.println("Warning: default (ie. inherited from base class) implementation of chooseCardState is used for " + this.getClass().getName() + ". Consider declaring an overloaded method");
return Iterables.getFirst(faces, null);
}
public int chooseNumber(Player player, SpellAbility sa, int min, int max, Map<String, Object> params) { public int chooseNumber(Player player, SpellAbility sa, int min, int max, Map<String, Object> params) {
return max; return max;
} }

View File

@@ -189,6 +189,7 @@ public enum SpellApiToAi {
.put(ApiType.TwoPiles, TwoPilesAi.class) .put(ApiType.TwoPiles, TwoPilesAi.class)
.put(ApiType.Unattach, CannotPlayAi.class) .put(ApiType.Unattach, CannotPlayAi.class)
.put(ApiType.UnattachAll, UnattachAllAi.class) .put(ApiType.UnattachAll, UnattachAllAi.class)
.put(ApiType.UnlockDoor, AlwaysPlayAi.class)
.put(ApiType.Untap, UntapAi.class) .put(ApiType.Untap, UntapAi.class)
.put(ApiType.UntapAll, UntapAllAi.class) .put(ApiType.UntapAll, UntapAllAi.class)
.put(ApiType.Venture, VentureAi.class) .put(ApiType.Venture, VentureAi.class)

View File

@@ -12,6 +12,7 @@ public enum CardStateName {
RightSplit, RightSplit,
Adventure, Adventure,
Modal, Modal,
EmptyRoom,
SpecializeW, SpecializeW,
SpecializeU, SpecializeU,
SpecializeB, SpecializeB,

View File

@@ -190,7 +190,12 @@ public class GameAction {
// Make sure the card returns from the battlefield as the original card with two halves // Make sure the card returns from the battlefield as the original card with two halves
resetToOriginal = true; resetToOriginal = true;
} }
} else if (!zoneTo.is(ZoneType.Stack)) { } else if (zoneTo.is(ZoneType.Battlefield) && c.isRoom()) {
if (c.getCastSA() == null) {
// need to set as empty room
c.updateRooms();
}
} else if (!zoneTo.is(ZoneType.Stack) && !zoneTo.is(ZoneType.Battlefield)) {
// For regular splits, recreate the original state unless the card is going to stack as one half // For regular splits, recreate the original state unless the card is going to stack as one half
resetToOriginal = true; resetToOriginal = true;
} }
@@ -423,9 +428,6 @@ public class GameAction {
cards = (CardCollection) c.getOwner().getController().orderMoveToZoneList(cards, zoneTo.getZoneType(), cause); cards = (CardCollection) c.getOwner().getController().orderMoveToZoneList(cards, zoneTo.getZoneType(), cause);
} }
cards.set(cards.indexOf(copied), c); cards.set(cards.indexOf(copied), c);
if (zoneTo.is(ZoneType.Library)) {
Collections.reverse(cards);
}
mergedCards = cards; mergedCards = cards;
if (cause != null) { if (cause != null) {
// Replace sa targeting cards // Replace sa targeting cards
@@ -454,9 +456,8 @@ public class GameAction {
} }
game.getCombat().removeFromCombat(c); game.getCombat().removeFromCombat(c);
} }
if ((zoneFrom.is(ZoneType.Library) || zoneFrom.is(ZoneType.PlanarDeck) if (zoneFrom.getZoneType().isDeck() && zoneFrom == zoneTo
|| zoneFrom.is(ZoneType.SchemeDeck) || zoneFrom.is(ZoneType.AttractionDeck)) && position.equals(zoneFrom.size()) && position != 0) {
&& zoneFrom == zoneTo && position.equals(zoneFrom.size()) && position != 0) {
position--; position--;
} }
if (mergedCards != null) { if (mergedCards != null) {
@@ -608,6 +609,9 @@ public class GameAction {
// CR 603.6b // CR 603.6b
if (toBattlefield) { if (toBattlefield) {
zoneTo.saveLKI(copied, lastKnownInfo); zoneTo.saveLKI(copied, lastKnownInfo);
if (copied.isRoom() && copied.getCastSA() != null) {
copied.unlockRoom(copied.getCastSA().getActivatingPlayer(), copied.getCastSA().getCardStateName());
}
} }
// only now that the LKI preserved it // only now that the LKI preserved it

View File

@@ -48,7 +48,6 @@ import forge.util.Lang;
import forge.util.TextUtil; import forge.util.TextUtil;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import java.util.Collections;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@@ -832,12 +831,8 @@ public final class GameActionUtil {
return list; return list;
} }
CardCollection completeList = new CardCollection(); CardCollection completeList = new CardCollection();
PlayerCollection players = new PlayerCollection(game.getPlayers());
// CR 613.7m use APNAP // CR 613.7m use APNAP
int indexAP = players.indexOf(game.getPhaseHandler().getPlayerTurn()); PlayerCollection players = game.getPlayersInTurnOrder(game.getPhaseHandler().getPlayerTurn());
if (indexAP != -1) {
Collections.rotate(players, - indexAP);
}
for (Player p : players) { for (Player p : players) {
CardCollection subList = new CardCollection(); CardCollection subList = new CardCollection();
for (Card c : list) { for (Card c : list) {

View File

@@ -30,6 +30,7 @@ public enum AbilityKey {
Blockers("Blockers"), Blockers("Blockers"),
CanReveal("CanReveal"), CanReveal("CanReveal"),
Card("Card"), Card("Card"),
CardState("CardState"),
Cards("Cards"), Cards("Cards"),
CardsFiltered("CardsFiltered"), CardsFiltered("CardsFiltered"),
CardLKI("CardLKI"), CardLKI("CardLKI"),

View File

@@ -2,7 +2,6 @@ package forge.game.ability;
import com.google.common.collect.*; import com.google.common.collect.*;
import com.google.common.math.IntMath; import com.google.common.math.IntMath;
import forge.card.CardStateName; import forge.card.CardStateName;
import forge.card.CardType; import forge.card.CardType;
import forge.card.ColorSet; import forge.card.ColorSet;
@@ -2509,6 +2508,19 @@ public class AbilityUtils {
return doXMath(CardLists.getValidCardCount(game.getLeftGraveyardThisTurn(), validFilter, player, c, ctb), expr, c, ctb); return doXMath(CardLists.getValidCardCount(game.getLeftGraveyardThisTurn(), validFilter, player, c, ctb), expr, c, ctb);
} }
// Count$UnlockedDoors <Valid>
if (sq[0].startsWith("UnlockedDoors")) {
final String[] workingCopy = l[0].split(" ", 2);
final String validFilter = workingCopy[1];
int unlocked = 0;
for (Card doorCard : CardLists.getValidCards(player.getCardsIn(ZoneType.Battlefield), validFilter, player, c, ctb)) {
unlocked += doorCard.getUnlockedRooms().size();
}
return doXMath(unlocked, expr, c, ctb);
}
// Manapool // Manapool
if (sq[0].startsWith("ManaPool")) { if (sq[0].startsWith("ManaPool")) {
final String color = l[0].split(":")[1]; final String color = l[0].split(":")[1];

View File

@@ -194,6 +194,7 @@ public enum ApiType {
TwoPiles (TwoPilesEffect.class), TwoPiles (TwoPilesEffect.class),
Unattach (UnattachEffect.class), Unattach (UnattachEffect.class),
UnattachAll (UnattachAllEffect.class), UnattachAll (UnattachAllEffect.class),
UnlockDoor (UnlockDoorEffect.class),
Untap (UntapEffect.class), Untap (UntapEffect.class),
UntapAll (UntapAllEffect.class), UntapAll (UntapAllEffect.class),
Venture (VentureEffect.class), Venture (VentureEffect.class),

View File

@@ -276,6 +276,7 @@ public abstract class SpellAbilityEffect {
return getPlayers(definedFirst, definedParam, sa, null); return getPlayers(definedFirst, definedParam, sa, null);
} }
private static PlayerCollection getPlayers(final boolean definedFirst, final String definedParam, final SpellAbility sa, List<Player> resultDuplicate) { private static PlayerCollection getPlayers(final boolean definedFirst, final String definedParam, final SpellAbility sa, List<Player> resultDuplicate) {
Game game = sa.getHostCard().getGame();
PlayerCollection resultUnique = null; PlayerCollection resultUnique = null;
final boolean useTargets = sa.usesTargeting() && (!definedFirst || !sa.hasParam(definedParam)); final boolean useTargets = sa.usesTargeting() && (!definedFirst || !sa.hasParam(definedParam));
if (useTargets) { if (useTargets) {
@@ -298,10 +299,12 @@ public abstract class SpellAbilityEffect {
} }
// try sort in APNAP order // try sort in APNAP order
int indexAP = resultDuplicate.indexOf(sa.getHostCard().getGame().getPhaseHandler().getPlayerTurn()); Player starter = game.getPhaseHandler().getPlayerTurn();
if (indexAP != -1) { if (sa.hasParam("StartingWith")) {
Collections.rotate(resultDuplicate, - indexAP); starter = AbilityUtils.getDefinedPlayers(sa.getHostCard(), sa.getParam("StartingWith"), sa).getFirst();
} }
PlayerCollection ordered = game.getPlayersInTurnOrder(starter);
resultDuplicate.sort(Comparator.comparingInt(ordered::indexOf));
return resultUnique; return resultUnique;
} }

View File

@@ -84,22 +84,20 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
final String imprint = sa.getParam("Imprint"); final String imprint = sa.getParam("Imprint");
final boolean random = sa.hasParam("RandomOrder"); final boolean random = sa.hasParam("RandomOrder");
final boolean remLKI = sa.hasParam("RememberLKI"); final boolean remLKI = sa.hasParam("RememberLKI");
final boolean movingToDeck = destination.isDeck();
final int libraryPos = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : 0; final int libraryPos = sa.hasParam("LibraryPosition") ? Integer.parseInt(sa.getParam("LibraryPosition")) : 0;
if (!random && !((destination == ZoneType.Library || destination == ZoneType.PlanarDeck) && sa.hasParam("Shuffle"))) { if (!random && !sa.hasParam("Shuffle")) {
if ((destination == ZoneType.Library || destination == ZoneType.PlanarDeck) && cards.size() >= 2) { if (movingToDeck && cards.size() >= 2) {
Player p = AbilityUtils.getDefinedPlayers(source, sa.getParam("DefinedPlayer"), sa).get(0); Player p = AbilityUtils.getDefinedPlayers(source, sa.getParam("DefinedPlayer"), sa).get(0);
cards = (CardCollection) p.getController().orderMoveToZoneList(cards, destination, sa); cards = (CardCollection) p.getController().orderMoveToZoneList(cards, destination, sa);
//the last card in this list will be the closest to the top, but we want the first card to be closest.
//so reverse it here before moving them to the library.
java.util.Collections.reverse(cards);
} else { } else {
cards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, cards, destination, sa); cards = (CardCollection) GameActionUtil.orderCardsByTheirOwners(game, cards, destination, sa);
} }
} }
if (destination.equals(ZoneType.Library) && random) { if (movingToDeck && random) {
CardLists.shuffle(cards); CardLists.shuffle(cards);
} }
@@ -207,6 +205,7 @@ public class ChangeZoneAllEffect extends SpellAbilityEffect {
// CR 701.20d If an effect would cause a player to shuffle a set of objects into a library, // CR 701.20d If an effect would cause a player to shuffle a set of objects into a library,
// that library is shuffled even if there are no objects in that set. // that library is shuffled even if there are no objects in that set.
if (sa.hasParam("Shuffle")) { if (sa.hasParam("Shuffle")) {
//TODO: If destination zone is some other kind of deck like a planar deck, shuffle that instead.
for (Player p : tgtPlayers) { for (Player p : tgtPlayers) {
p.shuffle(sa); p.shuffle(sa);
} }

View File

@@ -514,15 +514,16 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
} }
// CR 401.4 // CR 401.4
if (destination.equals(ZoneType.Library) && !shuffle && tgtCards.size() > 1) { if (destination.isDeck() && !shuffle && tgtCards.size() > 1) {
if (sa.hasParam("RandomOrder")) { if (sa.hasParam("RandomOrder")) {
final CardCollection random = new CardCollection(tgtCards); final CardCollection random = new CardCollection(tgtCards);
CardLists.shuffle(random); CardLists.shuffle(random);
tgtCards = random; tgtCards = random;
} else if (sa.hasParam("Chooser")) {
tgtCards = chooser.getController().orderMoveToZoneList(tgtCards, destination, sa);
} else { } else {
tgtCards = GameActionUtil.orderCardsByTheirOwners(game, tgtCards, destination, sa); if (sa.hasParam("Chooser"))
tgtCards = chooser.getController().orderMoveToZoneList(tgtCards, destination, sa);
else
tgtCards = GameActionUtil.orderCardsByTheirOwners(game, tgtCards, destination, sa);
} }
} }
@@ -717,7 +718,7 @@ public class ChangeZoneEffect extends SpellAbilityEffect {
handleExiledWith(gameCard, sa); handleExiledWith(gameCard, sa);
} }
movedCard = game.getAction().moveTo(destination, gameCard, sa, moveParams); movedCard = game.getAction().moveTo(destination, gameCard, libraryPosition, sa, moveParams);
if (destination.equals(ZoneType.Exile) && lastStateBattlefield.contains(gameCard) && hostCard.equals(gameCard)) { if (destination.equals(ZoneType.Exile) && lastStateBattlefield.contains(gameCard) && hostCard.equals(gameCard)) {
// support Parallax Wave returning itself // support Parallax Wave returning itself

View File

@@ -144,6 +144,7 @@ public class CloneEffect extends SpellAbilityEffect {
final long ts = game.getNextTimestamp(); final long ts = game.getNextTimestamp();
tgtCard.addCloneState(CardFactory.getCloneStates(cardToCopy, tgtCard, sa), ts); tgtCard.addCloneState(CardFactory.getCloneStates(cardToCopy, tgtCard, sa), ts);
tgtCard.updateRooms();
// set ETB tapped of clone // set ETB tapped of clone
if (sa.hasParam("IntoPlayTapped")) { if (sa.hasParam("IntoPlayTapped")) {

View File

@@ -273,6 +273,7 @@ public class CounterEffect extends SpellAbilityEffect {
// card is no longer cast // card is no longer cast
c.setCastSA(null); c.setCastSA(null);
c.setCastFrom(null); c.setCastFrom(null);
c.forceTurnFaceUp();
if (tgtSA instanceof SpellPermanent) { if (tgtSA instanceof SpellPermanent) {
c.setController(srcSA.getActivatingPlayer(), 0); c.setController(srcSA.getActivatingPlayer(), 0);
movedCard = game.getAction().moveToPlay(c, srcSA.getActivatingPlayer(), srcSA, params); movedCard = game.getAction().moveToPlay(c, srcSA.getActivatingPlayer(), srcSA, params);

View File

@@ -372,7 +372,7 @@ public class DigEffect extends SpellAbilityEffect {
Map<AbilityKey, Object> moveParams = AbilityKey.newMap(); Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
AbilityKey.addCardZoneTableParams(moveParams, zoneMovements); AbilityKey.addCardZoneTableParams(moveParams, zoneMovements);
if (destZone1.equals(ZoneType.Library) || destZone1.equals(ZoneType.PlanarDeck) || destZone1.equals(ZoneType.SchemeDeck)) { if (destZone1.isDeck()) {
c = game.getAction().moveTo(destZone1, c, libraryPosition, sa, AbilityKey.newMap()); c = game.getAction().moveTo(destZone1, c, libraryPosition, sa, AbilityKey.newMap());
} else { } else {
if (destZone1.equals(ZoneType.Exile) && !c.canExiledBy(sa, true)) { if (destZone1.equals(ZoneType.Exile) && !c.canExiledBy(sa, true)) {
@@ -445,8 +445,7 @@ public class DigEffect extends SpellAbilityEffect {
if (!rest.isEmpty() && (!sa.hasParam("DestZone2Optional") || p.getController().confirmAction(sa, null, if (!rest.isEmpty() && (!sa.hasParam("DestZone2Optional") || p.getController().confirmAction(sa, null,
Localizer.getInstance().getMessage("lblDoYouWantPutCardToZone", Localizer.getInstance().getMessage("lblDoYouWantPutCardToZone",
destZone2.getTranslatedName()), null))) { destZone2.getTranslatedName()), null))) {
if (destZone2 == ZoneType.Library || destZone2 == ZoneType.PlanarDeck if (destZone2.isDeck() || destZone2 == ZoneType.Graveyard) {
|| destZone2 == ZoneType.SchemeDeck || destZone2 == ZoneType.Graveyard) {
CardCollection afterOrder = rest; CardCollection afterOrder = rest;
if (sa.hasParam("RestRandomOrder")) { if (sa.hasParam("RestRandomOrder")) {
CardLists.shuffle(afterOrder); CardLists.shuffle(afterOrder);
@@ -457,10 +456,6 @@ public class DigEffect extends SpellAbilityEffect {
afterOrder = (CardCollection) chooser.getController().orderMoveToZoneList(rest, destZone2, sa); afterOrder = (CardCollection) chooser.getController().orderMoveToZoneList(rest, destZone2, sa);
} }
} }
if (libraryPosition2 != -1) {
// Closest to top
Collections.reverse(afterOrder);
}
for (final Card c : afterOrder) { for (final Card c : afterOrder) {
Map<AbilityKey, Object> moveParams = AbilityKey.newMap(); Map<AbilityKey, Object> moveParams = AbilityKey.newMap();

View File

@@ -120,7 +120,7 @@ public class DigMultipleEffect extends SpellAbilityEffect {
final PlayerZone zone = c.getOwner().getZone(destZone1); final PlayerZone zone = c.getOwner().getZone(destZone1);
if (!sa.hasParam("ChangeLater")) { if (!sa.hasParam("ChangeLater")) {
if (zone.is(ZoneType.Library) || zone.is(ZoneType.PlanarDeck) || zone.is(ZoneType.SchemeDeck)) { if (zone.getZoneType().isDeck()) {
c = game.getAction().moveTo(destZone1, c, libraryPosition, sa, AbilityKey.newMap()); c = game.getAction().moveTo(destZone1, c, libraryPosition, sa, AbilityKey.newMap());
} else { } else {
if (destZone1.equals(ZoneType.Battlefield)) { if (destZone1.equals(ZoneType.Battlefield)) {
@@ -153,8 +153,7 @@ public class DigMultipleEffect extends SpellAbilityEffect {
// now, move the rest to destZone2 // now, move the rest to destZone2
if (!sa.hasParam("ChangeLater")) { if (!sa.hasParam("ChangeLater")) {
if (destZone2 == ZoneType.Library || destZone2 == ZoneType.PlanarDeck if (destZone2.isDeck() || destZone2 == ZoneType.Graveyard) {
|| destZone2 == ZoneType.SchemeDeck || destZone2 == ZoneType.Graveyard) {
CardCollection afterOrder = rest; CardCollection afterOrder = rest;
if (sa.hasParam("RestRandomOrder")) { if (sa.hasParam("RestRandomOrder")) {
CardLists.shuffle(afterOrder); CardLists.shuffle(afterOrder);

View File

@@ -321,6 +321,7 @@ public class PlayEffect extends SpellAbilityEffect {
if (sa.hasParam("CastFaceDown")) { if (sa.hasParam("CastFaceDown")) {
// For Illusionary Mask effect // For Illusionary Mask effect
tgtSA = CardFactoryUtil.abilityCastFaceDown(tgtCard.getCurrentState(), false, "Morph"); tgtSA = CardFactoryUtil.abilityCastFaceDown(tgtCard.getCurrentState(), false, "Morph");
tgtSA.setCastFromPlayEffect(true);
} else { } else {
tgtSA = controller.getController().getAbilityToPlay(tgtCard, sas); tgtSA = controller.getController().getAbilityToPlay(tgtCard, sas);
} }

View File

@@ -103,11 +103,9 @@ public class RearrangeTopOfLibraryEffect extends SpellAbilityEffect {
} }
CardCollection topCards = player.getTopXCardsFromLibrary(numCards); CardCollection topCards = player.getTopXCardsFromLibrary(numCards);
int maxCards = topCards.size();
CardCollectionView orderedCards = activator.getController().orderMoveToZoneList(topCards, ZoneType.Library, sa); CardCollectionView orderedCards = activator.getController().orderMoveToZoneList(topCards, ZoneType.Library, sa);
for (int i = maxCards - 1; i >= 0; i--) { for (Card next : orderedCards) {
Card next = orderedCards.get(i);
player.getGame().getAction().moveToLibrary(next, 0, sa); player.getGame().getAction().moveToLibrary(next, 0, sa);
} }
if (mayshuffle && activator.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoyouWantShuffleTheLibrary"), null)) { if (mayshuffle && activator.getController().confirmAction(sa, null, Localizer.getInstance().getMessage("lblDoyouWantShuffleTheLibrary"), null)) {

View File

@@ -5,6 +5,7 @@ import java.util.List;
import forge.game.ability.SpellAbilityEffect; import forge.game.ability.SpellAbilityEffect;
import forge.game.card.CardCollection; import forge.game.card.CardCollection;
import forge.game.card.CardCollectionView;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType; import forge.game.zone.ZoneType;
@@ -36,7 +37,8 @@ public class ReorderZoneEffect extends SpellAbilityEffect {
Collections.shuffle(list, MyRandom.getRandom()); Collections.shuffle(list, MyRandom.getRandom());
p.getZone(zone).setCards(list); p.getZone(zone).setCards(list);
} else { } else {
p.getController().orderMoveToZoneList(list, zone, sa); CardCollectionView orderedCards = p.getController().orderMoveToZoneList(list, zone, sa);
p.getZone(zone).setCards(orderedCards);
} }
} }
} }

View File

@@ -56,8 +56,7 @@ public class RepeatEachEffect extends SpellAbilityEffect {
} else { } else {
zone.add(ZoneType.Battlefield); zone.add(ZoneType.Battlefield);
} }
repeatCards = CardLists.getValidCards(game.getCardsIn(zone), repeatCards = CardLists.getValidCards(game.getCardsIn(zone), sa.getParam("RepeatCards"), source.getController(), source, sa);
sa.getParam("RepeatCards"), source.getController(), source, sa);
} }
else if (sa.hasParam(("RepeatSpellAbilities"))) { else if (sa.hasParam(("RepeatSpellAbilities"))) {
repeatSas = Lists.newArrayList(); repeatSas = Lists.newArrayList();
@@ -167,18 +166,13 @@ public class RepeatEachEffect extends SpellAbilityEffect {
} }
if (sa.hasParam("RepeatPlayers")) { if (sa.hasParam("RepeatPlayers")) {
final FCollection<Player> repeatPlayers = AbilityUtils.getDefinedPlayers(source, sa.getParam("RepeatPlayers"), sa); final FCollection<Player> repeatPlayers = getDefinedPlayersOrTargeted(sa, "RepeatPlayers");
if (sa.hasParam("ClearRememberedBeforeLoop")) { if (sa.hasParam("ClearRememberedBeforeLoop")) {
source.clearRemembered(); source.clearRemembered();
} }
boolean optional = sa.hasParam("RepeatOptionalForEachPlayer"); boolean optional = sa.hasParam("RepeatOptionalForEachPlayer");
boolean nextTurn = sa.hasParam("NextTurnForEachPlayer"); boolean nextTurn = sa.hasParam("NextTurnForEachPlayer");
if (sa.hasParam("StartingWithActivator")) {
int aidx = repeatPlayers.indexOf(activator);
if (aidx != -1) {
Collections.rotate(repeatPlayers, -aidx);
}
}
for (final Player p : repeatPlayers) { for (final Player p : repeatPlayers) {
if (optional && !p.getController().confirmAction(repeat, null, sa.getParam("RepeatOptionalMessage"), null)) { if (optional && !p.getController().confirmAction(repeat, null, sa.getParam("RepeatOptionalMessage"), null)) {
continue; continue;

View File

@@ -0,0 +1,106 @@
package forge.game.ability.effects;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import forge.card.CardStateName;
import forge.game.Game;
import forge.game.ability.SpellAbilityEffect;
import forge.game.card.Card;
import forge.game.card.CardCollection;
import forge.game.card.CardLists;
import forge.game.card.CardState;
import forge.game.player.Player;
import forge.game.spellability.SpellAbility;
import forge.game.zone.ZoneType;
import forge.util.Localizer;
public class UnlockDoorEffect extends SpellAbilityEffect {
@Override
public void resolve(SpellAbility sa) {
final Card source = sa.getHostCard();
final Game game = source.getGame();
final Player activator = sa.getActivatingPlayer();
CardCollection list;
if (sa.hasParam("Choices")) {
Player chooser = activator;
String title = sa.hasParam("ChoiceTitle") ? sa.getParam("ChoiceTitle") : Localizer.getInstance().getMessage("lblChoose") + " ";
CardCollection choices = CardLists.getValidCards(game.getCardsIn(ZoneType.Battlefield), sa.getParam("Choices"), activator, source, sa);
Card c = chooser.getController().chooseSingleEntityForEffect(choices, sa, title, Maps.newHashMap());
if (c == null) {
return;
}
list = new CardCollection(c);
} else {
list = getTargetCards(sa);
}
for (Card c : list) {
Map<String, Object> params = Maps.newHashMap();
params.put("Object", c);
switch (sa.getParamOrDefault("Mode", "ThisDoor")) {
case "ThisDoor":
c.unlockRoom(activator, sa.getCardStateName());
break;
case "Unlock":
List<CardState> states = c.getLockedRooms().stream().map(stateName -> c.getState(stateName)).collect(Collectors.toList());
// need to choose Room Name
CardState chosen = activator.getController().chooseSingleCardState(sa, states, "Choose Room to unlock", params);
if (chosen == null) {
continue;
}
c.unlockRoom(activator, chosen.getStateName());
break;
case "LockOrUnlock":
switch (c.getLockedRooms().size()) {
case 0:
// no locked, all unlocked, can only lock door
List<CardState> unlockStates = c.getUnlockedRooms().stream().map(stateName -> c.getState(stateName)).collect(Collectors.toList());
CardState chosenUnlock = activator.getController().chooseSingleCardState(sa, unlockStates, "Choose Room to lock", params);
if (chosenUnlock == null) {
continue;
}
c.lockRoom(activator, chosenUnlock.getStateName());
break;
case 1:
// TODO check for Lock vs Unlock first?
List<CardState> bothStates = Lists.newArrayList();
bothStates.add(c.getState(CardStateName.LeftSplit));
bothStates.add(c.getState(CardStateName.RightSplit));
CardState chosenBoth = activator.getController().chooseSingleCardState(sa, bothStates, "Choose Room to lock or unlock", params);
if (chosenBoth == null) {
continue;
}
if (c.getLockedRooms().contains(chosenBoth.getStateName())) {
c.unlockRoom(activator, chosenBoth.getStateName());
} else {
c.lockRoom(activator, chosenBoth.getStateName());
}
break;
case 2:
List<CardState> lockStates = c.getLockedRooms().stream().map(stateName -> c.getState(stateName)).collect(Collectors.toList());
// need to choose Room Name
CardState chosenLock = activator.getController().chooseSingleCardState(sa, lockStates, "Choose Room to unlock", params);
if (chosenLock == null) {
continue;
}
c.unlockRoom(activator, chosenLock.getStateName());
break;
}
break;
}
}
}
}

View File

@@ -213,6 +213,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
private boolean plotted; private boolean plotted;
private Set<CardStateName> unlockedRooms = EnumSet.noneOf(CardStateName.class);
private Map<CardStateName, SpellAbility> unlockAbilities = Maps.newEnumMap(CardStateName.class);
private boolean specialized; private boolean specialized;
private int timesCrewedThisTurn = 0; private int timesCrewedThisTurn = 0;
@@ -442,6 +445,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
if (state == CardStateName.FaceDown) { if (state == CardStateName.FaceDown) {
return getFaceDownState(); return getFaceDownState();
} }
if (state == CardStateName.EmptyRoom) {
return getEmptyRoomState();
}
CardCloneStates clStates = getLastClonedState(); CardCloneStates clStates = getLastClonedState();
if (clStates == null) { if (clStates == null) {
return getOriginalState(state); return getOriginalState(state);
@@ -450,7 +456,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
public boolean hasState(final CardStateName state) { public boolean hasState(final CardStateName state) {
if (state == CardStateName.FaceDown) { if (state == CardStateName.FaceDown || state == CardStateName.EmptyRoom) {
return true; return true;
} }
CardCloneStates clStates = getLastClonedState(); CardCloneStates clStates = getLastClonedState();
@@ -464,6 +470,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
if (state == CardStateName.FaceDown) { if (state == CardStateName.FaceDown) {
return getFaceDownState(); return getFaceDownState();
} }
if (state == CardStateName.EmptyRoom) {
return getEmptyRoomState();
}
return states.get(state); return states.get(state);
} }
@@ -490,7 +499,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
boolean needsTransformAnimation = transform || rollback; boolean needsTransformAnimation = transform || rollback;
// faceDown has higher priority over clone states // faceDown has higher priority over clone states
// while text change states doesn't apply while the card is faceDown // while text change states doesn't apply while the card is faceDown
if (state != CardStateName.FaceDown) { if (state != CardStateName.FaceDown && state != CardStateName.EmptyRoom) {
CardCloneStates cloneStates = getLastClonedState(); CardCloneStates cloneStates = getLastClonedState();
if (cloneStates != null) { if (cloneStates != null) {
if (!cloneStates.containsKey(state)) { if (!cloneStates.containsKey(state)) {
@@ -794,6 +803,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
return setState(CardStateName.FaceDown, false); return setState(CardStateName.FaceDown, false);
} }
public void forceTurnFaceUp() {
turnFaceUp(false, null);
}
public boolean turnFaceUp(SpellAbility cause) { public boolean turnFaceUp(SpellAbility cause) {
return turnFaceUp(true, cause); return turnFaceUp(true, cause);
} }
@@ -928,6 +941,10 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
return alt ? StaticData.instance().getCommonCards().getName(name, true) : name; return alt ? StaticData.instance().getCommonCards().getName(name, true) : name;
} }
public final boolean hasNameOverwrite() {
return changedCardNames.values().stream().anyMatch(CardChangedName::isOverwrite);
}
public final boolean hasNonLegendaryCreatureNames() { public final boolean hasNonLegendaryCreatureNames() {
boolean result = false; boolean result = false;
for (CardChangedName change : this.changedCardNames.values()) { for (CardChangedName change : this.changedCardNames.values()) {
@@ -1039,7 +1056,12 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
public final boolean isSplitCard() { public final boolean isSplitCard() {
return getRules() != null && getRules().getSplitType() == CardSplitType.Split; // Normal Split Cards, these need to return true before Split States are added
if (getRules() != null && getRules().getSplitType() == CardSplitType.Split) {
return true;
};
// in case or clones or copies
return hasState(CardStateName.LeftSplit);
} }
public final boolean isAdventureCard() { public final boolean isAdventureCard() {
@@ -2480,8 +2502,9 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
sbLong.append(" (").append(inst.getReminderText()).append(")"); sbLong.append(" (").append(inst.getReminderText()).append(")");
} else if (keyword.equals("Gift")) { } else if (keyword.equals("Gift")) {
sbLong.append(keyword); sbLong.append(keyword);
if (inst.getHostCard() != null && inst.getHostCard().getFirstSpellAbility().hasAdditionalAbility("GiftAbility")) { Trigger trig = inst.getTriggers().stream().findFirst().orElse(null);
sbLong.append(" ").append(inst.getHostCard().getFirstSpellAbility().getAdditionalAbility("GiftAbility").getParam("GiftDescription")); if (trig != null && trig.getCardState().getFirstSpellAbility().hasAdditionalAbility("GiftAbility")) {
sbLong.append(" ").append(trig.getCardState().getFirstSpellAbility().getAdditionalAbility("GiftAbility").getParam("GiftDescription"));
} }
sbLong.append("\r\n"); sbLong.append("\r\n");
} else if (keyword.startsWith("Starting intensity")) { } else if (keyword.startsWith("Starting intensity")) {
@@ -4083,13 +4106,7 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
if (Iterables.isEmpty(changedCardTypes)) { if (Iterables.isEmpty(changedCardTypes)) {
return state.getType(); return state.getType();
} }
// CR 506.4 attacked planeswalkers leave combat return state.getType().getTypeWithChanges(changedCardTypes);
boolean checkCombat = state.getType().isPlaneswalker() && game.getCombat() != null && !game.getCombat().getAttackersOf(this).isEmpty();
CardTypeView types = state.getType().getTypeWithChanges(changedCardTypes);
if (checkCombat && !types.isPlaneswalker()) {
game.getCombat().removeFromCombat(this);
}
return types;
} }
public final CardTypeView getOriginalType() { public final CardTypeView getOriginalType() {
@@ -5573,6 +5590,8 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
public final boolean isOutlaw() { return getType().isOutlaw(); } public final boolean isOutlaw() { return getType().isOutlaw(); }
public final boolean isRoom() { return getType().hasSubtype("Room"); }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final int compareTo(final Card that) { public final int compareTo(final Card that) {
@@ -5983,9 +6002,21 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
boolean shares = getName(true).equals(name); boolean shares = getName(true).equals(name);
// Split cards has extra logic to check if it does share a name with // Split cards has extra logic to check if it does share a name with
if (isSplitCard()) { if (!shares && !hasNameOverwrite()) {
shares |= name.equals(getState(CardStateName.LeftSplit).getName()); if (isInPlay()) {
shares |= name.equals(getState(CardStateName.RightSplit).getName()); // split cards in play are only rooms
for (String door : getUnlockedRoomNames()) {
shares |= name.equals(door);
}
} else { // not on the battlefield
if (hasState(CardStateName.LeftSplit)) {
shares |= name.equals(getState(CardStateName.LeftSplit).getName());
}
if (hasState(CardStateName.RightSplit)) {
shares |= name.equals(getState(CardStateName.RightSplit).getName());
}
}
// TODO does it need extra check for stack?
} }
if (!shares && hasNonLegendaryCreatureNames()) { if (!shares && hasNonLegendaryCreatureNames()) {
@@ -7472,6 +7503,15 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
} }
if (isInPlay() && !isPhasedOut() && player.canCastSorcery()) {
if (getCurrentStateName() == CardStateName.RightSplit || getCurrentStateName() == CardStateName.EmptyRoom) {
abilities.add(getUnlockAbility(CardStateName.LeftSplit));
}
if (getCurrentStateName() == CardStateName.LeftSplit || getCurrentStateName() == CardStateName.EmptyRoom) {
abilities.add(getUnlockAbility(CardStateName.RightSplit));
}
}
if (isInPlay() && isFaceDown() && oState.getType().isCreature() && oState.getManaCost() != null && !oState.getManaCost().isNoCost()) if (isInPlay() && isFaceDown() && oState.getType().isCreature() && oState.getManaCost() != null && !oState.getManaCost().isNoCost())
{ {
if (isManifested()) { if (isManifested()) {
@@ -7711,12 +7751,6 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
} }
public void forceTurnFaceUp() {
getGame().getTriggerHandler().suppressMode(TriggerType.TurnFaceUp);
turnFaceUp(false, null);
getGame().getTriggerHandler().clearSuppression(TriggerType.TurnFaceUp);
}
public final void addGoad(Long timestamp, final Player p) { public final void addGoad(Long timestamp, final Player p) {
goad.put(timestamp, p); goad.put(timestamp, p);
updateAbilityTextForView(); updateAbilityTextForView();
@@ -8079,4 +8113,107 @@ public class Card extends GameEntity implements Comparable<Card>, IHasSVars, ITr
} }
return StaticAbilityWitherDamage.isWitherDamage(this); return StaticAbilityWitherDamage.isWitherDamage(this);
} }
public Set<CardStateName> getUnlockedRooms() {
return this.unlockedRooms;
}
public void setUnlockedRooms(Set<CardStateName> set) {
this.unlockedRooms = set;
}
public List<String> getUnlockedRoomNames() {
List<String> result = Lists.newArrayList();
for (CardStateName stateName : unlockedRooms) {
if (this.hasState(stateName)) {
result.add(this.getState(stateName).getName());
}
}
return result;
}
public Set<CardStateName> getLockedRooms() {
Set<CardStateName> result = Sets.newHashSet(CardStateName.LeftSplit, CardStateName.RightSplit);
result.removeAll(this.unlockedRooms);
return result;
}
public List<String> getLockedRoomNames() {
List<String> result = Lists.newArrayList();
for (CardStateName stateName : getLockedRooms()) {
if (this.hasState(stateName)) {
result.add(this.getState(stateName).getName());
}
}
return result;
}
public boolean unlockRoom(Player p, CardStateName stateName) {
if (unlockedRooms.contains(stateName) || (stateName != CardStateName.LeftSplit && stateName != CardStateName.RightSplit)) {
return false;
}
unlockedRooms.add(stateName);
updateRooms();
Map<AbilityKey, Object> unlockParams = AbilityKey.mapFromPlayer(p);
unlockParams.put(AbilityKey.Card, this);
unlockParams.put(AbilityKey.CardState, getState(stateName));
getGame().getTriggerHandler().runTrigger(TriggerType.UnlockDoor, unlockParams, true);
// fully unlock
if (unlockedRooms.size() > 1) {
Map<AbilityKey, Object> fullyUnlockParams = AbilityKey.mapFromPlayer(p);
fullyUnlockParams.put(AbilityKey.Card, this);
getGame().getTriggerHandler().runTrigger(TriggerType.FullyUnlock, fullyUnlockParams, true);
}
return true;
}
public boolean lockRoom(Player p, CardStateName stateName) {
if (!unlockedRooms.contains(stateName) || (stateName != CardStateName.LeftSplit && stateName != CardStateName.RightSplit)) {
return false;
}
unlockedRooms.remove(stateName);
updateRooms();
return true;
}
public void updateRooms() {
if (!this.isRoom()) {
return;
}
if (this.isFaceDown()) {
return;
}
if (unlockedRooms.isEmpty()) {
this.setState(CardStateName.EmptyRoom, true);
} else if (unlockedRooms.size() > 1) {
this.setState(CardStateName.Original, true);
} else { // we already know the set is only one
for (CardStateName name : unlockedRooms) {
this.setState(name, true);
}
}
// update trigger after state change
getGame().getTriggerHandler().clearActiveTriggers(this, null);
getGame().getTriggerHandler().registerActiveTrigger(this, false);
}
public CardState getEmptyRoomState() {
if (!states.containsKey(CardStateName.EmptyRoom)) {
states.put(CardStateName.EmptyRoom, CardUtil.getEmptyRoomCharacteristic(this));
}
return states.get(CardStateName.EmptyRoom);
}
public SpellAbility getUnlockAbility(CardStateName state) {
if (!unlockAbilities.containsKey(state)) {
unlockAbilities.put(state, CardFactoryUtil.abilityUnlockRoom(getState(state)));
}
return unlockAbilities.get(state);
}
} }

View File

@@ -33,6 +33,7 @@ import forge.game.cost.Cost;
import forge.game.keyword.Keyword; import forge.game.keyword.Keyword;
import forge.game.keyword.KeywordInterface; import forge.game.keyword.KeywordInterface;
import forge.game.player.Player; import forge.game.player.Player;
import forge.game.replacement.ReplacementEffect;
import forge.game.replacement.ReplacementHandler; import forge.game.replacement.ReplacementHandler;
import forge.game.spellability.*; import forge.game.spellability.*;
import forge.game.staticability.StaticAbility; import forge.game.staticability.StaticAbility;
@@ -261,6 +262,21 @@ public class CardFactory {
final CardState original = card.getState(CardStateName.Original); final CardState original = card.getState(CardStateName.Original);
original.addNonManaAbilities(card.getCurrentState().getNonManaAbilities()); original.addNonManaAbilities(card.getCurrentState().getNonManaAbilities());
original.addIntrinsicKeywords(card.getCurrentState().getIntrinsicKeywords()); // Copy 'Fuse' to original side original.addIntrinsicKeywords(card.getCurrentState().getIntrinsicKeywords()); // Copy 'Fuse' to original side
for (Trigger t : card.getCurrentState().getTriggers()) {
if (t.isIntrinsic()) {
original.addTrigger(t.copy(card, false));
}
}
for (StaticAbility st : card.getCurrentState().getStaticAbilities()) {
if (st.isIntrinsic()) {
original.addStaticAbility(st.copy(card, false));
}
}
for (ReplacementEffect re : card.getCurrentState().getReplacementEffects()) {
if (re.isIntrinsic()) {
original.addReplacementEffect(re.copy(card, false));
}
}
original.getSVars().putAll(card.getCurrentState().getSVars()); // Unfortunately need to copy these to (Effect looks for sVars on execute) original.getSVars().putAll(card.getCurrentState().getSVars()); // Unfortunately need to copy these to (Effect looks for sVars on execute)
} else if (state != CardStateName.Original) { } else if (state != CardStateName.Original) {
CardFactoryUtil.setupKeywordedAbilities(card); CardFactoryUtil.setupKeywordedAbilities(card);
@@ -418,7 +434,11 @@ public class CardFactory {
c.setAttractionLights(face.getAttractionLights()); c.setAttractionLights(face.getAttractionLights());
// SpellPermanent only for Original State // SpellPermanent only for Original State
if (c.getCurrentStateName() == CardStateName.Original || c.getCurrentStateName() == CardStateName.Modal || c.getCurrentStateName().toString().startsWith("Specialize")) { if (c.getCurrentStateName() == CardStateName.Original ||
c.getCurrentStateName() == CardStateName.LeftSplit ||
c.getCurrentStateName() == CardStateName.RightSplit ||
c.getCurrentStateName() == CardStateName.Modal ||
c.getCurrentStateName().toString().startsWith("Specialize")) {
if (c.isLand()) { if (c.isLand()) {
SpellAbility sa = new LandAbility(c); SpellAbility sa = new LandAbility(c);
sa.setCardState(c.getCurrentState()); sa.setCardState(c.getCurrentState());

View File

@@ -118,6 +118,12 @@ public class CardFactoryUtil {
return morphDown; return morphDown;
} }
public static SpellAbility abilityUnlockRoom(CardState cardState) {
String unlockStr = "ST$ UnlockDoor | Cost$ " + cardState.getManaCost().getShortString() + " | Unlock$ True | SpellDescription$ Unlock " + cardState.getName();
return AbilityFactory.getAbility(unlockStr, cardState);
}
/** /**
* <p> * <p>
* abilityMorphUp. * abilityMorphUp.

View File

@@ -1133,10 +1133,6 @@ public class CardProperty {
if (!card.isFirstTurnControlled()) { if (!card.isFirstTurnControlled()) {
return false; return false;
} }
} else if (property.startsWith("notFirstTurnControlled")) {
if (card.isFirstTurnControlled()) {
return false;
}
} else if (property.startsWith("startedTheTurnUntapped")) { } else if (property.startsWith("startedTheTurnUntapped")) {
if (!card.hasStartedTheTurnUntapped()) { if (!card.hasStartedTheTurnUntapped()) {
return false; return false;

View File

@@ -216,6 +216,24 @@ public final class CardUtil {
return ret; return ret;
} }
public static CardState getEmptyRoomCharacteristic(Card c) {
return getEmptyRoomCharacteristic(c, CardStateName.EmptyRoom);
}
public static CardState getEmptyRoomCharacteristic(Card c, CardStateName state) {
final CardType type = new CardType(false);
type.add("Enchantment");
type.add("Room");
final CardState ret = new CardState(c, state);
ret.setName("");
ret.setType(type);
// find new image key for empty room
ret.setImageKey(c.getImageKey());
return ret;
}
// a nice entry point with minimum parameters // a nice entry point with minimum parameters
public static Set<String> getReflectableManaColors(final SpellAbility sa) { public static Set<String> getReflectableManaColors(final SpellAbility sa) {
return getReflectableManaColors(sa, sa, Sets.newHashSet(), new CardCollection()); return getReflectableManaColors(sa, sa, Sets.newHashSet(), new CardCollection());

View File

@@ -1,6 +1,7 @@
package forge.game.card; package forge.game.card;
import com.google.common.collect.Iterables; import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import forge.ImageKeys; import forge.ImageKeys;
import forge.StaticData; import forge.StaticData;
@@ -40,6 +41,14 @@ public class CardView extends GameEntityView {
return s == null ? null : s.getView(); return s == null ? null : s.getView();
} }
public static Map<CardStateView, CardState> getStateMap(Iterable<CardState> states) {
Map<CardStateView, CardState> stateViewCache = Maps.newLinkedHashMap();
for (CardState state : states) {
stateViewCache.put(state.getView(), state);
}
return stateViewCache;
}
public CardView getBackup() { public CardView getBackup() {
if (get(TrackableProperty.PaperCardBackup) == null) if (get(TrackableProperty.PaperCardBackup) == null)
return null; return null;
@@ -795,7 +804,7 @@ public class CardView extends GameEntityView {
sb.append(getOwner().getCommanderInfo(this)).append("\r\n"); sb.append(getOwner().getCommanderInfo(this)).append("\r\n");
} }
if (isSplitCard() && !isFaceDown() && getZone() != ZoneType.Stack) { if (isSplitCard() && !isFaceDown() && getZone() != ZoneType.Stack && getZone() != ZoneType.Battlefield) {
sb.append("(").append(getLeftSplitState().getName()).append(") "); sb.append("(").append(getLeftSplitState().getName()).append(") ");
sb.append(getLeftSplitState().getAbilityText()); sb.append(getLeftSplitState().getAbilityText());
sb.append("\r\n\r\n").append("(").append(getRightSplitState().getName()).append(") "); sb.append("\r\n\r\n").append("(").append(getRightSplitState().getName()).append(") ");
@@ -1183,6 +1192,11 @@ public class CardView extends GameEntityView {
return StringUtils.EMPTY; return StringUtils.EMPTY;
} }
@Override
public int hashCode() {
return Objects.hash(getId(), state);
}
@Override @Override
public String toString() { public String toString() {
return (getName() + " (" + getDisplayId() + ")").trim(); return (getName() + " (" + getDisplayId() + ")").trim();

View File

@@ -632,7 +632,7 @@ public class Combat {
} }
public final boolean removeAbsentCombatants() { public final boolean removeAbsentCombatants() {
// iterate all attackers and remove illegal declarations // CR 506.4 iterate all attackers and remove illegal declarations
CardCollection missingCombatants = new CardCollection(); CardCollection missingCombatants = new CardCollection();
for (Entry<GameEntity, AttackingBand> ee : attackedByBands.entries()) { for (Entry<GameEntity, AttackingBand> ee : attackedByBands.entries()) {
for (Card c : ee.getValue().getAttackers()) { for (Card c : ee.getValue().getAttackers()) {
@@ -640,6 +640,12 @@ public class Combat {
missingCombatants.add(c); missingCombatants.add(c);
} }
} }
if (ee.getKey() instanceof Card) {
Card c = (Card) ee.getKey();
if (!c.isBattle() && !c.isPlaneswalker()) {
missingCombatants.add(c);
}
}
} }
for (Entry<AttackingBand, Card> be : blockedBands.entries()) { for (Entry<AttackingBand, Card> be : blockedBands.entries()) {

View File

@@ -71,7 +71,7 @@ public class PhaseHandler implements java.io.Serializable {
private int nUpkeepsThisTurn = 0; private int nUpkeepsThisTurn = 0;
private int nUpkeepsThisGame = 0; private int nUpkeepsThisGame = 0;
private int nCombatsThisTurn = 0; private int nCombatsThisTurn = 0;
private int nMain2sThisTurn = 0; private int nMainsThisTurn = 0;
private int planarDiceSpecialActionThisTurn = 0; private int planarDiceSpecialActionThisTurn = 0;
private transient Player playerTurn = null; private transient Player playerTurn = null;
@@ -266,23 +266,26 @@ public class PhaseHandler implements java.io.Serializable {
break; break;
case MAIN1: case MAIN1:
{ nMainsThisTurn++;
if (playerTurn.isArchenemy()) {
playerTurn.setSchemeInMotion(null); if (playerTurn.isArchenemy()) {
} playerTurn.setSchemeInMotion(null);
GameEntityCounterTable table = new GameEntityCounterTable();
// all Sagas get a Lore counter at the beginning of pre combat
for (Card c : playerTurn.getCardsIn(ZoneType.Battlefield)) {
if (c.isSaga()) {
c.addCounter(CounterEnumType.LORE, 1, playerTurn, table);
}
}
// roll for attractions if we have any
if (playerTurn.getCardsIn(ZoneType.Battlefield).anyMatch(CardPredicates.ATTRACTIONS)) {
playerTurn.rollToVisitAttractions();
}
table.replaceCounterEffect(game, null, false);
} }
GameEntityCounterTable table = new GameEntityCounterTable();
// all Sagas get a Lore counter at the beginning of pre combat
for (Card c : playerTurn.getCardsIn(ZoneType.Battlefield)) {
if (c.isSaga()) {
c.addCounter(CounterEnumType.LORE, 1, playerTurn, table);
}
}
table.replaceCounterEffect(game, null, false);
// roll for attractions if we have any
if (playerTurn.getCardsIn(ZoneType.Battlefield).anyMatch(CardPredicates.ATTRACTIONS)) {
playerTurn.rollToVisitAttractions();
}
break; break;
case COMBAT_BEGIN: case COMBAT_BEGIN:
@@ -343,6 +346,7 @@ public class PhaseHandler implements java.io.Serializable {
break; break;
case MAIN2: case MAIN2:
nMainsThisTurn++;
//SDisplayUtil.showTab(EDocID.REPORT_STACK.getDoc()); //SDisplayUtil.showTab(EDocID.REPORT_STACK.getDoc());
break; break;
@@ -362,9 +366,9 @@ public class PhaseHandler implements java.io.Serializable {
int numDiscard = playerTurn.isUnlimitedHandSize() || handSize <= max || handSize == 0 ? 0 : handSize - max; int numDiscard = playerTurn.isUnlimitedHandSize() || handSize <= max || handSize == 0 ? 0 : handSize - max;
if (numDiscard > 0) { if (numDiscard > 0) {
final CardZoneTable table = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard()); final CardZoneTable zoneMovements = new CardZoneTable(game.getLastStateBattlefield(), game.getLastStateGraveyard());
Map<AbilityKey, Object> moveParams = AbilityKey.newMap(); Map<AbilityKey, Object> moveParams = AbilityKey.newMap();
AbilityKey.addCardZoneTableParams(moveParams, table); AbilityKey.addCardZoneTableParams(moveParams, zoneMovements);
final CardCollection discarded = new CardCollection(); final CardCollection discarded = new CardCollection();
List<Card> discardedBefore = Lists.newArrayList(playerTurn.getDiscardedThisTurn()); List<Card> discardedBefore = Lists.newArrayList(playerTurn.getDiscardedThisTurn());
@@ -374,7 +378,7 @@ public class PhaseHandler implements java.io.Serializable {
discarded.add(moved); discarded.add(moved);
} }
} }
table.triggerChangesZoneAll(game, null); zoneMovements.triggerChangesZoneAll(game, null);
if (!discarded.isEmpty()) { if (!discarded.isEmpty()) {
final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(playerTurn); final Map<AbilityKey, Object> runParams = AbilityKey.mapFromPlayer(playerTurn);
@@ -402,7 +406,7 @@ public class PhaseHandler implements java.io.Serializable {
nUpkeepsThisTurn = 0; nUpkeepsThisTurn = 0;
nCombatsThisTurn = 0; nCombatsThisTurn = 0;
nMain2sThisTurn = 0; nMainsThisTurn = 0;
game.getStack().resetMaxDistinctSources(); game.getStack().resetMaxDistinctSources();
// Rule 514.3 // Rule 514.3
@@ -487,10 +491,6 @@ public class PhaseHandler implements java.io.Serializable {
} }
break; break;
case MAIN2:
nMain2sThisTurn++;
break;
case CLEANUP: case CLEANUP:
if (!bRepeatCleanup) { if (!bRepeatCleanup) {
// only call onCleanupPhase when Cleanup is not repeated // only call onCleanupPhase when Cleanup is not repeated
@@ -975,8 +975,12 @@ public class PhaseHandler implements java.io.Serializable {
return is(PhaseType.UPKEEP) && nUpkeepsThisGame == 0; return is(PhaseType.UPKEEP) && nUpkeepsThisGame == 0;
} }
public final int getNumMain() {
return nMainsThisTurn;
}
public final boolean beforeFirstPostCombatMainEnd() { public final boolean beforeFirstPostCombatMainEnd() {
return nMain2sThisTurn == 0; return nMainsThisTurn <= (is(PhaseType.MAIN2) ? 2 : 1);
} }
public final boolean skippedDeclareBlockers() { public final boolean skippedDeclareBlockers() {

View File

@@ -116,6 +116,9 @@ public enum PhaseType {
String sTo = s.substring(idxArrow + 2); String sTo = s.substring(idxArrow + 2);
PhaseType to = StringUtils.isBlank(sTo) ? PhaseType.CLEANUP : PhaseType.smartValueOf(sTo); PhaseType to = StringUtils.isBlank(sTo) ? PhaseType.CLEANUP : PhaseType.smartValueOf(sTo);
result.addAll(EnumSet.range(from, to)); result.addAll(EnumSet.range(from, to));
} else if (s.equals("Main")) {
result.add(MAIN1);
result.add(MAIN2);
} else { } else {
result.add(PhaseType.smartValueOf(s)); result.add(PhaseType.smartValueOf(s));
} }

View File

@@ -62,6 +62,8 @@ import org.apache.commons.lang3.tuple.Pair;
import java.util.*; import java.util.*;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.function.Function; import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/** /**
* <p> * <p>
@@ -298,7 +300,7 @@ public class Player extends GameEntity implements Comparable<Player> {
* Should keep player relations somewhere in the match structure * Should keep player relations somewhere in the match structure
*/ */
public final PlayerCollection getOpponents() { public final PlayerCollection getOpponents() {
return game.getPlayers().filter(PlayerPredicates.isOpponentOf(this)); return game.getPlayersInTurnOrder(this).filter(PlayerPredicates.isOpponentOf(this));
} }
public final PlayerCollection getRegisteredOpponents() { public final PlayerCollection getRegisteredOpponents() {
@@ -3951,4 +3953,12 @@ public class Player extends GameEntity implements Comparable<Player> {
Map.Entry<Long, Player> e = declaresBlockers.lastEntry(); Map.Entry<Long, Player> e = declaresBlockers.lastEntry();
return e == null ? null : e.getValue(); return e == null ? null : e.getValue();
} }
public List<String> getUnlockedDoors() {
return StreamSupport.stream(getCardsIn(ZoneType.Battlefield).spliterator(), false)
.filter(Card::isRoom)
.map(Card::getUnlockedRoomNames)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
} }

View File

@@ -173,6 +173,13 @@ public abstract class PlayerController {
public abstract ImmutablePair<CardCollection, CardCollection> arrangeForSurveil(CardCollection topN); public abstract ImmutablePair<CardCollection, CardCollection> arrangeForSurveil(CardCollection topN);
public abstract boolean willPutCardOnTop(Card c); public abstract boolean willPutCardOnTop(Card c);
/**
* Prompts the player to choose the order for cards being moved into a zone.
* The cards will be returned in the order that they should be moved, one at a time,
* to the given zone and position. Be aware that when moving cards to the top of a
* deck, this will be the reverse of the order they will ultimately end up in.
*/
public abstract CardCollectionView orderMoveToZoneList(CardCollectionView cards, ZoneType destinationZone, SpellAbility source); public abstract CardCollectionView orderMoveToZoneList(CardCollectionView cards, ZoneType destinationZone, SpellAbility source);
/** p = target player, validCards - possible discards, min cards to discard */ /** p = target player, validCards - possible discards, min cards to discard */
@@ -236,6 +243,8 @@ public abstract class PlayerController {
public abstract byte chooseColorAllowColorless(String message, Card c, ColorSet colors); public abstract byte chooseColorAllowColorless(String message, Card c, ColorSet colors);
public abstract ICardFace chooseSingleCardFace(SpellAbility sa, String message, Predicate<ICardFace> cpp, String name); public abstract ICardFace chooseSingleCardFace(SpellAbility sa, String message, Predicate<ICardFace> cpp, String name);
public abstract ICardFace chooseSingleCardFace(SpellAbility sa, List<ICardFace> faces, String message);
public abstract CardState chooseSingleCardState(SpellAbility sa, List<CardState> states, String message, Map<String, Object> params);
public abstract List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options); public abstract List<String> chooseColors(String message, SpellAbility sa, int min, int max, List<String> options);
public abstract CounterType chooseCounterType(List<CounterType> options, SpellAbility sa, String prompt, Map<String, Object> params); public abstract CounterType chooseCounterType(List<CounterType> options, SpellAbility sa, String prompt, Map<String, Object> params);

View File

@@ -583,7 +583,6 @@ public abstract class SpellAbility extends CardTraitBase implements ISpellAbilit
public ApiType getApi() { public ApiType getApi() {
return api; return api;
} }
public void setApi(ApiType apiType) { public void setApi(ApiType apiType) {
api = apiType; api = apiType;
} }

View File

@@ -239,6 +239,10 @@ public abstract class Trigger extends TriggerReplacementBase {
if (!validPhases.contains(phaseHandler.getPhase())) { if (!validPhases.contains(phaseHandler.getPhase())) {
return false; return false;
} }
// add support for calculation if needed
if (hasParam("PhaseCount") && phaseHandler.getNumMain() + 1 != 2) {
return false;
}
} }
if (hasParam("PlayerTurn")) { if (hasParam("PlayerTurn")) {

View File

@@ -38,7 +38,6 @@ import forge.game.player.Player;
import forge.game.spellability.SpellAbility; import forge.game.spellability.SpellAbility;
import forge.game.spellability.SpellAbilityStackInstance; import forge.game.spellability.SpellAbilityStackInstance;
import forge.game.spellability.TargetChoices; import forge.game.spellability.TargetChoices;
import forge.game.zone.ZoneType;
import forge.util.Expressions; import forge.util.Expressions;
import forge.util.Localizer; import forge.util.Localizer;
import forge.util.collect.FCollection; import forge.util.collect.FCollection;
@@ -229,23 +228,6 @@ public class TriggerSpellAbilityCastOrCopy extends Trigger {
} }
} }
if (hasParam("SharesNameWithActivatorsZone")) {
String zones = getParam("SharesNameWithActivatorsZone");
if (si == null) {
return false;
}
boolean sameNameFound = false;
for (Card c: si.getSpellAbility().getActivatingPlayer().getCardsIn(ZoneType.listValueOf(zones))) {
if (cast.getName().equals(c.getName())) {
sameNameFound = true;
break;
}
}
if (!sameNameFound) {
return false;
}
}
if (hasParam("NoColoredMana")) { if (hasParam("NoColoredMana")) {
for (Mana m : spellAbility.getPayingMana()) { for (Mana m : spellAbility.getPayingMana()) {
if (!m.isColorless()) { if (!m.isColorless()) {

View File

@@ -144,6 +144,7 @@ public enum TriggerType {
TurnBegin(TriggerTurnBegin.class), TurnBegin(TriggerTurnBegin.class),
TurnFaceUp(TriggerTurnFaceUp.class), TurnFaceUp(TriggerTurnFaceUp.class),
Unattach(TriggerUnattach.class), Unattach(TriggerUnattach.class),
UnlockDoor(TriggerUnlockDoor.class),
UntapAll(TriggerUntapAll.class), UntapAll(TriggerUntapAll.class),
Untaps(TriggerUntaps.class), Untaps(TriggerUntaps.class),
VisitAttraction(TriggerVisitAttraction.class), VisitAttraction(TriggerVisitAttraction.class),

View File

@@ -0,0 +1,55 @@
package forge.game.trigger;
import java.util.Map;
import forge.game.ability.AbilityKey;
import forge.game.card.Card;
import forge.game.card.CardState;
import forge.game.spellability.SpellAbility;
import forge.util.Localizer;
public class TriggerUnlockDoor extends Trigger {
public TriggerUnlockDoor(final Map<String, String> params, final Card host, final boolean intrinsic) {
super(params, host, intrinsic);
}
@Override
public boolean performTest(Map<AbilityKey, Object> runParams) {
if (!matchesValidParam("ValidCard", runParams.get(AbilityKey.Card))) {
return false;
}
if (!matchesValidParam("ValidPlayer", runParams.get(AbilityKey.Player))) {
return false;
}
if (hasParam("ThisDoor")) {
CardState state = (CardState) runParams.get(AbilityKey.CardState);
// This Card
if (!getHostCard().equals(state.getCard())) {
return false;
}
// This Face
if (!getCardStateName().equals(state.getStateName())) {
return false;
}
}
return true;
}
@Override
public void setTriggeringObjects(SpellAbility sa, Map<AbilityKey, Object> runParams) {
sa.setTriggeringObjectsFrom(runParams, AbilityKey.Card, AbilityKey.Player);
}
@Override
public String getImportantStackObjects(SpellAbility sa) {
StringBuilder sb = new StringBuilder();
sb.append(Localizer.getInstance().getMessage("lblPlayer")).append(": ").append(sa.getTriggeringObject(AbilityKey.Player));
sb.append(", ").append(Localizer.getInstance().getMessage("lblCard")).append(": ").append(sa.getTriggeringObject(AbilityKey.Card));
return sb.toString();
}
}

View File

@@ -3,7 +3,7 @@ package forge.game.zone;
import forge.util.Localizer; import forge.util.Localizer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.EnumSet;
import java.util.List; import java.util.List;
/** /**
@@ -30,8 +30,9 @@ public enum ZoneType {
ExtraHand(true, "lblHandZone"), ExtraHand(true, "lblHandZone"),
None(true, "lblNoneZone"); None(true, "lblNoneZone");
public static final List<ZoneType> STATIC_ABILITIES_SOURCE_ZONES = Arrays.asList(Battlefield, Graveyard, Exile, Command, Stack/*, Hand*/); public static final EnumSet<ZoneType> STATIC_ABILITIES_SOURCE_ZONES = EnumSet.of(Battlefield, Graveyard, Exile, Command, Stack/*, Hand*/);
public static final List<ZoneType> PART_OF_COMMAND_ZONE = Arrays.asList(Command, SchemeDeck, PlanarDeck, AttractionDeck, Junkyard); public static final EnumSet<ZoneType> PART_OF_COMMAND_ZONE = EnumSet.of(Command, SchemeDeck, PlanarDeck, AttractionDeck, Junkyard);
public static final EnumSet<ZoneType> DECK_ZONES = EnumSet.of(Library, SchemeDeck, PlanarDeck, AttractionDeck);
private final boolean holdsHiddenInfo; private final boolean holdsHiddenInfo;
private final String zoneName; private final String zoneName;
@@ -79,6 +80,14 @@ public enum ZoneType {
return PART_OF_COMMAND_ZONE.contains(this); return PART_OF_COMMAND_ZONE.contains(this);
} }
/**
* Indicates that this zone behaves as a deck - an ordered pile of face down cards
* such as the Library or Planar Deck.
*/
public boolean isDeck() {
return DECK_ZONES.contains(this);
}
public String getTranslatedName() { public String getTranslatedName() {
return zoneName; return zoneName;
} }

View File

@@ -47,7 +47,7 @@ public abstract class TrackableObject implements IIdentifiable, Serializable {
@Override @Override
public final boolean equals(final Object o) { public final boolean equals(final Object o) {
if (o == null) { return false; } if (o == null) { return false; }
return o.hashCode() == id && o.getClass().equals(getClass()); return o.hashCode() == hashCode() && o.getClass().equals(getClass());
} }
// don't know if this is really needed, but don't know a better way // don't know if this is really needed, but don't know a better way

View File

@@ -198,7 +198,7 @@ public class CardDetailPanel extends SkinnedPanel {
nameCost = name; nameCost = name;
} else { } else {
final String manaCost; final String manaCost;
if (card.isSplitCard() && card.hasAlternateState() && !card.isFaceDown() && card.getZone() != ZoneType.Stack) { //only display current state's mana cost when on stack if (card.isSplitCard() && card.hasAlternateState() && !card.isFaceDown() && card.getZone() != ZoneType.Stack && card.getZone() != ZoneType.Battlefield) { //only display current state's mana cost when on stack
manaCost = card.getLeftSplitState().getManaCost() + " // " + card.getAlternateState().getManaCost(); manaCost = card.getLeftSplitState().getManaCost() + " // " + card.getAlternateState().getManaCost();
} else { } else {
manaCost = state.getManaCost().toString(); manaCost = state.getManaCost().toString();

View File

@@ -23,6 +23,7 @@ import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import forge.card.CardRarity; import forge.card.CardRarity;
import forge.card.CardStateName;
import forge.card.mana.ManaCost; import forge.card.mana.ManaCost;
import forge.game.card.CardView; import forge.game.card.CardView;
import forge.game.card.CardView.CardStateView; import forge.game.card.CardView.CardStateView;
@@ -748,8 +749,11 @@ public class FCardImageRenderer {
//draw type //draw type
x += padding; x += padding;
w -= padding; w -= padding;
String typeLine = CardDetailUtil.formatCardType(state, true).replace(" - ", ""); // check for shared type line
drawVerticallyCenteredString(g, typeLine, new Rectangle(x, y, w, h), TYPE_FONT, TYPE_SIZE); if (!state.getType().hasStringType("Room") || state.getState() != CardStateName.RightSplit) {
String typeLine = CardDetailUtil.formatCardType(state, true).replace(" - ", "");
drawVerticallyCenteredString(g, typeLine, new Rectangle(x, y, w, h), TYPE_FONT, TYPE_SIZE);
}
} }
/** /**

View File

@@ -479,12 +479,15 @@ public class CardPanel extends SkinnedPanel implements CardContainer, IDisposabl
private void displayIconOverlay(final Graphics g, final boolean canShow) { private void displayIconOverlay(final Graphics g, final boolean canShow) {
if (canShow && showCardManaCostOverlay() && cardWidth < 200) { if (canShow && showCardManaCostOverlay() && cardWidth < 200) {
final boolean showSplitMana = card.isSplitCard(); final boolean showSplitMana = card.isSplitCard() && card.getZone() != ZoneType.Battlefield;
if (!showSplitMana) { if (!showSplitMana) {
drawManaCost(g, card.getCurrentState().getManaCost(), 0); drawManaCost(g, card.getCurrentState().getManaCost(), 0);
} else { } else {
if (!card.isFaceDown()) { // no need to draw mana symbols on face down split cards (e.g. manifested) if (!card.isFaceDown()) { // no need to draw mana symbols on face down split cards (e.g. manifested)
PaperCard pc = StaticData.instance().getCommonCards().getCard(card.getName()); PaperCard pc = null;
if (!card.getName().isEmpty()) {
pc = StaticData.instance().getCommonCards().getCard(card.getName());
}
int ofs = pc != null && Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH) ? -12 : 12; int ofs = pc != null && Card.getCardForUi(pc).hasKeyword(Keyword.AFTERMATH) ? -12 : 12;
drawManaCost(g, card.getLeftSplitState().getManaCost(), ofs); drawManaCost(g, card.getLeftSplitState().getManaCost(), ofs);

View File

@@ -727,6 +727,18 @@ public class PlayerControllerForTests extends PlayerController {
return null; return null;
} }
@Override
public ICardFace chooseSingleCardFace(SpellAbility sa, List<ICardFace> faces, String message) {
// TODO Auto-generated method stub
return null;
}
@Override
public CardState chooseSingleCardState(SpellAbility sa, List<CardState> states, String message, Map<String, Object> params) {
// TODO Auto-generated method stub
return null;
}
@Override @Override
public Card chooseDungeon(Player player, List<PaperCard> dungeonCards, String message) { public Card chooseDungeon(Player player, List<PaperCard> dungeonCards, String message) {
// TODO Auto-generated method stub // TODO Auto-generated method stub

View File

@@ -48,9 +48,14 @@ public class EffectData implements Serializable {
if(C != null) if(C != null)
startCards.add(C); startCards.add(C);
else { else {
PaperToken T = FModel.getMagicDb().getAllTokens().getToken(name); try {
if (T != null) startCards.add(T); PaperToken T = FModel.getMagicDb().getAllTokens().getToken(name);
else System.err.print("Can not find card \"" + name + "\"\n"); if (T != null) startCards.add(T);
else System.err.print("Can not find card/token \"" + name + "\"\n");
} catch (Exception e) {
//if it's not found probably the item is using funny cards and the users setting disabled non legal cards
System.err.print("Can not find card/token \"" + name + "\"\n");
}
} }
} }
} }
@@ -65,9 +70,14 @@ public class EffectData implements Serializable {
if(C != null) if(C != null)
startCardsInCommandZone.add(C); startCardsInCommandZone.add(C);
else { else {
PaperToken T = FModel.getMagicDb().getAllTokens().getToken(name); try {
if (T != null) startCardsInCommandZone.add(T); PaperToken T = FModel.getMagicDb().getAllTokens().getToken(name);
else System.err.print("Can not find card \"" + name + "\"\n"); if (T != null) startCardsInCommandZone.add(T);
else System.err.print("Can not find card/token \"" + name + "\"\n");
} catch (Exception e) {
//if it's not found probably the item is using funny cards and the users setting disabled non legal cards
System.err.print("Can not find card/token \"" + name + "\"\n");
}
} }
} }
} }

View File

@@ -39,7 +39,7 @@ public class SpellSmithScene extends UIScene {
private List<PaperCard> cardPool = new ArrayList<>(); private List<PaperCard> cardPool = new ArrayList<>();
private TextraLabel playerGold, playerShards, poolSize; private TextraLabel playerGold, playerShards, poolSize;
private final TextraButton pullUsingGold, pullUsingShards; private final TextraButton pullUsingGold, pullUsingShards, acceptReward, declineReward, exitSmith;
private final ScrollPane rewardDummy; private final ScrollPane rewardDummy;
private RewardActor rewardActor; private RewardActor rewardActor;
SelectBox<CardEdition> editionList; SelectBox<CardEdition> editionList;
@@ -47,6 +47,7 @@ public class SpellSmithScene extends UIScene {
final private HashMap<String, TextraButton> rarityButtons = new HashMap<>(); final private HashMap<String, TextraButton> rarityButtons = new HashMap<>();
final private HashMap<String, TextraButton> costButtons = new HashMap<>(); final private HashMap<String, TextraButton> costButtons = new HashMap<>();
final private HashMap<String, TextraButton> colorButtons = new HashMap<>(); final private HashMap<String, TextraButton> colorButtons = new HashMap<>();
//Filter variables. //Filter variables.
private String edition = ""; private String edition = "";
private String rarity = ""; private String rarity = "";
@@ -57,20 +58,28 @@ public class SpellSmithScene extends UIScene {
private int currentPrice = 0; private int currentPrice = 0;
private int currentShardPrice = 0; private int currentShardPrice = 0;
private List<CardEdition> editions = null; private List<CardEdition> editions = null;
private Reward currentReward = null;
private boolean paidInShards = false;
private SpellSmithScene() { private SpellSmithScene() {
super(Forge.isLandscapeMode() ? "ui/spellsmith.json" : "ui/spellsmith_portrait.json"); super(Forge.isLandscapeMode() ? "ui/spellsmith.json" : "ui/spellsmith_portrait.json");
editionList = ui.findActor("BSelectPlane"); editionList = ui.findActor("BSelectPlane");
rewardDummy = ui.findActor("RewardDummy"); rewardDummy = ui.findActor("RewardDummy");
rewardDummy.setVisible(false); rewardDummy.setVisible(false);
pullUsingGold = ui.findActor("pullUsingGold"); pullUsingGold = ui.findActor("pullUsingGold");
pullUsingGold.setDisabled(true); pullUsingGold.setDisabled(true);
pullUsingShards = ui.findActor("pullUsingShards"); pullUsingShards = ui.findActor("pullUsingShards");
pullUsingShards.setDisabled(true); pullUsingShards.setDisabled(true);
exitSmith = ui.findActor("done");
acceptReward = ui.findActor("accept");
acceptReward.setVisible(false);
declineReward = ui.findActor("decline");
declineReward.setVisible(false);
playerGold = Controls.newAccountingLabel(ui.findActor("playerGold"), false); playerGold = Controls.newAccountingLabel(ui.findActor("playerGold"), false);
playerShards = Controls.newAccountingLabel(ui.findActor("playerShards"), true); playerShards = Controls.newAccountingLabel(ui.findActor("playerShards"), true);
poolSize = ui.findActor("poolSize"); poolSize = ui.findActor("poolSize");
@@ -114,6 +123,8 @@ public class SpellSmithScene extends UIScene {
} }
} }
ui.onButtonPress("accept", SpellSmithScene.this::acceptSmithing);
ui.onButtonPress("decline", SpellSmithScene.this::declineSmithing);
ui.onButtonPress("done", SpellSmithScene.this::done); ui.onButtonPress("done", SpellSmithScene.this::done);
ui.onButtonPress("pullUsingGold", () -> SpellSmithScene.this.pullCard(false)); ui.onButtonPress("pullUsingGold", () -> SpellSmithScene.this.pullCard(false));
ui.onButtonPress("pullUsingShards", () -> SpellSmithScene.this.pullCard(true)); ui.onButtonPress("pullUsingShards", () -> SpellSmithScene.this.pullCard(true));
@@ -122,6 +133,7 @@ public class SpellSmithScene extends UIScene {
filterResults(); filterResults();
}); });
} }
private void reset() { private void reset() {
edition = ""; edition = "";
cost_low = -1; cost_low = -1;
@@ -160,6 +172,10 @@ public class SpellSmithScene extends UIScene {
} }
public boolean done() { public boolean done() {
if (currentReward != null) {
acceptSmithing();
}
if (rewardActor != null) rewardActor.remove(); if (rewardActor != null) rewardActor.remove();
cardPool.clear(); //Get rid of cardPool, filtering is fast enough to justify keeping it cached. cardPool.clear(); //Get rid of cardPool, filtering is fast enough to justify keeping it cached.
Forge.switchToLast(); Forge.switchToLast();
@@ -380,29 +396,74 @@ public class SpellSmithScene extends UIScene {
} }
public void pullCard(boolean usingShards) { public void pullCard(boolean usingShards) {
paidInShards = usingShards;
PaperCard P = cardPool.get(MyRandom.getRandom().nextInt(cardPool.size())); //Don't use the standard RNG. PaperCard P = cardPool.get(MyRandom.getRandom().nextInt(cardPool.size())); //Don't use the standard RNG.
Reward R = null; currentReward = null;
if (Config.instance().getSettingData().useAllCardVariants) { if (Config.instance().getSettingData().useAllCardVariants) {
if (!edition.isEmpty()) { if (!edition.isEmpty()) {
R = new Reward(CardUtil.getCardByNameAndEdition(P.getCardName(), edition)); currentReward = new Reward(CardUtil.getCardByNameAndEdition(P.getCardName(), edition));
} else { } else {
R = new Reward(CardUtil.getCardByName(P.getCardName())); // grab any random variant if no set preference is specified currentReward = new Reward(CardUtil.getCardByName(P.getCardName())); // grab any random variant if no set preference is specified
} }
} else { } else {
R = new Reward(P); currentReward = new Reward(P);
} }
Current.player().addReward(R); if (rewardActor != null) rewardActor.remove();
if (usingShards) { rewardActor = new RewardActor(currentReward, true, null, true);
rewardActor.flip(); //Make it flip so it draws visual attention, why not.
rewardActor.setBounds(rewardDummy.getX(), rewardDummy.getY(), rewardDummy.getWidth(), rewardDummy.getHeight());
stage.addActor(rewardActor);
acceptReward.setVisible(true);
declineReward.setVisible(true);
exitSmith.setDisabled(true);
disablePullButtons();
}
private void acceptSmithing() {
if (paidInShards) {
Current.player().takeShards(currentShardPrice); Current.player().takeShards(currentShardPrice);
} else { } else {
Current.player().takeGold(currentPrice); Current.player().takeGold(currentPrice);
} }
if (Current.player().getGold() < currentPrice) pullUsingGold.setDisabled(true);
if (Current.player().getShards() < currentShardPrice) pullUsingShards.setDisabled(true); Current.player().addReward(currentReward);
clearReward();
updatePullButtons();
}
private void declineSmithing() {
// Decline the smith reward for 10% of original price
float priceAdjustment = .10f;
if (paidInShards) {
Current.player().takeShards((int)(currentShardPrice * priceAdjustment));
} else {
Current.player().takeGold((int)(currentPrice * priceAdjustment));
}
clearReward();
updatePullButtons();
}
private void clearReward() {
if (rewardActor != null) rewardActor.remove(); if (rewardActor != null) rewardActor.remove();
rewardActor = new RewardActor(R, true, null, true); currentReward = null;
rewardActor.flip(); //Make it flip so it draws visual attention, why not. }
rewardActor.setBounds(rewardDummy.getX(), rewardDummy.getY(), rewardDummy.getWidth(), rewardDummy.getHeight());
stage.addActor(rewardActor);
private void updatePullButtons() {
pullUsingGold.setDisabled(Current.player().getGold() < currentPrice);
pullUsingShards.setDisabled(Current.player().getShards() < currentShardPrice);
acceptReward.setVisible(false);
declineReward.setVisible(false);
exitSmith.setDisabled(false);
}
private void disablePullButtons() {
pullUsingGold.setDisabled(true);
pullUsingShards.setDisabled(true);
} }
} }

View File

@@ -277,7 +277,7 @@ public class CardImageRenderer {
if (!noText && state != null) { if (!noText && state != null) {
//draw mana cost for card //draw mana cost for card
ManaCost mainManaCost = state.getManaCost(); ManaCost mainManaCost = state.getManaCost();
if (card.isSplitCard() && card.getAlternateState() != null) { if (card.isSplitCard() && card.getAlternateState() != null && !card.isFaceDown() && card.getZone() != ZoneType.Stack && card.getZone() != ZoneType.Battlefield) {
//handle rendering both parts of split card //handle rendering both parts of split card
mainManaCost = card.getLeftSplitState().getManaCost(); mainManaCost = card.getLeftSplitState().getManaCost();
ManaCost otherManaCost = card.getRightSplitState().getManaCost(); ManaCost otherManaCost = card.getRightSplitState().getManaCost();
@@ -1112,7 +1112,7 @@ public class CardImageRenderer {
float manaCostWidth = 0; float manaCostWidth = 0;
if (canShow) { if (canShow) {
ManaCost mainManaCost = state.getManaCost(); ManaCost mainManaCost = state.getManaCost();
if (card.isSplitCard() && card.hasAlternateState() && !card.isFaceDown() && card.getZone() != ZoneType.Stack) { //only display current state's mana cost when on stack if (card.isSplitCard() && card.hasAlternateState() && !card.isFaceDown() && card.getZone() != ZoneType.Stack && card.getZone() != ZoneType.Battlefield) { //only display current state's mana cost when on stack
//handle rendering both parts of split card //handle rendering both parts of split card
mainManaCost = card.getLeftSplitState().getManaCost(); mainManaCost = card.getLeftSplitState().getManaCost();
ManaCost otherManaCost = card.getAlternateState().getManaCost(); ManaCost otherManaCost = card.getAlternateState().getManaCost();

View File

@@ -37,6 +37,7 @@ import forge.assets.FRotatedImage;
import forge.assets.FSkin; import forge.assets.FSkin;
import forge.assets.FSkinColor; import forge.assets.FSkinColor;
import forge.assets.FSkinFont; import forge.assets.FSkinFont;
import forge.assets.FSkinImageInterface;
import forge.assets.FTextureRegionImage; import forge.assets.FTextureRegionImage;
import forge.assets.ImageCache; import forge.assets.ImageCache;
import forge.card.CardZoom.ActivateHandler; import forge.card.CardZoom.ActivateHandler;
@@ -93,13 +94,22 @@ public class CardRenderer {
} }
} }
private static float calcSymbolSize(FSkinProp skinProp) {
if (skinProp == null)
return 0f;
FSkinImageInterface image = FSkin.getImages().get(skinProp);
if (image == null)
return 0f;
return image.getNearestHQWidth(2 * (NAME_FONT.getCapHeight() - MANA_COST_PADDING));
}
private static final FSkinFont NAME_FONT = FSkinFont.get(16); private static final FSkinFont NAME_FONT = FSkinFont.get(16);
public static final float NAME_BOX_TINT = 0.2f; public static final float NAME_BOX_TINT = 0.2f;
public static final float TEXT_BOX_TINT = 0.1f; public static final float TEXT_BOX_TINT = 0.1f;
public static final float PT_BOX_TINT = 0.2f; public static final float PT_BOX_TINT = 0.2f;
private static final float MANA_COST_PADDING = Utils.scale(3); private static final float MANA_COST_PADDING = Utils.scale(3);
public static final float SET_BOX_MARGIN = Utils.scale(1); public static final float SET_BOX_MARGIN = Utils.scale(1);
public static final float MANA_SYMBOL_SIZE = FSkin.getImages().get(FSkinProp.IMG_MANA_1).getNearestHQWidth(2 * (NAME_FONT.getCapHeight() - MANA_COST_PADDING)); public static final float MANA_SYMBOL_SIZE = calcSymbolSize(FSkinProp.IMG_MANA_1);
private static final float NAME_COST_THRESHOLD = Utils.scale(200); private static final float NAME_COST_THRESHOLD = Utils.scale(200);
private static final float BORDER_THICKNESS = Utils.scale(1); private static final float BORDER_THICKNESS = Utils.scale(1);
public static final float PADDING_MULTIPLIER = 0.021f; public static final float PADDING_MULTIPLIER = 0.021f;
@@ -842,19 +852,17 @@ public class CardRenderer {
} }
if (showCardManaCostOverlay(card)) { if (showCardManaCostOverlay(card)) {
float manaSymbolSize = w / 4.5f; float manaSymbolSize = w / 4.5f;
if (card.isSplitCard() && card.hasAlternateState()) { if (card.isSplitCard() && card.hasAlternateState() && !card.isFaceDown() && card.getZone() != ZoneType.Stack && card.getZone() != ZoneType.Battlefield) {
if (!card.isFaceDown()) { // no need to draw mana symbols on face down split cards (e.g. manifested) if (isChoiceList) {
if (isChoiceList) { if (card.getRightSplitState().getName().equals(details.getName()))
if (card.getRightSplitState().getName().equals(details.getName())) drawManaCost(g, card.getRightSplitState().getManaCost(), x - padding, y, w + 2 * padding, h, manaSymbolSize);
drawManaCost(g, card.getRightSplitState().getManaCost(), x - padding, y, w + 2 * padding, h, manaSymbolSize); else
else drawManaCost(g, card.getLeftSplitState().getManaCost(), x - padding, y, w + 2 * padding, h, manaSymbolSize);
drawManaCost(g, card.getLeftSplitState().getManaCost(), x - padding, y, w + 2 * padding, h, manaSymbolSize); } else {
} else { ManaCost leftManaCost = card.getLeftSplitState().getManaCost();
ManaCost leftManaCost = card.getLeftSplitState().getManaCost(); ManaCost rightManaCost = card.getRightSplitState().getManaCost();
ManaCost rightManaCost = card.getRightSplitState().getManaCost(); drawManaCost(g, leftManaCost, x - padding, y-(manaSymbolSize/1.5f), w + 2 * padding, h, manaSymbolSize);
drawManaCost(g, leftManaCost, x - padding, y-(manaSymbolSize/1.5f), w + 2 * padding, h, manaSymbolSize); drawManaCost(g, rightManaCost, x - padding, y+(manaSymbolSize/1.5f), w + 2 * padding, h, manaSymbolSize);
drawManaCost(g, rightManaCost, x - padding, y+(manaSymbolSize/1.5f), w + 2 * padding, h, manaSymbolSize);
}
} }
} else { } else {
drawManaCost(g, showAltState ? card.getAlternateState().getManaCost() : card.getCurrentState().getManaCost(), x - padding, y, w + 2 * padding, h, manaSymbolSize); drawManaCost(g, showAltState ? card.getAlternateState().getManaCost() : card.getCurrentState().getManaCost(), x - padding, y, w + 2 * padding, h, manaSymbolSize);

View File

@@ -1,7 +1,7 @@
Name:Farmer's Tools Name:Farmer's Tools
ManaCost:no cost ManaCost:no cost
Types:Artifact Types:Artifact
A:AB$ RepeatEach | Cost$ PayShards<2> | ActivationZone$ Command | RepeatSubAbility$ DBChangeZone | RepeatPlayers$ Player | SubAbility$ Eject | StartingWithActivator$ True | SpellDescription$ Starting with you, each player may put a land card from their hand onto the battlefield. Exile Farmer's Tools. A:AB$ RepeatEach | Cost$ PayShards<2> | ActivationZone$ Command | RepeatSubAbility$ DBChangeZone | RepeatPlayers$ Player | SubAbility$ Eject | StartingWith$ You | SpellDescription$ Starting with you, each player may put a land card from their hand onto the battlefield. Exile Farmer's Tools.
SVar:DBChangeZone:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Land.RememberedPlayerCtrl | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered | ChangeNum$ 1 | Hidden$ True SVar:DBChangeZone:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Land.RememberedPlayerCtrl | DefinedPlayer$ Player.IsRemembered | Chooser$ Player.IsRemembered | ChangeNum$ 1 | Hidden$ True
SVar:Eject:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile SVar:Eject:DB$ ChangeZone | Defined$ Self | Origin$ Command | Destination$ Exile
Oracle:{M}{M}: Starting with you, each player may put a land card from their hand onto the battlefield. Exile Farmer's Tools. Oracle:{M}{M}: Starting with you, each player may put a land card from their hand onto the battlefield. Exile Farmer's Tools.

View File

@@ -67,7 +67,7 @@
&quot;options&quot;: [ &quot;options&quot;: [
{ {
&quot;name&quot;: &quot;Am I allowed to enter the aerie ?&quot;, &quot;name&quot;: &quot;Am I allowed to enter the aerie ?&quot;,
&quot;text&quot;: &quot;I'm afraid to say to you that you are not allowed to do that. Our guild is very protective of it's breeding practices, which have been developed over a span of more than thousands of years. Because of that, we don't want our competitors peeking into our business. If anyone without permission enters the aerie, that person will be repremanded by the various guards and even the birds, who have been trained to attack unwanted intruders.'&quot;, &quot;text&quot;: &quot;I'm afraid to say to you that you are not allowed to do that. Our guild is very protective of it's breeding practices, which have been developed over a span of more than thousands of years. Because of that, we don't want our competitors peeking into our business. If anyone without permission enters the aerie, that person will be reprimanded by the various guards and even the birds, who have been trained to attack unwanted intruders.'&quot;,
&quot;options&quot;: [ &quot;options&quot;: [
{ {
&quot;name&quot;: &quot;Thanks for the information, goodbye&quot;, &quot;name&quot;: &quot;Thanks for the information, goodbye&quot;,

View File

@@ -169,12 +169,34 @@
"y": 5, "y": 5,
"width": 90, "width": 90,
"height": 20 "height": 20
},
{
"type": "TextButton",
"selectable": true,
"name": "accept",
"text": "tr(lblTake)",
"binding": "Use",
"x": 343,
"y": 173,
"width": 60,
"height": 20
},
{
"type": "TextButton",
"selectable": true,
"name": "decline",
"text": "tr(lblRefund)",
"binding": "Back",
"x": 405,
"y": 173,
"width": 60,
"height": 20
}, },
{ {
"type": "Label", "type": "Label",
"name": "poolSize", "name": "poolSize",
"x": 360, "x": 360,
"y": 180, "y": 192,
"width": 90, "width": 90,
"height": 20 "height": 20
}, },

View File

@@ -174,12 +174,34 @@
"y": 75, "y": 75,
"width": 90, "width": 90,
"height": 20 "height": 20
},
{
"type": "TextButton",
"selectable": true,
"name": "accept",
"text": "tr(lblTake)",
"binding": "Use",
"x": 2,
"y": 142,
"width": 60,
"height": 20
},
{
"type": "TextButton",
"selectable": true,
"name": "decline",
"text": "tr(lblRefund)",
"binding": "Back",
"x": 70,
"y": 142,
"width": 60,
"height": 20
}, },
{ {
"type": "Label", "type": "Label",
"name": "poolSize", "name": "poolSize",
"x": 16, "x": 16,
"y": 150, "y": 163,
"width": 97, "width": 97,
"height": 20 "height": 20
}, },

View File

@@ -4,7 +4,7 @@ Types:Instant
K:Devoid K:Devoid
A:SP$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Permanent.nonLand | RememberChanged$ True | TgtPromt$ Select target nonland permanent | SubAbility$ DBEffect | SpellDescription$ Exile target nonland permanent. A:SP$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Permanent.nonLand | RememberChanged$ True | TgtPromt$ Select target nonland permanent | SubAbility$ DBEffect | SpellDescription$ Exile target nonland permanent.
SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ MayPlay,ManaConvert | SubAbility$ DBCleanup | Duration$ Permanent | ForgetOnMoved$ Exile | SpellDescription$ You may cast that card for as long as it remains exiled, and you may spend colorless mana as though it were mana of any color to cast that spell. SVar:DBEffect:DB$ Effect | RememberObjects$ Remembered | StaticAbilities$ MayPlay,ManaConvert | SubAbility$ DBCleanup | Duration$ Permanent | ForgetOnMoved$ Exile | SpellDescription$ You may cast that card for as long as it remains exiled, and you may spend colorless mana as though it were mana of any color to cast that spell.
SVar:MayPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonLand | AffectedZone$ Exile | Description$ You may cast that card for as long as it remains exiled SVar:MayPlay:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered+nonLand | AffectedZone$ Exile | Description$ You may cast that card for as long as it remains exiled.
SVar:ManaConvert:Mode$ ManaConvert | ValidPlayer$ You | ValidCard$ Card.IsRemembered | ValidSA$ Spell.MayPlaySource | ManaConversion$ C->AnyColor | AffectedZone$ Exile | Description$ You may spend colorless mana as though it were mana of any color to cast that spell. SVar:ManaConvert:Mode$ ManaConvert | ValidPlayer$ You | ValidCard$ Card.IsRemembered | ValidSA$ Spell.MayPlaySource | ManaConversion$ C->AnyColor | AffectedZone$ Exile | Description$ You may spend colorless mana as though it were mana of any color to cast that spell.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
Oracle:Devoid\nExile target nonland permanent. You may cast that card for as long as it remains exiled, and you may spend colorless mana as though it were mana of any color to cast that spell. Oracle:Devoid\nExile target nonland permanent. You may cast that card for as long as it remains exiled, and you may spend colorless mana as though it were mana of any color to cast that spell.

View File

@@ -6,10 +6,10 @@ Draft:Reveal CARDNAME as you draft it.
Draft:Reveal the next card you draft and note its name. Draft:Reveal the next card you draft and note its name.
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearchHand | TriggerDescription$ When CARDNAME enters, you may search your hand and/or library for a card with a name noted as you drafted cards named Aether Searcher. You may cast it without paying its mana cost. If you searched your library this way, shuffle. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearchHand | TriggerDescription$ When CARDNAME enters, you may search your hand and/or library for a card with a name noted as you drafted cards named Aether Searcher. You may cast it without paying its mana cost. If you searched your library this way, shuffle.
SVar:TrigSearchHand:DB$ ChangeZone | Origin$ Hand | Destination$ Hand | ChangeType$ Card.NotedNameAetherSearcher | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ TrigBranch SVar:TrigSearchHand:DB$ ChangeZone | Origin$ Hand | Destination$ Hand | ChangeType$ Card.NotedNameAetherSearcher | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ TrigBranch
# Branch to casting the found spell # Branch to cast that card from hand
SVar:TrigBranch:DB$ Branch | BranchConditionSVar$ X | BranchConditionSVarCompare$ EQ1 | TrueSubAbility$ CastFromHand | FalseSubAbility$ SearchLibrary SVar:TrigBranch:DB$ Branch | BranchConditionSVar$ X | BranchConditionSVarCompare$ EQ1 | TrueSubAbility$ CastFromHand | FalseSubAbility$ SearchLibrary
SVar:CastFromHand:DB$ Play | ValidZone$ Hand | Valid$ Card.IsRemembered | Controller$ You | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup SVar:CastFromHand:DB$ Play | ValidZone$ Hand | Valid$ Card.IsRemembered | Controller$ You | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup
# Or search the library # Branch to search the library and cast that card
SVar:SearchLibrary:DB$ ChangeZone | Origin$ Library | Destination$ Library | ChangeType$ Card.NotedNameAetherSearcher | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ CastFromLibrary SVar:SearchLibrary:DB$ ChangeZone | Origin$ Library | Destination$ Library | ChangeType$ Card.NotedNameAetherSearcher | ChangeNum$ 1 | RememberChanged$ True | SubAbility$ CastFromLibrary
SVar:CastFromLibrary:DB$ Play | ValidZone$ Library | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | Valid$ Card.IsRemembered | Controller$ You | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup SVar:CastFromLibrary:DB$ Play | ValidZone$ Library | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | Valid$ Card.IsRemembered | Controller$ You | WithoutManaCost$ True | Optional$ True | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True

View File

@@ -14,7 +14,7 @@ ManaCost:no cost
Colors:red Colors:red
Types:Creature Werewolf Types:Creature Werewolf
PT:5/4 PT:5/4
T:Mode$ Transformed | ValidCard$ Card.Self | Execute$ TrigDestroy | OptionalDecider$ You | TriggerDescription$ Whenever this creature transforms into CARDNAME, you may destroy target artifact. If that artifact is put into a graveyard this way, CARDNAME deals 3 damage to that artifact's controller T:Mode$ Transformed | ValidCard$ Card.Self | Execute$ TrigDestroy | OptionalDecider$ You | TriggerDescription$ Whenever this creature transforms into CARDNAME, you may destroy target artifact. If that artifact is put into a graveyard this way, CARDNAME deals 3 damage to that artifact's controller.
SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact | TgtPrompt$ Select target artifact. | RememberTargets$ True | ForgetOtherTargets$ True | SubAbility$ DBDamage SVar:TrigDestroy:DB$ Destroy | ValidTgts$ Artifact | TgtPrompt$ Select target artifact. | RememberTargets$ True | ForgetOtherTargets$ True | SubAbility$ DBDamage
SVar:DBDamage:DB$ DealDamage | Defined$ TargetedController | NumDmg$ 3 | SubAbility$ DBCleanup | ConditionCheckSVar$ IsDestroyed | ConditionSVarCompare$ GE1 SVar:DBDamage:DB$ DealDamage | Defined$ TargetedController | NumDmg$ 3 | SubAbility$ DBCleanup | ConditionCheckSVar$ IsDestroyed | ConditionSVarCompare$ GE1
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True

View File

@@ -5,6 +5,6 @@ PT:4/3
K:Flying K:Flying
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearch | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters, you may search your graveyard, hand, and/or library for a card named Magnifying Glass and/or a card named Thinking Cap and put them onto the battlefield. If you search your library this way, shuffle. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigSearch | OptionalDecider$ You | TriggerDescription$ When CARDNAME enters, you may search your graveyard, hand, and/or library for a card named Magnifying Glass and/or a card named Thinking Cap and put them onto the battlefield. If you search your library this way, shuffle.
SVar:TrigSearch:DB$ ChangeZone | OriginAlternative$ Graveyard,Hand | Hidden$ True | Origin$ Library | Destination$ Battlefield | DifferentNames$ True | ChangeType$ Card.namedMagnifying Glass,Card.namedThinking Cap | ChangeNum$ 2 | ShuffleNonMandatory$ True SVar:TrigSearch:DB$ ChangeZone | OriginAlternative$ Graveyard,Hand | Hidden$ True | Origin$ Library | Destination$ Battlefield | DifferentNames$ True | ChangeType$ Card.namedMagnifying Glass,Card.namedThinking Cap | ChangeNum$ 2 | ShuffleNonMandatory$ True
DeckHas:Ability$Artifact|Equipment DeckHas:Ability$Graveyard
DeckHints:Name$Thinking Cap|Magnifying Glass DeckHints:Name$Thinking Cap|Magnifying Glass
Oracle:Flying\nWhen Agency Outfitter enters, you may search your graveyard, hand, and/or library for a card named Magnifying Glass and/or a card named Thinking Cap and put them onto the battlefield. If you search your library this way, shuffle. Oracle:Flying\nWhen Agency Outfitter enters, you may search your graveyard, hand, and/or library for a card named Magnifying Glass and/or a card named Thinking Cap and put them onto the battlefield. If you search your library this way, shuffle.

View File

@@ -1,7 +1,7 @@
Name:Aggressive Instinct Name:Aggressive Instinct
ManaCost:1 G ManaCost:1 G
Types:Sorcery Types:Sorcery
A:SP$ Pump | ValidTgts$ Creature.YouCtrl | AILogic$ PowerDmg | TgtPrompt$ Select target creature you control | SubAbility$ SoulsDamage | StackDescription$ None | SpellDescription$ Target creature you control deals damage equal to its power to target creature you don't control A:SP$ Pump | ValidTgts$ Creature.YouCtrl | AILogic$ PowerDmg | TgtPrompt$ Select target creature you control | SubAbility$ SoulsDamage | StackDescription$ None | SpellDescription$ Target creature you control deals damage equal to its power to target creature you don't control.
SVar:SoulsDamage:DB$ DealDamage | ValidTgts$ Creature.YouDontCtrl | AILogic$ PowerDmg | TgtPrompt$ Select target creature you don't control | NumDmg$ X | DamageSource$ ParentTarget SVar:SoulsDamage:DB$ DealDamage | ValidTgts$ Creature.YouDontCtrl | AILogic$ PowerDmg | TgtPrompt$ Select target creature you don't control | NumDmg$ X | DamageSource$ ParentTarget
SVar:X:ParentTargeted$CardPower SVar:X:ParentTargeted$CardPower
Oracle:Target creature you control deals damage equal to its power to target creature you don't control. Oracle:Target creature you control deals damage equal to its power to target creature you don't control.

View File

@@ -2,6 +2,6 @@ Name:Aid the Fallen
ManaCost:1 B ManaCost:1 B
Types:Sorcery Types:Sorcery
A:SP$ Charm | MinCharmNum$ 1 | CharmNum$ 2 | Choices$ DBCreature,DBPlaneswalker A:SP$ Charm | MinCharmNum$ 1 | CharmNum$ 2 | Choices$ DBCreature,DBPlaneswalker
SVar:DBCreature:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature in your graveyard | SpellDescription$ Return target creature card from your graveyard to your hand SVar:DBCreature:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Creature.YouCtrl | TgtPrompt$ Select target creature in your graveyard | SpellDescription$ Return target creature card from your graveyard to your hand.
SVar:DBPlaneswalker:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Planeswalker.YouCtrl | TgtPrompt$ Select target planeswalker in your graveyard | SpellDescription$ Return target planeswalker card from your graveyard to your hand SVar:DBPlaneswalker:DB$ ChangeZone | Origin$ Graveyard | Destination$ Hand | ValidTgts$ Planeswalker.YouCtrl | TgtPrompt$ Select target planeswalker in your graveyard | SpellDescription$ Return target planeswalker card from your graveyard to your hand.
Oracle:Choose one or both —\n• Return target creature card from your graveyard to your hand.\n• Return target planeswalker card from your graveyard to your hand. Oracle:Choose one or both —\n• Return target creature card from your graveyard to your hand.\n• Return target planeswalker card from your graveyard to your hand.

View File

@@ -17,7 +17,7 @@ ALTERNATE
Name:Wild Goose Chase Name:Wild Goose Chase
ManaCost:U G ManaCost:U G
Types:Instant Adventure Types:Instant Adventure
A:SP$ Draw | Defined$ You | NumCards$ 2 | SubAbility$ TrigDiscard | SpellDescription$ Draw two cards, then discard two cards A:SP$ Draw | Defined$ You | NumCards$ 2 | SubAbility$ TrigDiscard | SpellDescription$ Draw two cards, then discard two cards.
SVar:TrigDiscard:DB$ Discard | Defined$ You | NumCards$ 2 | Mode$ TgtChoose | SubAbility$ DBToken SVar:TrigDiscard:DB$ Discard | Defined$ You | NumCards$ 2 | Mode$ TgtChoose | SubAbility$ DBToken
SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_food_sac | TokenOwner$ You | SpellDescription$ Create a Food token. SVar:DBToken:DB$ Token | TokenAmount$ 1 | TokenScript$ c_a_food_sac | TokenOwner$ You | SpellDescription$ Create a Food token.
Oracle:Draw two cards, then discard two cards. Create a Food token. Oracle:Draw two cards, then discard two cards. Create a Food token.

View File

@@ -1,7 +1,7 @@
Name:All Will Be One Name:All Will Be One
ManaCost:3 R R ManaCost:3 R R
Types:Enchantment Types:Enchantment
T:Mode$ CounterPlayerAddedAll | ValidObject$ Permanent.inRealZoneBattlefield,Player | TriggerZones$ Battlefield | ValidSource$ You | Execute$ TrigDamage | TriggerDescription$ Whenever you put one or more counters on a permanent or player, CARDNAME deals that much damage to target opponent, creature an opponent controls, or planeswalker an opponent controls T:Mode$ CounterPlayerAddedAll | ValidObject$ Permanent.inRealZoneBattlefield,Player | TriggerZones$ Battlefield | ValidSource$ You | Execute$ TrigDamage | TriggerDescription$ Whenever you put one or more counters on a permanent or player, CARDNAME deals that much damage to target opponent, creature an opponent controls, or planeswalker an opponent controls.
SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Creature.OppCtrl,Planeswalker.OppCtrl,Opponent | TgtPrompt$ Select target opponent, creature an opponent controls, or planeswalker an opponent controls. | NumDmg$ X SVar:TrigDamage:DB$ DealDamage | ValidTgts$ Creature.OppCtrl,Planeswalker.OppCtrl,Opponent | TgtPrompt$ Select target opponent, creature an opponent controls, or planeswalker an opponent controls. | NumDmg$ X
SVar:X:TriggerCount$Amount SVar:X:TriggerCount$Amount
DeckNeeds:Ability$Counters DeckNeeds:Ability$Counters

View File

@@ -1,7 +1,7 @@
Name:Alliance of Arms Name:Alliance of Arms
ManaCost:W ManaCost:W
Types:Sorcery Types:Sorcery
A:SP$ RepeatEach | RepeatPlayers$ Player | StartingWithActivator$ True | RepeatSubAbility$ DBPay | SubAbility$ DBToken | StackDescription$ SpellDescription | SpellDescription$ Join forces — Starting with you, each player may pay any amount of mana. Each player creates X 1/1 white Soldier creature tokens, where X is the total amount of mana paid this way. A:SP$ RepeatEach | RepeatPlayers$ Player | StartingWith$ You | RepeatSubAbility$ DBPay | SubAbility$ DBToken | StackDescription$ SpellDescription | SpellDescription$ Join forces — Starting with you, each player may pay any amount of mana. Each player creates X 1/1 white Soldier creature tokens, where X is the total amount of mana paid this way.
SVar:DBPay:DB$ ChooseNumber | Defined$ Player.IsRemembered | ChooseAnyNumber$ True | ListTitle$ amount of mana to pay | SubAbility$ DBStore SVar:DBPay:DB$ ChooseNumber | Defined$ Player.IsRemembered | ChooseAnyNumber$ True | ListTitle$ amount of mana to pay | SubAbility$ DBStore
SVar:DBStore:DB$ StoreSVar | SVar$ JoinForcesAmount | Type$ CountSVar | Expression$ JoinForcesAmount/Plus.Y | UnlessCost$ Y | UnlessPayer$ Player.IsRemembered | UnlessSwitched$ True | UnlessAI$ OnlyOwn SVar:DBStore:DB$ StoreSVar | SVar$ JoinForcesAmount | Type$ CountSVar | Expression$ JoinForcesAmount/Plus.Y | UnlessCost$ Y | UnlessPayer$ Player.IsRemembered | UnlessSwitched$ True | UnlessAI$ OnlyOwn
SVar:DBToken:DB$ Token | TokenAmount$ JoinForcesAmount | TokenScript$ w_1_1_soldier | TokenOwner$ Player | StackDescription$ None SVar:DBToken:DB$ Token | TokenAmount$ JoinForcesAmount | TokenScript$ w_1_1_soldier | TokenOwner$ Player | StackDescription$ None

View File

@@ -9,7 +9,7 @@ SVar:Z:SVar$X/Plus.Y
T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigChooseCardType | TriggerDescription$ At the beginning of your end step, choose a card type, then reveal the top two cards of your library. Put all cards of the chosen type revealed this way into your hand and the rest on the bottom of your library in any order. T:Mode$ Phase | Phase$ End of Turn | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigChooseCardType | TriggerDescription$ At the beginning of your end step, choose a card type, then reveal the top two cards of your library. Put all cards of the chosen type revealed this way into your hand and the rest on the bottom of your library in any order.
SVar:TrigChooseCardType:DB$ ChooseType | Defined$ You | Type$ Card | SubAbility$ DBDig SVar:TrigChooseCardType:DB$ ChooseType | Defined$ You | Type$ Card | SubAbility$ DBDig
SVar:DBDig:DB$ Dig | DigNum$ 2 | Reveal$ True | ChangeNum$ All | ChangeValid$ Card.ChosenType | DestinationZone2$ Library | LibraryPosition$ -1 SVar:DBDig:DB$ Dig | DigNum$ 2 | Reveal$ True | ChangeNum$ All | ChangeValid$ Card.ChosenType | DestinationZone2$ Library | LibraryPosition$ -1
DeckHints:Ability$Foretell DeckHints:Keyword$Foretell
AI:RemoveDeck:All AI:RemoveDeck:All
AlternateMode:Modal AlternateMode:Modal
Oracle:Alrund gets +1/+1 for each card in your hand and each foretold card you own in exile.\nAt the beginning of your end step, choose a card type, then reveal the top two cards of your library. Put all cards of the chosen type revealed this way into your hand and the rest on the bottom of your library in any order. Oracle:Alrund gets +1/+1 for each card in your hand and each foretold card you own in exile.\nAt the beginning of your end step, choose a card type, then reveal the top two cards of your library. Put all cards of the chosen type revealed this way into your hand and the rest on the bottom of your library in any order.

View File

@@ -1,9 +1,9 @@
Name:Altar of Shadows Name:Altar of Shadows
ManaCost:7 ManaCost:7
Types:Artifact Types:Artifact
T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigGetMana | TriggerDescription$ At the beginning of your precombat main phase, add {B} for each charge counter on CARDNAME. T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigGetMana | TriggerDescription$ At the beginning of your first main phase, add {B} for each charge counter on CARDNAME.
SVar:TrigGetMana:DB$ Mana | Produced$ B | Amount$ X | SpellDescription$ Add {B} for each charge counter on CARDNAME. SVar:TrigGetMana:DB$ Mana | Produced$ B | Amount$ X | SpellDescription$ Add {B} for each charge counter on CARDNAME.
A:AB$ Destroy | Cost$ 7 T | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBPutCounter | SpellDescription$ Destroy target creature. Then put a charge counter on CARDNAME. A:AB$ Destroy | Cost$ 7 T | ValidTgts$ Creature | TgtPrompt$ Select target creature | SubAbility$ DBPutCounter | SpellDescription$ Destroy target creature. Then put a charge counter on CARDNAME.
SVar:DBPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ CHARGE | CounterNum$ 1 SVar:DBPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ CHARGE | CounterNum$ 1
SVar:X:Count$CardCounters.CHARGE SVar:X:Count$CardCounters.CHARGE
Oracle:At the beginning of your precombat main phase, add {B} for each charge counter on Altar of Shadows.\n{7}, {T}: Destroy target creature. Then put a charge counter on Altar of Shadows. Oracle:At the beginning of your first main phase, add {B} for each charge counter on Altar of Shadows.\n{7}, {T}: Destroy target creature. Then put a charge counter on Altar of Shadows.

View File

@@ -5,4 +5,4 @@ PT:5/4
Draft:Draft CARDNAME face up. Draft:Draft CARDNAME face up.
Draft:As long as CARDNAME is face up during the draft, you can't look at booster packs and must draft cards at random. After you draft three cards this way, turn CARDNAME face down. (You may look at cards as you draft them.) Draft:As long as CARDNAME is face up during the draft, you can't look at booster packs and must draft cards at random. After you draft three cards this way, turn CARDNAME face down. (You may look at cards as you draft them.)
K:Flying K:Flying
Oracle:Draft Archdemon of Paliano face up.\n\nAs long as Archdemon of Paliano is face up during the draft, you can't look at booster packs and must draft cards at random. After you draft three cards this way, turn Archdemon of Paliano face down. (You may look at cards as you draft them.)\nFlying Oracle:Draft Archdemon of Paliano face up.\nAs long as Archdemon of Paliano is face up during the draft, you can't look at booster packs and must draft cards at random. After you draft three cards this way, turn Archdemon of Paliano face down. (You may look at cards as you draft them.)\nFlying

View File

@@ -1,7 +1,7 @@
Name:Arcum's Whistle Name:Arcum's Whistle
ManaCost:3 ManaCost:3
Types:Artifact Types:Artifact
A:AB$ Animate | Cost$ 3 T | ActivationPhases$ Upkeep->BeginCombat | ActivationFirstCombat$ True | ValidTgts$ Creature.nonWall+ActivePlayerCtrl+notFirstTurnControlled | TgtPrompt$ Select target non-Wall creature the active player has controlled continuously since the beginning of the turn | IsCurse$ True | staticAbilities$ MustAttack | UnlessCost$ X | UnlessPayer$ TargetedController | UnlessResolveSubs$ WhenNotPaid | SubAbility$ DestroyPacifist | SpellDescription$ Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. That player may pay {X}, where X is that creature's mana value. If they don't pay, the creature attacks this turn if able, and at the beginning of the next end step, destroy it if it didn't attack this turn. Activate only before attackers are declared. A:AB$ Animate | Cost$ 3 T | ActivationPhases$ Upkeep->BeginCombat | ActivationFirstCombat$ True | ValidTgts$ Creature.nonWall+ActivePlayerCtrl+!firstTurnControlled | TgtPrompt$ Select target non-Wall creature the active player has controlled continuously since the beginning of the turn | IsCurse$ True | staticAbilities$ MustAttack | UnlessCost$ X | UnlessPayer$ TargetedController | UnlessResolveSubs$ WhenNotPaid | SubAbility$ DestroyPacifist | SpellDescription$ Choose target non-Wall creature the active player has controlled continuously since the beginning of the turn. That player may pay {X}, where X is that creature's mana value. If they don't pay, the creature attacks this turn if able, and at the beginning of the next end step, destroy it if it didn't attack this turn. Activate only before attackers are declared.
SVar:MustAttack:Mode$ MustAttack | ValidCreature$ Card.Self | Description$ This creature attacks this turn if able. SVar:MustAttack:Mode$ MustAttack | ValidCreature$ Card.Self | Description$ This creature attacks this turn if able.
SVar:DestroyPacifist:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigDestroy | RememberObjects$ ParentTarget | TriggerDescription$ At the beginning of the next end step, destroy that creature if it didn't attack this turn. SVar:DestroyPacifist:DB$ DelayedTrigger | Mode$ Phase | Phase$ End of Turn | Execute$ TrigDestroy | RememberObjects$ ParentTarget | TriggerDescription$ At the beginning of the next end step, destroy that creature if it didn't attack this turn.
SVar:TrigDestroy:DB$ Destroy | Defined$ DelayTriggerRemembered | ConditionDefined$ DelayTriggerRemembered | ConditionPresent$ Creature.notAttackedThisTurn | ConditionCompare$ GE1 SVar:TrigDestroy:DB$ Destroy | Defined$ DelayTriggerRemembered | ConditionDefined$ DelayTriggerRemembered | ConditionPresent$ Creature.notAttackedThisTurn | ConditionCompare$ GE1

View File

@@ -3,7 +3,7 @@ ManaCost:X G
Types:Sorcery Types:Sorcery
A:SP$ PutCounter | TargetMin$ 0 | TargetMax$ X | ValidTgts$ Land.YouCtrl | TgtPrompt$ Select up to X target lands you control | CounterType$ P1P1 | CounterNum$ 2 | SubAbility$ DBAnimate | SpellDescription$ Put two +1/+1 counters on each of up to X target lands you control. They each become 0/0 Elemental creatures with reach, haste, and "When this creature leaves the battlefield, conjure a card named Forest onto the battlefield tapped." They're still lands. A:SP$ PutCounter | TargetMin$ 0 | TargetMax$ X | ValidTgts$ Land.YouCtrl | TgtPrompt$ Select up to X target lands you control | CounterType$ P1P1 | CounterNum$ 2 | SubAbility$ DBAnimate | SpellDescription$ Put two +1/+1 counters on each of up to X target lands you control. They each become 0/0 Elemental creatures with reach, haste, and "When this creature leaves the battlefield, conjure a card named Forest onto the battlefield tapped." They're still lands.
SVar:DBAnimate:DB$ Animate | Defined$ ParentTarget | Power$ 0 | Toughness$ 0 | Types$ Creature,Elemental | Keywords$ Haste & Reach | Duration$ Permanent | Triggers$ DiesTrig SVar:DBAnimate:DB$ Animate | Defined$ ParentTarget | Power$ 0 | Toughness$ 0 | Types$ Creature,Elemental | Keywords$ Haste & Reach | Duration$ Permanent | Triggers$ DiesTrig
SVar:DiesTrig:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigConjure | TriggerDescription$ When this creature leaves the battlefield, conjure a card named Forest onto the battlefield tapped SVar:DiesTrig:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Any | ValidCard$ Card.Self | Execute$ TrigConjure | TriggerDescription$ When this creature leaves the battlefield, conjure a card named Forest onto the battlefield tapped.
SVar:TrigConjure:DB$ MakeCard | Conjure$ True | Name$ Forest | Zone$ Battlefield | Tapped$ True SVar:TrigConjure:DB$ MakeCard | Conjure$ True | Name$ Forest | Zone$ Battlefield | Tapped$ True
SVar:X:Count$xPaid SVar:X:Count$xPaid
DeckHas:Type$Elemental & Ability$Counters DeckHas:Type$Elemental & Ability$Counters

View File

@@ -2,7 +2,7 @@ Name:Asinine Antics
ManaCost:2 U U ManaCost:2 U U
Types:Sorcery Types:Sorcery
K:MayFlashCost:2 K:MayFlashCost:2
A:SP$ RepeatEach | RepeatCards$ Creature.OppCtrl | Zone$ Battlefield | RepeatSubAbility$ DBToken | ChangeZoneTable$ True | SpellDescription$ For each creature your opponents control, create a Cursed Role token attached to that creature. (if you control another Role on it, put that one into the graveyard. Enchanted creature is 1/1) A:SP$ RepeatEach | RepeatCards$ Creature.OppCtrl | Zone$ Battlefield | RepeatSubAbility$ DBToken | ChangeZoneTable$ True | SpellDescription$ For each creature your opponents control, create a Cursed Role token attached to that creature. (If you control another Role on it, put that one into the graveyard. Enchanted creature is 1/1.)
SVar:DBToken:DB$ Token | TokenScript$ role_cursed | AttachedTo$ Remembered SVar:DBToken:DB$ Token | TokenScript$ role_cursed | AttachedTo$ Remembered
DeckHas:Type$Aura|Role & Ability$Token DeckHas:Type$Aura|Role & Ability$Token
Oracle:You may cast Asinine Antics as though it had flash if you pay {2} more to cast it. \nFor each creature your opponents control, create a Cursed Role token attached to that creature. (if you control another Role on it, put that one into the graveyard. Enchanted creature is 1/1) Oracle:You may cast Asinine Antics as though it had flash if you pay {2} more to cast it. \nFor each creature your opponents control, create a Cursed Role token attached to that creature. (If you control another Role on it, put that one into the graveyard. Enchanted creature is 1/1.)

View File

@@ -7,7 +7,7 @@ SVar:CurrentLife:Count$YourLifeTotal
SVar:X:Count$YourStartingLife/HalfDown SVar:X:Count$YourStartingLife/HalfDown
T:Mode$ ChangesZone | ValidCard$ Creature.nonToken+Other+YouCtrl | Origin$ Battlefield | Destination$ Graveyard | Execute$ DBAskOpponentDrawOrPlay | TriggerZones$ Battlefield | TriggerDescription$ Whenever another nontoken creature you control dies, target opponent may have you draw a card. If they don't, you may put a creature card with equal or lesser toughness from your hand onto the battlefield. T:Mode$ ChangesZone | ValidCard$ Creature.nonToken+Other+YouCtrl | Origin$ Battlefield | Destination$ Graveyard | Execute$ DBAskOpponentDrawOrPlay | TriggerZones$ Battlefield | TriggerDescription$ Whenever another nontoken creature you control dies, target opponent may have you draw a card. If they don't, you may put a creature card with equal or lesser toughness from your hand onto the battlefield.
SVar:DBAskOpponentDrawOrPlay:DB$ GenericChoice | ValidTgts$ Opponent | Choices$ DBDrawCard,DBCheatCreature SVar:DBAskOpponentDrawOrPlay:DB$ GenericChoice | ValidTgts$ Opponent | Choices$ DBDrawCard,DBCheatCreature
SVar:DBDrawCard:DB$ Draw | Defined$ You | NumCards$ 1 | SpellDescription$ Controller draws a card SVar:DBDrawCard:DB$ Draw | Defined$ You | NumCards$ 1 | SpellDescription$ CARDNAME's controller draws a card.
SVar:DBCheatCreature:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Creature.toughnessLEY | ChangeNum$ 1 | SpellDescription$ Controller may put a creature card with equal or lesser toughness from your hand onto the battlefield. SVar:DBCheatCreature:DB$ ChangeZone | Origin$ Hand | Destination$ Battlefield | ChangeType$ Creature.toughnessLEY | ChangeNum$ 1 | SpellDescription$ CARDNAME's controller may put a creature card with equal or lesser toughness from their hand onto the battlefield.
SVar:Y:TriggeredCard$CardToughness SVar:Y:TriggeredCard$CardToughness
Oracle:As long as your life total is less than or equal to half your starting life total, Bane, Lord of Darkness has indestructible.\nWhenever another nontoken creature you control dies, target opponent may have you draw a card. If they don't, you may put a creature card with equal or lesser toughness from your hand onto the battlefield. Oracle:As long as your life total is less than or equal to half your starting life total, Bane, Lord of Darkness has indestructible.\nWhenever another nontoken creature you control dies, target opponent may have you draw a card. If they don't, you may put a creature card with equal or lesser toughness from your hand onto the battlefield.

View File

@@ -2,5 +2,5 @@ Name:Battershield Warrior
ManaCost:2 W ManaCost:2 W
Types:Creature Human Warrior Types:Creature Human Warrior
PT:2/2 PT:2/2
A:AB$ PumpAll | Cost$ 1 W | ValidCards$ Creature.YouCtrl | NumAtt$ +1 | NumDef$ +1 | Boast$ True | SpellDescription$ Creatures you control get +1/+1 until end of turn A:AB$ PumpAll | Cost$ 1 W | ValidCards$ Creature.YouCtrl | NumAtt$ +1 | NumDef$ +1 | Boast$ True | SpellDescription$ Creatures you control get +1/+1 until end of turn.
Oracle:Boast — {1}{W}: Creatures you control get +1/+1 until end of turn. (Activate only if this creature attacked this turn and only once each turn.) Oracle:Boast — {1}{W}: Creatures you control get +1/+1 until end of turn. (Activate only if this creature attacked this turn and only once each turn.)

View File

@@ -2,7 +2,7 @@ Name:Belbe, Corrupted Observer
ManaCost:B G ManaCost:B G
Types:Legendary Creature Phyrexian Zombie Elf Types:Legendary Creature Phyrexian Zombie Elf
PT:2/2 PT:2/2
T:Mode$ Phase | Phase$ Main2 | TriggerZones$ Battlefield | Execute$ TrigMana | TriggerDescription$ At the beginning of each player's postcombat main phase, that player adds {C}{C} for each of your opponents who lost life this turn. (Damage causes loss of life.) T:Mode$ Phase | Phase$ Main2 | TriggerZones$ Battlefield | Execute$ TrigMana | TriggerDescription$ At the beginning of each postcombat main phase, the active player adds {C}{C} for each of your opponents who lost life this turn. (Damage causes loss of life.)
SVar:TrigMana:DB$ Mana | Produced$ C | Amount$ X | Defined$ TriggeredPlayer SVar:TrigMana:DB$ Mana | Produced$ C | Amount$ X | Defined$ TriggeredPlayer
SVar:X:PlayerCountOpponents$HasPropertyLostLifeThisTurn/Twice SVar:X:PlayerCountOpponents$HasPropertyLostLifeThisTurn/Twice
Oracle:At the beginning of each player's postcombat main phase, that player adds {C}{C} for each of your opponents who lost life this turn. (Damage causes loss of life.) Oracle:At the beginning of each postcombat main phase, the active player adds {C}{C} for each of your opponents who lost life this turn. (Damage causes loss of life.)

View File

@@ -3,7 +3,7 @@ ManaCost:3 B B
Types:Enchantment Types:Enchantment
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever a creature dies, put a charge counter on CARDNAME. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature | TriggerZones$ Battlefield | Execute$ TrigPutCounter | TriggerDescription$ Whenever a creature dies, put a charge counter on CARDNAME.
SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ CHARGE | CounterNum$ 1 SVar:TrigPutCounter:DB$ PutCounter | Defined$ Self | CounterType$ CHARGE | CounterNum$ 1
T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigGetMana | TriggerDescription$ At the beginning of your precombat main phase, add {B} for each charge counter on CARDNAME. T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigGetMana | TriggerDescription$ At the beginning of your first main phase, add {B} for each charge counter on CARDNAME.
SVar:TrigGetMana:DB$ Mana | Produced$ B | Amount$ X | SpellDescription$ Add {X}{B} SVar:TrigGetMana:DB$ Mana | Produced$ B | Amount$ X | SpellDescription$ Add {X}{B}
SVar:X:Count$CardCounters.CHARGE SVar:X:Count$CardCounters.CHARGE
Oracle:Whenever a creature dies, put a charge counter on Black Market.\nAt the beginning of your precombat main phase, add {B} for each charge counter on Black Market. Oracle:Whenever a creature dies, put a charge counter on Black Market.\nAt the beginning of your first main phase, add {B} for each charge counter on Black Market.

View File

@@ -1,7 +1,7 @@
Name:Black Market Connections Name:Black Market Connections
ManaCost:2 B ManaCost:2 B
Types:Enchantment Types:Enchantment
T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigCharm | TriggerDescription$ At the beginning of your precombat main phase, ABILITY T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigCharm | TriggerDescription$ At the beginning of your first main phase, ABILITY
SVar:TrigCharm:DB$ Charm | Choices$ DBTreasureLose1,DBDrawLose2,DBTokenLose3 | MinCharmNum$ 1 | CharmNum$ 3 SVar:TrigCharm:DB$ Charm | Choices$ DBTreasureLose1,DBDrawLose2,DBTokenLose3 | MinCharmNum$ 1 | CharmNum$ 3
SVar:DBTreasureLose1:DB$ Token | TokenScript$ c_a_treasure_sac | SubAbility$ DBLoseLife1 | SpellDescription$ Sell Contraband — Create a Treasure token. You lose 1 life. SVar:DBTreasureLose1:DB$ Token | TokenScript$ c_a_treasure_sac | SubAbility$ DBLoseLife1 | SpellDescription$ Sell Contraband — Create a Treasure token. You lose 1 life.
SVar:DBDrawLose2:DB$ Draw | NumCards$ 1 | SubAbility$ DBLoseLife2 | SpellDescription$ Buy Information — Draw a card. You lose 2 life. SVar:DBDrawLose2:DB$ Draw | NumCards$ 1 | SubAbility$ DBLoseLife2 | SpellDescription$ Buy Information — Draw a card. You lose 2 life.
@@ -10,4 +10,4 @@ SVar:DBLoseLife1:DB$ LoseLife | LifeAmount$ 1 | Defined$ You
SVar:DBLoseLife2:DB$ LoseLife | LifeAmount$ 2 | Defined$ You SVar:DBLoseLife2:DB$ LoseLife | LifeAmount$ 2 | Defined$ You
SVar:DBLoseLife3:DB$ LoseLife | LifeAmount$ 3 | Defined$ You SVar:DBLoseLife3:DB$ LoseLife | LifeAmount$ 3 | Defined$ You
DeckHas:Ability$Token|Sacrifice & Type$Artifact|Treasure|Shapeshifter DeckHas:Ability$Token|Sacrifice & Type$Artifact|Treasure|Shapeshifter
Oracle:At the beginning of your precombat main phase, choose one or more —\n• Sell Contraband — Create a Treasure token. You lose 1 life.\n• Buy Information — Draw a card. You lose 2 life.\n• Hire a Mercenary — Create a 3/2 colorless Shapeshifter creature token with changeling. You lose 3 life. Oracle:At the beginning of your first main phase, choose one or more —\n• Sell Contraband — Create a Treasure token. You lose 1 life.\n• Buy Information — Draw a card. You lose 2 life.\n• Hire a Mercenary — Create a 3/2 colorless Shapeshifter creature token with changeling. You lose 3 life.

View File

@@ -1,5 +1,5 @@
Name:Black Tulip Name:Black Tulip
ManaCost:0 ManaCost:0
Types:Artifact Types:Artifact
A:AB$ Mana | Cost$ T Exile<1/CARDNAME> | Produced$ Any | Amount$ 3 | AILogic$ BlackLotus | CheckSVar$ Count$YourTurns | SVarCompare$ GE6 | SpellDescription$ Add three mana of any one color. You can't activate this ability until you've begun your sixth turn of the game (Keep track if this is in your deck!) A:AB$ Mana | Cost$ T Exile<1/CARDNAME> | Produced$ Any | Amount$ 3 | AILogic$ BlackLotus | CheckSVar$ Count$YourTurns | SVarCompare$ GE6 | SpellDescription$ Add three mana of any one color. You can't activate this ability until you've begun your sixth turn of the game. (Keep track if this is in your deck!)
Oracle:{T}, Exile Black Tulip: Add three mana of any one color. You can't activate this ability until you've begun your sixth turn of the game (Keep track if this is in your deck!) Oracle:{T}, Exile Black Tulip: Add three mana of any one color. You can't activate this ability until you've begun your sixth turn of the game. (Keep track if this is in your deck!)

View File

@@ -1,8 +1,8 @@
Name:Blinkmoth Urn Name:Blinkmoth Urn
ManaCost:5 ManaCost:5
Types:Artifact Types:Artifact
T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ Player | TriggerZones$ Battlefield | PresentDefined$ Self | IsPresent$ Card.untapped | Execute$ TrigGetMana | TriggerDescription$ At the beginning of each player's precombat main phase, if CARDNAME is untapped, that player adds {C} for each artifact they control. T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ Player | TriggerZones$ Battlefield | PresentDefined$ Self | IsPresent$ Card.untapped | Execute$ TrigGetMana | TriggerDescription$ At the beginning of each player's first main phase, if CARDNAME is untapped, that player adds {C} for each artifact they control.
SVar:TrigGetMana:DB$ Mana | Produced$ C | Amount$ X | Defined$ TriggeredPlayer SVar:TrigGetMana:DB$ Mana | Produced$ C | Amount$ X | Defined$ TriggeredPlayer
SVar:X:Count$Valid Artifact.ActivePlayerCtrl SVar:X:Count$Valid Artifact.ActivePlayerCtrl
AI:RemoveDeck:Random AI:RemoveDeck:Random
Oracle:At the beginning of each player's precombat main phase, if Blinkmoth Urn is untapped, that player adds {C} for each artifact they control. Oracle:At the beginning of each player's first main phase, if Blinkmoth Urn is untapped, that player adds {C} for each artifact they control.

View File

@@ -3,7 +3,7 @@ ManaCost:3 W W
Types:Enchantment Types:Enchantment
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigCounter | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment you control enters, put a blessing counter on CARDNAME. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self,Enchantment.Other+YouCtrl | Execute$ TrigCounter | TriggerDescription$ Constellation — Whenever CARDNAME or another enchantment you control enters, put a blessing counter on CARDNAME.
SVar:TrigCounter:DB$ PutCounter | CounterType$ BLESSING | CounterNum$ 1 SVar:TrigCounter:DB$ PutCounter | CounterType$ BLESSING | CounterNum$ 1
S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddPower$ X | AddToughness$ X | Description$ Creatures you control get +1/+1 for each blessing counter on CARDNAME S:Mode$ Continuous | Affected$ Creature.YouCtrl | AddPower$ X | AddToughness$ X | Description$ Creatures you control get +1/+1 for each blessing counter on CARDNAME.
SVar:X:Count$CardCounters.BLESSING SVar:X:Count$CardCounters.BLESSING
DeckHints:Type$Enchantment DeckHints:Type$Enchantment
DeckHas:Ability$Counters DeckHas:Ability$Counters

View File

@@ -1,11 +1,11 @@
Name:Bounty of the Luxa Name:Bounty of the Luxa
ManaCost:2 G U ManaCost:2 G U
Types:Enchantment Types:Enchantment
T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRemove | TriggerDescription$ At the beginning of your precombat main phase, remove all flood counters from CARDNAME. If no counters were removed this way, put a flood counter on CARDNAME and draw a card. Otherwise, add {C}{G}{U}. T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRemove | TriggerDescription$ At the beginning of your first main phase, remove all flood counters from CARDNAME. If no counters were removed this way, put a flood counter on CARDNAME and draw a card. Otherwise, add {C}{G}{U}.
SVar:TrigRemove:DB$ RemoveCounter | CounterType$ FLOOD | CounterNum$ All | RememberRemoved$ True | SubAbility$ DBPutCounter SVar:TrigRemove:DB$ RemoveCounter | CounterType$ FLOOD | CounterNum$ All | RememberRemoved$ True | SubAbility$ DBPutCounter
SVar:DBPutCounter:DB$ PutCounter | Defined$ Self | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | CounterType$ FLOOD | CounterNum$ 1 | SubAbility$ DBDraw SVar:DBPutCounter:DB$ PutCounter | Defined$ Self | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | CounterType$ FLOOD | CounterNum$ 1 | SubAbility$ DBDraw
SVar:DBDraw:DB$ Draw | NumCards$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | SubAbility$ DBGetMana SVar:DBDraw:DB$ Draw | NumCards$ 1 | ConditionCheckSVar$ X | ConditionSVarCompare$ EQ0 | SubAbility$ DBGetMana
SVar:DBGetMana:DB$ Mana | Produced$ C G U | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | SubAbility$ DBCleanup SVar:DBGetMana:DB$ Mana | Produced$ C G U | ConditionCheckSVar$ X | ConditionSVarCompare$ GE1 | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:X:Count$RememberedSize SVar:X:Count$RememberedSize
Oracle:At the beginning of your precombat main phase, remove all flood counters from Bounty of the Luxa. If no counters were removed this way, put a flood counter on Bounty of the Luxa and draw a card. Otherwise, add {C}{G}{U}. Oracle:At the beginning of your first main phase, remove all flood counters from Bounty of the Luxa. If no counters were removed this way, put a flood counter on Bounty of the Luxa and draw a card. Otherwise, add {C}{G}{U}.

View File

@@ -1,6 +1,6 @@
Name:Brainsurge Name:Brainsurge
ManaCost:2 U ManaCost:2 U
Types:Instant Types:Instant
A:SP$ Draw | NumCards$ 4 | StackDescription$ {p:You} draws four cards, | SpellDescription$ Draw four cards, then put two cards from your hand on top of your library in any order | SubAbility$ ChangeZoneDB A:SP$ Draw | NumCards$ 4 | StackDescription$ {p:You} draws four cards, | SpellDescription$ Draw four cards, then put two cards from your hand on top of your library in any order. | SubAbility$ ChangeZoneDB
SVar:ChangeZoneDB:DB$ ChangeZone | Origin$ Hand | Destination$ Library | ChangeNum$ 2 | Mandatory$ True | Reorder$ True | StackDescription$ then puts two cards from their hand on top of their library in any order. SVar:ChangeZoneDB:DB$ ChangeZone | Origin$ Hand | Destination$ Library | ChangeNum$ 2 | Mandatory$ True | Reorder$ True | StackDescription$ then puts two cards from their hand on top of their library in any order.
Oracle:Draw four cards, then put two cards from your hand on top of your library in any order. Oracle:Draw four cards, then put two cards from your hand on top of your library in any order.

View File

@@ -2,7 +2,7 @@ Name:Brawl
ManaCost:3 R R ManaCost:3 R R
Types:Instant Types:Instant
A:SP$ AnimateAll | ValidCards$ Creature | Abilities$ ThrowPunch | SpellDescription$ Until end of turn, all creatures gain "{T}: This creature deals damage equal to its power to target creature." A:SP$ AnimateAll | ValidCards$ Creature | Abilities$ ThrowPunch | SpellDescription$ Until end of turn, all creatures gain "{T}: This creature deals damage equal to its power to target creature."
SVar:ThrowPunch:AB$ DealDamage | Cost$ T | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ BrawlX | SpellDescription$ This creature deals damage equal to its power to target creature. SVar:ThrowPunch:AB$ DealDamage | Cost$ T | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ BrawlX | SpellDescription$ CARDNAME deals damage equal to its power to target creature.
SVar:BrawlX:Count$CardPower SVar:BrawlX:Count$CardPower
AI:RemoveDeck:All AI:RemoveDeck:All
Oracle:Until end of turn, all creatures gain "{T}: This creature deals damage equal to its power to target creature." Oracle:Until end of turn, all creatures gain "{T}: This creature deals damage equal to its power to target creature."

View File

@@ -3,10 +3,10 @@ ManaCost:3 R
Types:Enchantment Types:Enchantment
T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.attacking+YouCtrl | Execute$ TrigDamage | TriggerZones$ Battlefield | TriggerDescription$ Whenever an attacking creature you control dies, CARDNAME deals 2 damage to each opponent. T:Mode$ ChangesZone | Origin$ Battlefield | Destination$ Graveyard | ValidCard$ Creature.attacking+YouCtrl | Execute$ TrigDamage | TriggerZones$ Battlefield | TriggerDescription$ Whenever an attacking creature you control dies, CARDNAME deals 2 damage to each opponent.
SVar:TrigDamage:DB$ DealDamage | Defined$ Opponent | NumDmg$ 2 SVar:TrigDamage:DB$ DealDamage | Defined$ Opponent | NumDmg$ 2
T:Mode$ Phase | Phase$ Main2 | ValidPlayer$ You | TriggerZones$ Battlefield | CheckSVar$ RaidTest | Execute$ TrigExile | TriggerDescription$ Raid — At the beginning of your postcombat main phase, if you attacked with a creature this turn, exile the top card of your library. Until end of combat on your next turn, you may play that card. T:Mode$ Phase | Phase$ Main2 | ValidPlayer$ You | TriggerZones$ Battlefield | CheckSVar$ RaidTest | Execute$ TrigExile | TriggerDescription$ Raid — At the beginning of each of your postcombat main phases, if you attacked this turn, exile the top card of your library. Until end of combat on your next turn, you may play that card.
SVar:TrigExile:DB$ Dig | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect SVar:TrigExile:DB$ Dig | DigNum$ 1 | ChangeNum$ All | DestinationZone$ Exile | RememberChanged$ True | SubAbility$ DBEffect
SVar:DBEffect:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ Play | SubAbility$ DBCleanup | ExileOnMoved$ Exile | Duration$ UntilEndOfCombatYourNextTurn SVar:DBEffect:DB$ Effect | RememberObjects$ RememberedCard | StaticAbilities$ Play | SubAbility$ DBCleanup | ExileOnMoved$ Exile | Duration$ UntilEndOfCombatYourNextTurn
SVar:Play:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ Until end of combat on your next turn, you may play that card. SVar:Play:Mode$ Continuous | MayPlay$ True | EffectZone$ Command | Affected$ Card.IsRemembered | AffectedZone$ Exile | Description$ Until end of combat on your next turn, you may play that card.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:RaidTest:Count$AttackersDeclared SVar:RaidTest:Count$AttackersDeclared
Oracle:Whenever an attacking creature you control dies, Brazen Cannonade deals 2 damage to each opponent.\nRaid — At the beginning of your postcombat main phase, if you attacked with a creature this turn, exile the top card of your library. Until end of combat on your next turn, you may play that card. Oracle:Whenever an attacking creature you control dies, Brazen Cannonade deals 2 damage to each opponent.\nRaid — At the beginning of each of your postcombat main phases, if you attacked this turn, exile the top card of your library. Until end of combat on your next turn, you may play that card.

View File

@@ -8,8 +8,8 @@ T:Mode$ Attacks | ValidCard$ Card.Self | Execute$ Aurify | TriggerDescription$ W
T:Mode$ Blocks | ValidCard$ Card.Self | Execute$ Aurify | Secondary$ True | TriggerDescription$ Whenever CARDNAME attacks or blocks, you may attach to it any number of Auras on the battlefield and you may put onto the battlefield attached to it any number of Aura cards that could enchant it from your graveyard and/or hand. T:Mode$ Blocks | ValidCard$ Card.Self | Execute$ Aurify | Secondary$ True | TriggerDescription$ Whenever CARDNAME attacks or blocks, you may attach to it any number of Auras on the battlefield and you may put onto the battlefield attached to it any number of Aura cards that could enchant it from your graveyard and/or hand.
SVar:Aurify:DB$ RepeatEach | RepeatSubAbility$ BrunaAttach | RepeatCards$ Aura.CanEnchantSource+!Attached | SubAbility$ ZoneAuras SVar:Aurify:DB$ RepeatEach | RepeatSubAbility$ BrunaAttach | RepeatCards$ Aura.CanEnchantSource+!Attached | SubAbility$ ZoneAuras
SVar:BrunaAttach:DB$ Attach | Object$ Remembered | Defined$ Self | Optional$ True SVar:BrunaAttach:DB$ Attach | Object$ Remembered | Defined$ Self | Optional$ True
SVar:ZoneAuras:DB$ ChangeZone | Origin$ Hand,Graveyard | Destination$ Battlefield | ChangeType$ Aura.CanEnchantSource+YouOwn | AttachedTo$ Self | ChangeNum$ Count | Optional$ True | Hidden$ True SVar:ZoneAuras:DB$ ChangeZone | Origin$ Hand,Graveyard | Destination$ Battlefield | ChangeType$ Aura.CanEnchantSource+YouOwn | AttachedTo$ Self | ChangeNum$ CountAuras | Optional$ True | Hidden$ True
SVar:Count:Count$ValidHand,Graveyard Aura.CanEnchantSource+YouOwn SVar:CountAuras:Count$ValidHand,Graveyard Aura.CanEnchantSource+YouOwn
SVar:HasAttackEffect:TRUE SVar:HasAttackEffect:TRUE
SVar:HasBlockEffect:TRUE SVar:HasBlockEffect:TRUE
DeckNeeds:Type$Aura DeckNeeds:Type$Aura

View File

@@ -2,5 +2,5 @@ Name:Cabal Inquisitor
ManaCost:1 B ManaCost:1 B
Types:Creature Human Minion Types:Creature Human Minion
PT:1/1 PT:1/1
A:AB$ Discard | Cost$ 1 B T ExileFromGrave<2/Card> | ValidTgts$ Player | Activation$ Threshold | NumCards$ 1 | Mode$ TgtChoose | SorcerySpeed$ True | SpellDescription$ Target player discards a card. Activate only as a sorcery and only if seven or more cards are in your graveyard. | PrecostDesc$ Threshold — A:AB$ Discard | Cost$ 1 B T ExileFromGrave<2/Card> | ValidTgts$ Player | Activation$ Threshold | PrecostDesc$ Threshold — | NumCards$ 1 | Mode$ TgtChoose | SorcerySpeed$ True | SpellDescription$ Target player discards a card. Activate only as a sorcery and only if seven or more cards are in your graveyard.
Oracle:Threshold — {1}{B}, {T}, Exile two cards from your graveyard: Target player discards a card. Activate only as a sorcery and only if seven or more cards are in your graveyard. Oracle:Threshold — {1}{B}, {T}, Exile two cards from your graveyard: Target player discards a card. Activate only as a sorcery and only if seven or more cards are in your graveyard.

View File

@@ -3,10 +3,10 @@ ManaCost:B
Types:Creature Horror Types:Creature Horror
PT:1/1 PT:1/1
K:Menace K:Menace
T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | Execute$ DBImmediateTrigger | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your precombat main phase, you may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name. T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | Execute$ DBImmediateTrigger | TriggerZones$ Battlefield | TriggerDescription$ At the beginning of your first main phase, you may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name.
SVar:DBImmediateTrigger:AB$ ImmediateTrigger | Execute$ NameCard | TriggerDescription$ You may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name. | Cost$ Sac<1/Creature> SVar:DBImmediateTrigger:AB$ ImmediateTrigger | Execute$ NameCard | TriggerDescription$ You may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name. | Cost$ Sac<1/Creature>
SVar:NameCard:DB$ NameCard | Defined$ You | ValidCards$ Card.nonLand | ValidDescription$ nonland | SubAbility$ DBDiscard | SpellDescription$ Choose a nonland card name. Target player reveals their hand and discards all cards with that name. SVar:NameCard:DB$ NameCard | Defined$ You | ValidCards$ Card.nonLand | ValidDescription$ nonland | SubAbility$ DBDiscard | SpellDescription$ Choose a nonland card name. Target player reveals their hand and discards all cards with that name.
SVar:DBDiscard:DB$ Discard | ValidTgts$ Player | Mode$ RevealDiscardAll | DiscardValid$ Card.NamedCard | SubAbility$ DBCleanup SVar:DBDiscard:DB$ Discard | ValidTgts$ Player | Mode$ RevealDiscardAll | DiscardValid$ Card.NamedCard | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearNamedCard$ True SVar:DBCleanup:DB$ Cleanup | ClearNamedCard$ True
AI:RemoveDeck:All AI:RemoveDeck:All
Oracle:Menace\nAt the beginning of your precombat main phase, you may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name. Oracle:Menace\nAt the beginning of your first main phase, you may sacrifice a creature. When you do, choose a nonland card name, then target player reveals their hand and discards all cards with that name.

View File

@@ -3,5 +3,5 @@ ManaCost:1 B B
Types:Creature Human Minion Types:Creature Human Minion
PT:1/1 PT:1/1
A:AB$ Pump | Cost$ B T | NumAtt$ -1 | NumDef$ -1 | IsCurse$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | SpellDescription$ Target creature gets -1/-1 until end of turn. A:AB$ Pump | Cost$ B T | NumAtt$ -1 | NumDef$ -1 | IsCurse$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | SpellDescription$ Target creature gets -1/-1 until end of turn.
A:AB$ Pump | Cost$ 3 B B T | NumAtt$ -2 | NumDef$ -2 | IsCurse$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | Activation$ Threshold | SpellDescription$ Target creature gets -2/-2 until end of turn. Activate only if seven or more cards are in your graveyard. | PrecostDesc$ Threshold — A:AB$ Pump | Cost$ 3 B B T | NumAtt$ -2 | NumDef$ -2 | IsCurse$ True | ValidTgts$ Creature | TgtPrompt$ Select target creature | Activation$ Threshold | PrecostDesc$ Threshold — | SpellDescription$ Target creature gets -2/-2 until end of turn. Activate only if seven or more cards are in your graveyard.
Oracle:{B}, {T}: Target creature gets -1/-1 until end of turn.\nThreshold — {3}{B}{B}, {T}: Target creature gets -2/-2 until end of turn. Activate only if seven or more cards are in your graveyard. Oracle:{B}, {T}: Target creature gets -1/-1 until end of turn.\nThreshold — {3}{B}{B}, {T}: Target creature gets -2/-2 until end of turn. Activate only if seven or more cards are in your graveyard.

View File

@@ -1,9 +1,9 @@
Name:Call a Surprise Witness Name:Call a Surprise Witness
ManaCost:1 W ManaCost:1 W
Types:Sorcery Types:Sorcery
A:SP$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouCtrl+cmcLE3 | AnimateSubAbility$ DBAnimate | RememberChanged$ True | SubAbility$ DBPutCounter | TgtPrompt$ Select target creature card with mana value 3 or less | SpellDescription$ Return target creature card with mana value 3 or less from your graveyard to the battlefield. A:SP$ ChangeZone | Origin$ Graveyard | Destination$ Battlefield | ValidTgts$ Creature.YouCtrl+cmcLE3 | AnimateSubAbility$ DBAnimate | RememberChanged$ True | SubAbility$ DBPutCounter | TgtPrompt$ Select target creature card with mana value 3 or less | StackDescription$ REP Return_{p:You} returns & target creature card with mana value 3 or less_{c:Targeted} & your_their & Put_{p:You} puts & on it_on {c:Targeted} | SpellDescription$ Return target creature card with mana value 3 or less from your graveyard to the battlefield. Put a flying counter on it. It's a Spirit in addition to its other types.
SVar:DBPutCounter:DB$ PutCounter | Defined$ Remembered | CounterType$ Flying | CounterNum$ 1 | SubAbility$ DBCleanup | SpellDescription$ Put a flying counter on it SVar:DBPutCounter:DB$ PutCounter | Defined$ Remembered | CounterType$ Flying | CounterNum$ 1 | SubAbility$ DBCleanup | StackDescription$ None
SVar:DBAnimate:DB$ Animate | Defined$ Remembered | Types$ Spirit | Duration$ Permanent | SpellDescription$ It's a Spirit in addition to its other types. SVar:DBAnimate:DB$ Animate | Defined$ Remembered | Types$ Spirit | Duration$ Permanent
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
DeckHas:Ability$Graveyard & Type$Spirit DeckHas:Ability$Graveyard & Type$Spirit
Oracle:Return target creature card with mana value 3 or less from your graveyard to the battlefield. Put a flying counter on it. It's a Spirit in addition to its other types. Oracle:Return target creature card with mana value 3 or less from your graveyard to the battlefield. Put a flying counter on it. It's a Spirit in addition to its other types.

View File

@@ -4,7 +4,7 @@ Types:Sorcery
A:SP$ GainControl | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | AllValid$ Creature.TargetedPlayerCtrl | AddKWs$ Haste | Untap$ True | NewController$ You | LoseControl$ EOT | RememberControlled$ True | SubAbility$ DBEffect | SpellDescription$ Gain control of all creatures target opponent controls until end of turn. Untap those creatures. They gain haste until end of turn. You can't attack that player this turn. You can't sacrifice those creatures this turn. A:SP$ GainControl | ValidTgts$ Opponent | TgtPrompt$ Select target opponent | AllValid$ Creature.TargetedPlayerCtrl | AddKWs$ Haste | Untap$ True | NewController$ You | LoseControl$ EOT | RememberControlled$ True | SubAbility$ DBEffect | SpellDescription$ Gain control of all creatures target opponent controls until end of turn. Untap those creatures. They gain haste until end of turn. You can't attack that player this turn. You can't sacrifice those creatures this turn.
SVar:DBEffect:DB$ Effect | RememberObjects$ TargetedPlayer,RememberedCard | StaticAbilities$ CantSac,CantAttack | SubAbility$ DBCleanup SVar:DBEffect:DB$ Effect | RememberObjects$ TargetedPlayer,RememberedCard | StaticAbilities$ CantSac,CantAttack | SubAbility$ DBCleanup
SVar:CantSac:Mode$ CantSacrifice | ValidCard$ Card.IsRemembered+YouCtrl | Description$ You can't sacrifice those creatures this turn. SVar:CantSac:Mode$ CantSacrifice | ValidCard$ Card.IsRemembered+YouCtrl | Description$ You can't sacrifice those creatures this turn.
SVar:CantAttack:Mode$ CantAttack | ValidCard$ Creature.YouCtrl | Target$ Player.IsRemembered | Description$ You can't attack that player this turn SVar:CantAttack:Mode$ CantAttack | ValidCard$ Creature.YouCtrl | Target$ Player.IsRemembered | Description$ You can't attack that player this turn.
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
AI:RemoveDeck:All AI:RemoveDeck:All
Oracle:Gain control of all creatures target opponent controls until end of turn. Untap those creatures. They gain haste until end of turn. You can't attack that player this turn. You can't sacrifice those creatures this turn. Oracle:Gain control of all creatures target opponent controls until end of turn. Untap those creatures. They gain haste until end of turn. You can't attack that player this turn. You can't sacrifice those creatures this turn.

View File

@@ -2,9 +2,9 @@ Name:Casualties of War
ManaCost:2 B B G G ManaCost:2 B B G G
Types:Sorcery Types:Sorcery
A:SP$ Charm | MinCharmNum$ 1 | CharmNum$ 5 | Choices$ DestroyArtifact,DestroyCreature,DestroyEnchantment,DestroyLand,DestroyPlaneswalker A:SP$ Charm | MinCharmNum$ 1 | CharmNum$ 5 | Choices$ DestroyArtifact,DestroyCreature,DestroyEnchantment,DestroyLand,DestroyPlaneswalker
SVar:DestroyArtifact:DB$ Destroy | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SpellDescription$ Destroy target artifact SVar:DestroyArtifact:DB$ Destroy | ValidTgts$ Artifact | TgtPrompt$ Select target artifact | SpellDescription$ Destroy target artifact.
SVar:DestroyCreature:DB$ Destroy | ValidTgts$ Creature | TgtPrompt$ Select target creature | SpellDescription$ Destroy target creature. SVar:DestroyCreature:DB$ Destroy | ValidTgts$ Creature | TgtPrompt$ Select target creature | SpellDescription$ Destroy target creature.
SVar:DestroyEnchantment:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target Enchantment | SpellDescription$ Destroy target Enchantment. SVar:DestroyEnchantment:DB$ Destroy | ValidTgts$ Enchantment | TgtPrompt$ Select target Enchantment | SpellDescription$ Destroy target enchantment.
SVar:DestroyLand:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land | SpellDescription$ Destroy target land. SVar:DestroyLand:DB$ Destroy | ValidTgts$ Land | TgtPrompt$ Select target land | SpellDescription$ Destroy target land.
SVar:DestroyPlaneswalker:DB$ Destroy | ValidTgts$ Planeswalker | TgtPrompt$ Select target planeswalker | SpellDescription$ Destroy target planeswalker. SVar:DestroyPlaneswalker:DB$ Destroy | ValidTgts$ Planeswalker | TgtPrompt$ Select target planeswalker | SpellDescription$ Destroy target planeswalker.
Oracle:Choose one or more —\n• Destroy target artifact.\n• Destroy target creature.\n• Destroy target enchantment.\n• Destroy target land.\n• Destroy target planeswalker. Oracle:Choose one or more —\n• Destroy target artifact.\n• Destroy target creature.\n• Destroy target enchantment.\n• Destroy target land.\n• Destroy target planeswalker.

View File

@@ -1,7 +1,7 @@
Name:Cavalcade of Calamity Name:Cavalcade of Calamity
ManaCost:1 R ManaCost:1 R
Types:Enchantment Types:Enchantment
T:Mode$ Attacks | ValidCard$ Creature.powerLE1+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever a creature you control with power 1 or less attacks, CARDNAME deals 1 damage to the player or planeswalker that creature is attacking T:Mode$ Attacks | ValidCard$ Creature.powerLE1+YouCtrl | TriggerZones$ Battlefield | Execute$ TrigDamage | TriggerDescription$ Whenever a creature you control with power 1 or less attacks, CARDNAME deals 1 damage to the player or planeswalker that creature is attacking.
SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredDefender.Player & Valid Planeswalker.TriggeredDefender | NumDmg$ 1 SVar:TrigDamage:DB$ DealDamage | Defined$ TriggeredDefender.Player & Valid Planeswalker.TriggeredDefender | NumDmg$ 1
SVar:PlayMain1:TRUE SVar:PlayMain1:TRUE
Oracle:Whenever a creature you control with power 1 or less attacks, Cavalcade of Calamity deals 1 damage to the player or planeswalker that creature is attacking. Oracle:Whenever a creature you control with power 1 or less attacks, Cavalcade of Calamity deals 1 damage to the player or planeswalker that creature is attacking.

View File

@@ -19,7 +19,7 @@ ManaCost:no cost
Colors:red Colors:red
Types:Legendary Planeswalker Chandra Types:Legendary Planeswalker Chandra
Loyalty:4 Loyalty:4
A:AB$ DealDamage | Cost$ AddCounter<1/LOYALTY> | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | Planeswalker$ True | NumDmg$ 2 | SpellDescription$ CARDNAME deals 2 damage to target player or planeswalker A:AB$ DealDamage | Cost$ AddCounter<1/LOYALTY> | ValidTgts$ Player,Planeswalker | TgtPrompt$ Select target player or planeswalker | Planeswalker$ True | NumDmg$ 2 | SpellDescription$ CARDNAME deals 2 damage to target player or planeswalker.
A:AB$ DealDamage | Cost$ SubCounter<2/LOYALTY> | ValidTgts$ Creature | Planeswalker$ True | NumDmg$ 2 | SpellDescription$ CARDNAME deals 2 damage to target creature. A:AB$ DealDamage | Cost$ SubCounter<2/LOYALTY> | ValidTgts$ Creature | Planeswalker$ True | NumDmg$ 2 | SpellDescription$ CARDNAME deals 2 damage to target creature.
A:AB$ DealDamage | Cost$ SubCounter<7/LOYALTY> | Defined$ Player.Opponent | Planeswalker$ True | Ultimate$ True | NumDmg$ 6 | RememberDamaged$ True | SubAbility$ DBUltimateEmblem | SpellDescription$ CARDNAME deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with "At the beginning of your upkeep, this emblem deals 3 damage to you." A:AB$ DealDamage | Cost$ SubCounter<7/LOYALTY> | Defined$ Player.Opponent | Planeswalker$ True | Ultimate$ True | NumDmg$ 6 | RememberDamaged$ True | SubAbility$ DBUltimateEmblem | SpellDescription$ CARDNAME deals 6 damage to each opponent. Each player dealt damage this way gets an emblem with "At the beginning of your upkeep, this emblem deals 3 damage to you."
SVar:DBUltimateEmblem:DB$ Effect | Name$ Emblem — Chandra, Roaring Flame | Image$ emblem_chandra_roaring_flame | Stackable$ True | Triggers$ FlameTrigger | Duration$ Permanent | AILogic$ Always | EffectOwner$ Player.IsRemembered | SubAbility$ DBCleanup SVar:DBUltimateEmblem:DB$ Effect | Name$ Emblem — Chandra, Roaring Flame | Image$ emblem_chandra_roaring_flame | Stackable$ True | Triggers$ FlameTrigger | Duration$ Permanent | AILogic$ Always | EffectOwner$ Player.IsRemembered | SubAbility$ DBCleanup

View File

@@ -4,5 +4,5 @@ Types:Enchantment
T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigAnimate | TriggerDescription$ At the beginning of your upkeep, instant and sorcery cards in your hand perpetually gain "This spell costs {1} less to cast." T:Mode$ Phase | Phase$ Upkeep | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigAnimate | TriggerDescription$ At the beginning of your upkeep, instant and sorcery cards in your hand perpetually gain "This spell costs {1} less to cast."
SVar:TrigAnimate:DB$ AnimateAll | ValidCards$ Sorcery.YouOwn,Instant.YouOwn | Zone$ Hand | staticAbilities$ ReduceCost | Duration$ Perpetual SVar:TrigAnimate:DB$ AnimateAll | ValidCards$ Sorcery.YouOwn,Instant.YouOwn | Zone$ Hand | staticAbilities$ ReduceCost | Duration$ Perpetual
SVar:ReduceCost:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ 1 | EffectZone$ All | Description$ This spell costs {1} less to cast. SVar:ReduceCost:Mode$ ReduceCost | ValidCard$ Card.Self | Type$ Spell | Amount$ 1 | EffectZone$ All | Description$ This spell costs {1} less to cast.
A:AB$ MakeCard | Cost$ Sac<1/CARDNAME> | Conjure$ True | Spellbook$ Empty the Warrens,Galvanic Relay,Grapeshot | SorcerySpeed$ True | Zone$ Hand | SpellDescription$ Conjure a card of your choice from Charged Conjuration's spellbook into your hand. Activate only as a sorcery. A:AB$ MakeCard | Cost$ Sac<1/CARDNAME> | Conjure$ True | Spellbook$ Empty the Warrens,Galvanic Relay,Grapeshot | SorcerySpeed$ True | Zone$ Hand | SpellDescription$ Conjure a card of your choice from CARDNAME's spellbook into your hand. Activate only as a sorcery.
Oracle:At the beginning of your upkeep, instant and sorcery cards in your hand perpetually gain "This spell costs {1} less to cast."\nSacrifice this enchantment: Conjure a card of your choice from Charged Conjuration's spellbook into your hand. Activate only as a sorcery. Oracle:At the beginning of your upkeep, instant and sorcery cards in your hand perpetually gain "This spell costs {1} less to cast."\nSacrifice this enchantment: Conjure a card of your choice from Charged Conjuration's spellbook into your hand. Activate only as a sorcery.

View File

@@ -3,6 +3,6 @@ ManaCost:3 U
Types:Instant Types:Instant
K:Cycling:1 U K:Cycling:1 U
A:SP$ Tap | ValidTgts$ Creature | TgtPrompt$ Select target creature | TargetMin$ 0 | TargetMax$ 4 | SpellDescription$ Tap up to four target creatures. A:SP$ Tap | ValidTgts$ Creature | TgtPrompt$ Select target creature | TargetMin$ 0 | TargetMax$ 4 | SpellDescription$ Tap up to four target creatures.
T:Mode$ Cycled | ValidCard$ Card.Self | Execute$ TrigTap | OptionalDecider$ You | TriggerDescription$ When you cycle CARDNAME, you may tap target creature T:Mode$ Cycled | ValidCard$ Card.Self | Execute$ TrigTap | OptionalDecider$ You | TriggerDescription$ When you cycle CARDNAME, you may tap target creature.
SVar:TrigTap:DB$ Tap | ValidTgts$ Creature | TgtPrompt$ Select target creature SVar:TrigTap:DB$ Tap | ValidTgts$ Creature | TgtPrompt$ Select target creature
Oracle:Tap up to four target creatures.\nCycling {1}{U} ({1}{U}, Discard this card: Draw a card.)\nWhen you cycle Choking Tethers, you may tap target creature. Oracle:Tap up to four target creatures.\nCycling {1}{U} ({1}{U}, Discard this card: Draw a card.)\nWhen you cycle Choking Tethers, you may tap target creature.

View File

@@ -3,7 +3,7 @@ ManaCost:no cost
Types:Scheme Types:Scheme
T:Mode$ SetInMotion | ValidCard$ Card.Self | Execute$ ChooseChampion | TriggerZones$ Command | TriggerDescription$ When you set this scheme in motion, target opponent chooses a player. Until your next turn, only you and the chosen player can cast spells and attack with creatures. T:Mode$ SetInMotion | ValidCard$ Card.Self | Execute$ ChooseChampion | TriggerZones$ Command | TriggerDescription$ When you set this scheme in motion, target opponent chooses a player. Until your next turn, only you and the chosen player can cast spells and attack with creatures.
SVar:ChooseChampion:DB$ ChoosePlayer | ValidTgts$ Opponent | Choices$ Player | AILogic$ BestAllyBoardPosition | SubAbility$ PrepChamps SVar:ChooseChampion:DB$ ChoosePlayer | ValidTgts$ Opponent | Choices$ Player | AILogic$ BestAllyBoardPosition | SubAbility$ PrepChamps
SVar:PrepChamps:DB$ Effect | RememberObjects$ ChosenPlayer,You | Name$ Choose Your Champion Scheme | Duration$ UntilYourNextTurn | StaticAbilities$ RestrictAttackers,RestrictCasting SVar:PrepChamps:DB$ Effect | RememberObjects$ ChosenPlayer,You | Duration$ UntilYourNextTurn | StaticAbilities$ RestrictAttackers,RestrictCasting
SVar:RestrictAttackers:Mode$ CantAttack | EffectZone$ Command | ValidCard$ Creature.!RememberedPlayerCtrl | Description$ Until your next turn, only you and the chosen player can attack with creatures. SVar:RestrictAttackers:Mode$ CantAttack | EffectZone$ Command | ValidCard$ Creature.!RememberedPlayerCtrl | Description$ Until your next turn, only you and the chosen player can attack with creatures.
SVar:RestrictCasting:Mode$ CantBeCast | ValidCard$ Card | Caster$ Player.IsNotRemembered | EffectZone$ Command | Description$ Until your next turn, only you and the chosen player can cast spells. SVar:RestrictCasting:Mode$ CantBeCast | ValidCard$ Card | Caster$ Player.IsNotRemembered | EffectZone$ Command | Description$ Until your next turn, only you and the chosen player can cast spells.
Oracle:When you set this scheme in motion, target opponent chooses a player. Until your next turn, only you and the chosen player can cast spells and attack with creatures. Oracle:When you set this scheme in motion, target opponent chooses a player. Until your next turn, only you and the chosen player can cast spells and attack with creatures.

View File

@@ -2,5 +2,5 @@ Name:Chronostutter
ManaCost:5 U ManaCost:5 U
Types:Instant Types:Instant
A:SP$ ChangeZone | Origin$ Battlefield | Destination$ Library | ValidTgts$ Creature | LibraryPosition$ 1 | SpellDescription$ Put target creature into its owner's library second from the top. A:SP$ ChangeZone | Origin$ Battlefield | Destination$ Library | ValidTgts$ Creature | LibraryPosition$ 1 | SpellDescription$ Put target creature into its owner's library second from the top.
# Library Position is zero indexed. So 1 is second from the top # LibraryPosition is zero indexed. So 1 is second from the top
Oracle:Put target creature into its owner's library second from the top. Oracle:Put target creature into its owner's library second from the top.

View File

@@ -1,7 +1,7 @@
Name:Cindercone Smite Name:Cindercone Smite
ManaCost:R ManaCost:R
Types:Sorcery Types:Sorcery
A:SP$ DealDamage | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 2 | SubAbility$ DBTreasure | SpellDescription$ CARDNAME deals 2 damage to target creature A:SP$ DealDamage | ValidTgts$ Creature | TgtPrompt$ Select target creature | NumDmg$ 2 | SubAbility$ DBTreasure | SpellDescription$ CARDNAME deals 2 damage to target creature.
SVar:DBTreasure:DB$ Token | ConditionCheckSVar$ X | TokenScript$ c_a_treasure_sac | SpellDescription$ Then create a Treasure token if you weren't the starting player. SVar:DBTreasure:DB$ Token | ConditionCheckSVar$ X | TokenScript$ c_a_treasure_sac | SpellDescription$ Then create a Treasure token if you weren't the starting player.
SVar:X:Count$StartingPlayer.0.1 SVar:X:Count$StartingPlayer.0.1
Oracle:Cindercone Smite deals 2 damage to target creature. Then create a Treasure token if you weren't the starting player. Oracle:Cindercone Smite deals 2 damage to target creature. Then create a Treasure token if you weren't the starting player.

View File

@@ -4,4 +4,4 @@ Types:Artifact Creature Wall
PT:0/3 PT:0/3
K:Defender K:Defender
A:AB$ Tap | Cost$ 2 W T | ValidTgts$ Creature | SpellDescription$ Tap target creature. A:AB$ Tap | Cost$ 2 W T | ValidTgts$ Creature | SpellDescription$ Tap target creature.
Oracle:Defender\n{2}{W}, {T}: Tap target creature Oracle:Defender\n{2}{W}, {T}: Tap target creature.

View File

@@ -3,9 +3,9 @@ ManaCost:3
Types:Artifact Types:Artifact
A:AB$ Mana | Cost$ T | Produced$ Any | Amount$ 1 | SpellDescription$ Add one mana of any color. A:AB$ Mana | Cost$ T | Produced$ Any | Amount$ 1 | SpellDescription$ Add one mana of any color.
A:AB$ PutCounter | Cost$ T | CounterType$ CHARGE | CounterNum$ 1 | SpellDescription$ Put a charge counter on CARDNAME. A:AB$ PutCounter | Cost$ T | CounterType$ CHARGE | CounterNum$ 1 | SpellDescription$ Put a charge counter on CARDNAME.
T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRemove | TriggerDescription$ At the beginning of your precombat main phase, remove all charge counters from CARDNAME. Add one mana of any color for each charge counter removed this way. T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigRemove | TriggerDescription$ At the beginning of your first main phase, remove all charge counters from CARDNAME. Add one mana of any color for each charge counter removed this way.
SVar:TrigRemove:DB$ RemoveCounter | CounterType$ CHARGE | CounterNum$ All | RememberRemoved$ True | SubAbility$ TrigGetMana SVar:TrigRemove:DB$ RemoveCounter | CounterType$ CHARGE | CounterNum$ All | RememberRemoved$ True | SubAbility$ TrigGetMana
SVar:TrigGetMana:DB$ Mana | Produced$ Combo Any | Amount$ NumRemoved | SubAbility$ DBCleanup SVar:TrigGetMana:DB$ Mana | Produced$ Combo Any | Amount$ NumRemoved | SubAbility$ DBCleanup
SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True SVar:DBCleanup:DB$ Cleanup | ClearRemembered$ True
SVar:NumRemoved:Count$RememberedSize SVar:NumRemoved:Count$RememberedSize
Oracle:{T}: Add one mana of any color.\n{T}: Put a charge counter on Coalition Relic.\nAt the beginning of your precombat main phase, remove all charge counters from Coalition Relic. Add one mana of any color for each charge counter removed this way. Oracle:{T}: Add one mana of any color.\n{T}: Put a charge counter on Coalition Relic.\nAt the beginning of your first main phase, remove all charge counters from Coalition Relic. Add one mana of any color for each charge counter removed this way.

View File

@@ -2,7 +2,7 @@ Name:Cobbled Lancer
ManaCost:U ManaCost:U
Types:Creature Zombie Horse Types:Creature Zombie Horse
PT:3/3 PT:3/3
A:SP$ PermanentCreature | Cost$ U ExileFromGrave<1/Creature/creature card> A:SP$ PermanentCreature | Cost$ U ExileFromGrave<1/Creature>
A:AB$ Draw | Cost$ 3 U ExileFromGrave<1/CARDNAME> | NumCards$ 1 | ActivationZone$ Graveyard | SpellDescription$ Draw a card. A:AB$ Draw | Cost$ 3 U ExileFromGrave<1/CARDNAME> | NumCards$ 1 | ActivationZone$ Graveyard | SpellDescription$ Draw a card.
DeckHas:Ability$Graveyard DeckHas:Ability$Graveyard
Oracle:As an additional cost to cast this spell, exile a creature card from your graveyard.\n{3}{U}, Exile Cobbled Lancer from your graveyard: Draw a card. Oracle:As an additional cost to cast this spell, exile a creature card from your graveyard.\n{3}{U}, Exile Cobbled Lancer from your graveyard: Draw a card.

View File

@@ -1,7 +1,7 @@
Name:Collective Voyage Name:Collective Voyage
ManaCost:G ManaCost:G
Types:Sorcery Types:Sorcery
A:SP$ RepeatEach | RepeatPlayers$ Player | StartingWithActivator$ True | RepeatSubAbility$ DBPay | SubAbility$ DBSearch | StackDescription$ SpellDescription | SpellDescription$ Join forces — Starting with you, each player may pay any amount of mana. Each player searches their library for up to X basic land cards, where X is the total amount of mana paid this way, puts them onto the battlefield tapped, then shuffles. A:SP$ RepeatEach | RepeatPlayers$ Player | StartingWith$ You | RepeatSubAbility$ DBPay | SubAbility$ DBSearch | StackDescription$ SpellDescription | SpellDescription$ Join forces — Starting with you, each player may pay any amount of mana. Each player searches their library for up to X basic land cards, where X is the total amount of mana paid this way, puts them onto the battlefield tapped, then shuffles.
SVar:DBPay:DB$ ChooseNumber | Defined$ Player.IsRemembered | ChooseAnyNumber$ True | ListTitle$ amount of mana to pay | SubAbility$ DBStore SVar:DBPay:DB$ ChooseNumber | Defined$ Player.IsRemembered | ChooseAnyNumber$ True | ListTitle$ amount of mana to pay | SubAbility$ DBStore
SVar:DBStore:DB$ StoreSVar | SVar$ JoinForcesAmount | Type$ CountSVar | Expression$ JoinForcesAmount/Plus.Y | UnlessCost$ Y | UnlessPayer$ Player.IsRemembered | UnlessSwitched$ True | UnlessAI$ OnlyOwn SVar:DBStore:DB$ StoreSVar | SVar$ JoinForcesAmount | Type$ CountSVar | Expression$ JoinForcesAmount/Plus.Y | UnlessCost$ Y | UnlessPayer$ Player.IsRemembered | UnlessSwitched$ True | UnlessAI$ OnlyOwn
SVar:DBSearch:DB$ ChangeZone | DefinedPlayer$ Player | ChangeType$ Land.Basic | ChangeNum$ JoinForcesAmount | Origin$ Library | Destination$ Battlefield | Tapped$ True | SubAbility$ DBReset | StackDescription$ None SVar:DBSearch:DB$ ChangeZone | DefinedPlayer$ Player | ChangeType$ Land.Basic | ChangeNum$ JoinForcesAmount | Origin$ Library | Destination$ Battlefield | Tapped$ True | SubAbility$ DBReset | StackDescription$ None

View File

@@ -2,7 +2,7 @@ Name:Commit
ManaCost:3 U ManaCost:3 U
Types:Instant Types:Instant
A:SP$ ChangeZone | TgtZone$ Stack,Battlefield | Origin$ Battlefield,Stack | Destination$ Library | ValidTgts$ Permanent.nonLand,Card.inZoneStack | TgtPrompt$ Select target spell or nonland permanent | LibraryPosition$ 1 | Fizzle$ True | SpellDescription$ Put target spell or nonland permanent into its owner's library second from the top. A:SP$ ChangeZone | TgtZone$ Stack,Battlefield | Origin$ Battlefield,Stack | Destination$ Library | ValidTgts$ Permanent.nonLand,Card.inZoneStack | TgtPrompt$ Select target spell or nonland permanent | LibraryPosition$ 1 | Fizzle$ True | SpellDescription$ Put target spell or nonland permanent into its owner's library second from the top.
# Library Position is zero indexed. So 1 is second from the top # LibraryPosition is zero indexed. So 1 is second from the top
AlternateMode:Split AlternateMode:Split
Oracle:Put target spell or nonland permanent into its owner's library second from the top. Oracle:Put target spell or nonland permanent into its owner's library second from the top.

View File

@@ -2,8 +2,8 @@ Name:Crack in Time
ManaCost:3 W ManaCost:3 W
Types:Enchantment Types:Enchantment
K:Vanishing:3 K:Vanishing:3
T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | Secondary$ True | TriggerDescription$ When CARDNAME enters and at the beginning of your precombat main phase, exile target creature an opponent controls until CARDNAME leaves the battlefield. T:Mode$ ChangesZone | Origin$ Any | Destination$ Battlefield | ValidCard$ Card.Self | Execute$ TrigExile | Secondary$ True | TriggerDescription$ When CARDNAME enters and at the beginning of your first main phase, exile target creature an opponent controls until CARDNAME leaves the battlefield.
T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters and at the beginning of your precombat main phase, exile target creature an opponent controls until CARDNAME leaves the battlefield. T:Mode$ Phase | Phase$ Main1 | ValidPlayer$ You | TriggerZones$ Battlefield | Execute$ TrigExile | TriggerDescription$ When CARDNAME enters and at the beginning of your first main phase, exile target creature an opponent controls until CARDNAME leaves the battlefield.
SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | Duration$ UntilHostLeavesPlay SVar:TrigExile:DB$ ChangeZone | Origin$ Battlefield | Destination$ Exile | ValidTgts$ Creature.OppCtrl | TgtPrompt$ Select target creature an opponent controls | Duration$ UntilHostLeavesPlay
DeckHas:Ability$Counters DeckHas:Ability$Counters
Oracle:Vanishing 3 (This enchantment enters with three time counters on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it.)\nWhen Crack in Time enters and at the beginning of your precombat main phase, exile target creature an opponent controls until Crack in Time leaves the battlefield. Oracle:Vanishing 3 (This enchantment enters with three time counters on it. At the beginning of your upkeep, remove a time counter from it. When the last is removed, sacrifice it.)\nWhen Crack in Time enters and at the beginning of your first main phase, exile target creature an opponent controls until Crack in Time leaves the battlefield.

Some files were not shown because too many files have changed in this diff Show More